summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/static_checks.yml1
-rw-r--r--CHANGELOG.md440
-rw-r--r--COPYRIGHT.txt4
-rw-r--r--SConstruct8
-rw-r--r--core/SCsub3
-rw-r--r--core/config/project_settings.cpp2
-rw-r--r--core/core_bind.cpp10
-rw-r--r--core/core_bind.h6
-rw-r--r--core/debugger/debugger_marshalls.cpp10
-rw-r--r--core/debugger/debugger_marshalls.h1
-rw-r--r--core/debugger/engine_debugger.cpp8
-rw-r--r--core/debugger/engine_debugger.h8
-rw-r--r--core/debugger/remote_debugger.cpp109
-rw-r--r--core/debugger/remote_debugger.h11
-rw-r--r--core/debugger/script_debugger.cpp22
-rw-r--r--core/debugger/script_debugger.h23
-rw-r--r--core/extension/gdextension.cpp8
-rw-r--r--core/extension/gdextension.h1
-rw-r--r--core/extension/gdextension_interface.cpp6
-rw-r--r--core/extension/gdextension_interface.h36
-rw-r--r--core/input/input.cpp27
-rw-r--r--core/input/input.h4
-rw-r--r--core/input/input_event.cpp2
-rw-r--r--core/io/compression.cpp8
-rw-r--r--core/io/file_access_zip.cpp2
-rw-r--r--core/io/image.cpp254
-rw-r--r--core/io/image.h5
-rw-r--r--core/io/json.cpp8
-rw-r--r--core/io/resource.cpp36
-rw-r--r--core/io/resource.h11
-rw-r--r--core/io/resource_format_binary.cpp20
-rw-r--r--core/io/resource_format_binary.h2
-rw-r--r--core/io/resource_importer.cpp20
-rw-r--r--core/io/resource_loader.cpp25
-rw-r--r--core/io/resource_loader.h2
-rw-r--r--core/object/callable_method_pointer.cpp22
-rw-r--r--core/object/class_db.cpp4
-rw-r--r--core/object/class_db.h4
-rw-r--r--core/object/message_queue.cpp94
-rw-r--r--core/object/message_queue.h2
-rw-r--r--core/object/object.cpp32
-rw-r--r--core/object/object.h10
-rw-r--r--core/object/script_language.h1
-rw-r--r--core/object/undo_redo.h2
-rw-r--r--core/object/worker_thread_pool.cpp9
-rw-r--r--core/os/main_loop.cpp8
-rw-r--r--core/os/main_loop.h4
-rw-r--r--core/os/os.cpp14
-rw-r--r--core/os/os.h3
-rw-r--r--core/string/print_string.cpp2
-rw-r--r--core/string/translation.cpp9
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/ustring.cpp9
-rw-r--r--core/templates/hash_map.h34
-rw-r--r--core/variant/array.cpp12
-rw-r--r--core/variant/callable_bind.cpp22
-rw-r--r--core/variant/callable_bind.h2
-rw-r--r--core/variant/native_ptr.h70
-rw-r--r--doc/class.xsd1
-rw-r--r--doc/classes/@GlobalScope.xml2
-rw-r--r--doc/classes/AABB.xml2
-rw-r--r--doc/classes/AESContext.xml2
-rw-r--r--doc/classes/AStar2D.xml2
-rw-r--r--doc/classes/AStar3D.xml2
-rw-r--r--doc/classes/AStarGrid2D.xml4
-rw-r--r--doc/classes/AcceptDialog.xml2
-rw-r--r--doc/classes/AnimatableBody2D.xml2
-rw-r--r--doc/classes/AnimatableBody3D.xml2
-rw-r--r--doc/classes/AnimatedSprite2D.xml2
-rw-r--r--doc/classes/AnimatedSprite3D.xml2
-rw-r--r--doc/classes/AnimatedTexture.xml2
-rw-r--r--doc/classes/Animation.xml2
-rw-r--r--doc/classes/AnimationLibrary.xml2
-rw-r--r--doc/classes/AnimationNode.xml2
-rw-r--r--doc/classes/AnimationNodeAdd2.xml2
-rw-r--r--doc/classes/AnimationNodeAdd3.xml4
-rw-r--r--doc/classes/AnimationNodeAnimation.xml2
-rw-r--r--doc/classes/AnimationNodeBlend2.xml2
-rw-r--r--doc/classes/AnimationNodeBlend3.xml4
-rw-r--r--doc/classes/AnimationNodeBlendSpace1D.xml2
-rw-r--r--doc/classes/AnimationNodeBlendSpace2D.xml2
-rw-r--r--doc/classes/AnimationNodeBlendTree.xml2
-rw-r--r--doc/classes/AnimationNodeOneShot.xml2
-rw-r--r--doc/classes/AnimationNodeOutput.xml2
-rw-r--r--doc/classes/AnimationNodeStateMachine.xml2
-rw-r--r--doc/classes/AnimationNodeStateMachinePlayback.xml2
-rw-r--r--doc/classes/AnimationNodeStateMachineTransition.xml2
-rw-r--r--doc/classes/AnimationNodeSub2.xml2
-rw-r--r--doc/classes/AnimationNodeSync.xml2
-rw-r--r--doc/classes/AnimationNodeTimeScale.xml2
-rw-r--r--doc/classes/AnimationNodeTimeSeek.xml2
-rw-r--r--doc/classes/AnimationNodeTransition.xml2
-rw-r--r--doc/classes/AnimationPlayer.xml2
-rw-r--r--doc/classes/AnimationRootNode.xml2
-rw-r--r--doc/classes/AnimationTree.xml2
-rw-r--r--doc/classes/Area2D.xml2
-rw-r--r--doc/classes/Area3D.xml2
-rw-r--r--doc/classes/Array.xml3
-rw-r--r--doc/classes/ArrayMesh.xml2
-rw-r--r--doc/classes/ArrayOccluder3D.xml2
-rw-r--r--doc/classes/AspectRatioContainer.xml2
-rw-r--r--doc/classes/AtlasTexture.xml2
-rw-r--r--doc/classes/AudioBusLayout.xml2
-rw-r--r--doc/classes/AudioEffect.xml2
-rw-r--r--doc/classes/AudioEffectAmplify.xml2
-rw-r--r--doc/classes/AudioEffectBandLimitFilter.xml2
-rw-r--r--doc/classes/AudioEffectBandPassFilter.xml2
-rw-r--r--doc/classes/AudioEffectCapture.xml2
-rw-r--r--doc/classes/AudioEffectChorus.xml2
-rw-r--r--doc/classes/AudioEffectCompressor.xml2
-rw-r--r--doc/classes/AudioEffectDelay.xml2
-rw-r--r--doc/classes/AudioEffectDistortion.xml2
-rw-r--r--doc/classes/AudioEffectEQ.xml2
-rw-r--r--doc/classes/AudioEffectEQ10.xml2
-rw-r--r--doc/classes/AudioEffectEQ21.xml2
-rw-r--r--doc/classes/AudioEffectEQ6.xml2
-rw-r--r--doc/classes/AudioEffectFilter.xml2
-rw-r--r--doc/classes/AudioEffectHighPassFilter.xml2
-rw-r--r--doc/classes/AudioEffectHighShelfFilter.xml2
-rw-r--r--doc/classes/AudioEffectInstance.xml2
-rw-r--r--doc/classes/AudioEffectLimiter.xml2
-rw-r--r--doc/classes/AudioEffectLowPassFilter.xml2
-rw-r--r--doc/classes/AudioEffectLowShelfFilter.xml2
-rw-r--r--doc/classes/AudioEffectNotchFilter.xml2
-rw-r--r--doc/classes/AudioEffectPanner.xml2
-rw-r--r--doc/classes/AudioEffectPhaser.xml2
-rw-r--r--doc/classes/AudioEffectPitchShift.xml2
-rw-r--r--doc/classes/AudioEffectRecord.xml2
-rw-r--r--doc/classes/AudioEffectReverb.xml2
-rw-r--r--doc/classes/AudioEffectSpectrumAnalyzer.xml2
-rw-r--r--doc/classes/AudioEffectSpectrumAnalyzerInstance.xml2
-rw-r--r--doc/classes/AudioEffectStereoEnhance.xml2
-rw-r--r--doc/classes/AudioListener2D.xml2
-rw-r--r--doc/classes/AudioListener3D.xml2
-rw-r--r--doc/classes/AudioServer.xml2
-rw-r--r--doc/classes/AudioStream.xml2
-rw-r--r--doc/classes/AudioStreamGenerator.xml2
-rw-r--r--doc/classes/AudioStreamGeneratorPlayback.xml2
-rw-r--r--doc/classes/AudioStreamMicrophone.xml2
-rw-r--r--doc/classes/AudioStreamPlayback.xml2
-rw-r--r--doc/classes/AudioStreamPlaybackPolyphonic.xml2
-rw-r--r--doc/classes/AudioStreamPlaybackResampled.xml2
-rw-r--r--doc/classes/AudioStreamPlayer.xml2
-rw-r--r--doc/classes/AudioStreamPlayer2D.xml2
-rw-r--r--doc/classes/AudioStreamPlayer3D.xml4
-rw-r--r--doc/classes/AudioStreamPolyphonic.xml2
-rw-r--r--doc/classes/AudioStreamRandomizer.xml2
-rw-r--r--doc/classes/AudioStreamWAV.xml2
-rw-r--r--doc/classes/BackBufferCopy.xml2
-rw-r--r--doc/classes/BaseButton.xml2
-rw-r--r--doc/classes/BaseMaterial3D.xml4
-rw-r--r--doc/classes/Basis.xml2
-rw-r--r--doc/classes/BitMap.xml2
-rw-r--r--doc/classes/Bone2D.xml2
-rw-r--r--doc/classes/BoneAttachment3D.xml4
-rw-r--r--doc/classes/BoneMap.xml2
-rw-r--r--doc/classes/BoxContainer.xml2
-rw-r--r--doc/classes/BoxMesh.xml2
-rw-r--r--doc/classes/BoxOccluder3D.xml2
-rw-r--r--doc/classes/BoxShape3D.xml2
-rw-r--r--doc/classes/Button.xml2
-rw-r--r--doc/classes/ButtonGroup.xml2
-rw-r--r--doc/classes/CPUParticles2D.xml11
-rw-r--r--doc/classes/CPUParticles3D.xml11
-rw-r--r--doc/classes/Callable.xml2
-rw-r--r--doc/classes/CallbackTweener.xml2
-rw-r--r--doc/classes/Camera2D.xml2
-rw-r--r--doc/classes/Camera3D.xml8
-rw-r--r--doc/classes/CameraAttributes.xml2
-rw-r--r--doc/classes/CameraAttributesPhysical.xml2
-rw-r--r--doc/classes/CameraAttributesPractical.xml2
-rw-r--r--doc/classes/CameraFeed.xml2
-rw-r--r--doc/classes/CameraServer.xml2
-rw-r--r--doc/classes/CameraTexture.xml2
-rw-r--r--doc/classes/CanvasGroup.xml2
-rw-r--r--doc/classes/CanvasItem.xml2
-rw-r--r--doc/classes/CanvasItemMaterial.xml2
-rw-r--r--doc/classes/CanvasLayer.xml2
-rw-r--r--doc/classes/CanvasModulate.xml2
-rw-r--r--doc/classes/CanvasTexture.xml2
-rw-r--r--doc/classes/CapsuleMesh.xml2
-rw-r--r--doc/classes/CapsuleShape2D.xml2
-rw-r--r--doc/classes/CapsuleShape3D.xml2
-rw-r--r--doc/classes/CenterContainer.xml2
-rw-r--r--doc/classes/CharFXTransform.xml2
-rw-r--r--doc/classes/CharacterBody2D.xml2
-rw-r--r--doc/classes/CharacterBody3D.xml2
-rw-r--r--doc/classes/CheckBox.xml2
-rw-r--r--doc/classes/CheckButton.xml2
-rw-r--r--doc/classes/CircleShape2D.xml2
-rw-r--r--doc/classes/ClassDB.xml2
-rw-r--r--doc/classes/CodeEdit.xml14
-rw-r--r--doc/classes/CodeHighlighter.xml2
-rw-r--r--doc/classes/CollisionObject2D.xml2
-rw-r--r--doc/classes/CollisionObject3D.xml2
-rw-r--r--doc/classes/CollisionPolygon2D.xml4
-rw-r--r--doc/classes/CollisionPolygon3D.xml2
-rw-r--r--doc/classes/CollisionShape2D.xml2
-rw-r--r--doc/classes/CollisionShape3D.xml6
-rw-r--r--doc/classes/Color.xml2
-rw-r--r--doc/classes/ColorPicker.xml2
-rw-r--r--doc/classes/ColorPickerButton.xml2
-rw-r--r--doc/classes/ColorRect.xml2
-rw-r--r--doc/classes/CompressedCubemap.xml2
-rw-r--r--doc/classes/CompressedCubemapArray.xml2
-rw-r--r--doc/classes/CompressedTexture2D.xml2
-rw-r--r--doc/classes/CompressedTexture2DArray.xml2
-rw-r--r--doc/classes/CompressedTexture3D.xml2
-rw-r--r--doc/classes/CompressedTextureLayered.xml2
-rw-r--r--doc/classes/ConcavePolygonShape2D.xml2
-rw-r--r--doc/classes/ConcavePolygonShape3D.xml2
-rw-r--r--doc/classes/ConeTwistJoint3D.xml2
-rw-r--r--doc/classes/ConfigFile.xml2
-rw-r--r--doc/classes/ConfirmationDialog.xml2
-rw-r--r--doc/classes/Container.xml2
-rw-r--r--doc/classes/Control.xml8
-rw-r--r--doc/classes/ConvexPolygonShape2D.xml4
-rw-r--r--doc/classes/ConvexPolygonShape3D.xml2
-rw-r--r--doc/classes/Crypto.xml2
-rw-r--r--doc/classes/CryptoKey.xml2
-rw-r--r--doc/classes/Cubemap.xml2
-rw-r--r--doc/classes/CubemapArray.xml2
-rw-r--r--doc/classes/Curve.xml2
-rw-r--r--doc/classes/Curve2D.xml2
-rw-r--r--doc/classes/Curve3D.xml2
-rw-r--r--doc/classes/CurveTexture.xml2
-rw-r--r--doc/classes/CurveXYZTexture.xml2
-rw-r--r--doc/classes/CylinderMesh.xml2
-rw-r--r--doc/classes/CylinderShape3D.xml6
-rw-r--r--doc/classes/DTLSServer.xml2
-rw-r--r--doc/classes/DampedSpringJoint2D.xml2
-rw-r--r--doc/classes/Decal.xml2
-rw-r--r--doc/classes/Dictionary.xml4
-rw-r--r--doc/classes/DirAccess.xml2
-rw-r--r--doc/classes/DirectionalLight2D.xml2
-rw-r--r--doc/classes/DirectionalLight3D.xml2
-rw-r--r--doc/classes/DisplayServer.xml59
-rw-r--r--doc/classes/EditorCommandPalette.xml2
-rw-r--r--doc/classes/EditorDebuggerPlugin.xml4
-rw-r--r--doc/classes/EditorDebuggerSession.xml2
-rw-r--r--doc/classes/EditorExportPlatform.xml2
-rw-r--r--doc/classes/EditorExportPlatformPC.xml2
-rw-r--r--doc/classes/EditorExportPlugin.xml80
-rw-r--r--doc/classes/EditorFeatureProfile.xml4
-rw-r--r--doc/classes/EditorFileDialog.xml2
-rw-r--r--doc/classes/EditorFileSystem.xml2
-rw-r--r--doc/classes/EditorFileSystemDirectory.xml2
-rw-r--r--doc/classes/EditorFileSystemImportFormatSupportQuery.xml2
-rw-r--r--doc/classes/EditorImportPlugin.xml2
-rw-r--r--doc/classes/EditorInspector.xml2
-rw-r--r--doc/classes/EditorInspectorPlugin.xml2
-rw-r--r--doc/classes/EditorInterface.xml29
-rw-r--r--doc/classes/EditorNode3DGizmo.xml2
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml2
-rw-r--r--doc/classes/EditorPaths.xml2
-rw-r--r--doc/classes/EditorPlugin.xml37
-rw-r--r--doc/classes/EditorProperty.xml2
-rw-r--r--doc/classes/EditorResourceConversionPlugin.xml2
-rw-r--r--doc/classes/EditorResourcePicker.xml2
-rw-r--r--doc/classes/EditorResourcePreview.xml2
-rw-r--r--doc/classes/EditorResourcePreviewGenerator.xml2
-rw-r--r--doc/classes/EditorResourceTooltipPlugin.xml2
-rw-r--r--doc/classes/EditorSceneFormatImporter.xml2
-rw-r--r--doc/classes/EditorScenePostImport.xml2
-rw-r--r--doc/classes/EditorScenePostImportPlugin.xml2
-rw-r--r--doc/classes/EditorScript.xml2
-rw-r--r--doc/classes/EditorScriptPicker.xml2
-rw-r--r--doc/classes/EditorSelection.xml2
-rw-r--r--doc/classes/EditorSettings.xml17
-rw-r--r--doc/classes/EditorSpinSlider.xml2
-rw-r--r--doc/classes/EditorSyntaxHighlighter.xml2
-rw-r--r--doc/classes/EditorTranslationParserPlugin.xml2
-rw-r--r--doc/classes/EditorUndoRedoManager.xml2
-rw-r--r--doc/classes/EditorVCSInterface.xml4
-rw-r--r--doc/classes/EncodedObjectAsID.xml2
-rw-r--r--doc/classes/Engine.xml12
-rw-r--r--doc/classes/EngineDebugger.xml2
-rw-r--r--doc/classes/EngineProfiler.xml2
-rw-r--r--doc/classes/Environment.xml2
-rw-r--r--doc/classes/Expression.xml2
-rw-r--r--doc/classes/FileAccess.xml2
-rw-r--r--doc/classes/FileDialog.xml6
-rw-r--r--doc/classes/FileSystemDock.xml2
-rw-r--r--doc/classes/FlowContainer.xml2
-rw-r--r--doc/classes/FogMaterial.xml2
-rw-r--r--doc/classes/FogVolume.xml2
-rw-r--r--doc/classes/Font.xml2
-rw-r--r--doc/classes/FontFile.xml4
-rw-r--r--doc/classes/FontVariation.xml2
-rw-r--r--doc/classes/GDExtension.xml2
-rw-r--r--doc/classes/GDExtensionManager.xml2
-rw-r--r--doc/classes/GPUParticles2D.xml13
-rw-r--r--doc/classes/GPUParticles3D.xml12
-rw-r--r--doc/classes/GPUParticlesAttractor3D.xml2
-rw-r--r--doc/classes/GPUParticlesAttractorBox3D.xml2
-rw-r--r--doc/classes/GPUParticlesAttractorSphere3D.xml2
-rw-r--r--doc/classes/GPUParticlesAttractorVectorField3D.xml2
-rw-r--r--doc/classes/GPUParticlesCollision3D.xml2
-rw-r--r--doc/classes/GPUParticlesCollisionBox3D.xml2
-rw-r--r--doc/classes/GPUParticlesCollisionHeightField3D.xml2
-rw-r--r--doc/classes/GPUParticlesCollisionSDF3D.xml2
-rw-r--r--doc/classes/GPUParticlesCollisionSphere3D.xml2
-rw-r--r--doc/classes/Generic6DOFJoint3D.xml2
-rw-r--r--doc/classes/Geometry2D.xml2
-rw-r--r--doc/classes/Geometry3D.xml2
-rw-r--r--doc/classes/GeometryInstance3D.xml2
-rw-r--r--doc/classes/Gradient.xml4
-rw-r--r--doc/classes/GradientTexture1D.xml2
-rw-r--r--doc/classes/GradientTexture2D.xml2
-rw-r--r--doc/classes/GraphEdit.xml38
-rw-r--r--doc/classes/GraphNode.xml11
-rw-r--r--doc/classes/GridContainer.xml2
-rw-r--r--doc/classes/GrooveJoint2D.xml2
-rw-r--r--doc/classes/HBoxContainer.xml2
-rw-r--r--doc/classes/HFlowContainer.xml2
-rw-r--r--doc/classes/HMACContext.xml2
-rw-r--r--doc/classes/HScrollBar.xml2
-rw-r--r--doc/classes/HSeparator.xml2
-rw-r--r--doc/classes/HSlider.xml2
-rw-r--r--doc/classes/HSplitContainer.xml2
-rw-r--r--doc/classes/HTTPClient.xml3
-rw-r--r--doc/classes/HTTPRequest.xml2
-rw-r--r--doc/classes/HashingContext.xml2
-rw-r--r--doc/classes/HeightMapShape3D.xml2
-rw-r--r--doc/classes/HingeJoint3D.xml2
-rw-r--r--doc/classes/IP.xml2
-rw-r--r--doc/classes/Image.xml25
-rw-r--r--doc/classes/ImageFormatLoader.xml2
-rw-r--r--doc/classes/ImageFormatLoaderExtension.xml2
-rw-r--r--doc/classes/ImageTexture.xml2
-rw-r--r--doc/classes/ImageTexture3D.xml2
-rw-r--r--doc/classes/ImageTextureLayered.xml2
-rw-r--r--doc/classes/ImmediateMesh.xml2
-rw-r--r--doc/classes/ImporterMesh.xml2
-rw-r--r--doc/classes/ImporterMeshInstance3D.xml2
-rw-r--r--doc/classes/Input.xml11
-rw-r--r--doc/classes/InputEvent.xml2
-rw-r--r--doc/classes/InputEventAction.xml2
-rw-r--r--doc/classes/InputEventFromWindow.xml2
-rw-r--r--doc/classes/InputEventGesture.xml2
-rw-r--r--doc/classes/InputEventJoypadButton.xml2
-rw-r--r--doc/classes/InputEventJoypadMotion.xml2
-rw-r--r--doc/classes/InputEventKey.xml2
-rw-r--r--doc/classes/InputEventMIDI.xml2
-rw-r--r--doc/classes/InputEventMagnifyGesture.xml2
-rw-r--r--doc/classes/InputEventMouse.xml2
-rw-r--r--doc/classes/InputEventMouseButton.xml2
-rw-r--r--doc/classes/InputEventMouseMotion.xml2
-rw-r--r--doc/classes/InputEventPanGesture.xml2
-rw-r--r--doc/classes/InputEventScreenDrag.xml2
-rw-r--r--doc/classes/InputEventScreenTouch.xml2
-rw-r--r--doc/classes/InputEventShortcut.xml2
-rw-r--r--doc/classes/InputEventWithModifiers.xml2
-rw-r--r--doc/classes/InputMap.xml2
-rw-r--r--doc/classes/InstancePlaceholder.xml2
-rw-r--r--doc/classes/IntervalTweener.xml2
-rw-r--r--doc/classes/ItemList.xml2
-rw-r--r--doc/classes/JNISingleton.xml2
-rw-r--r--doc/classes/JSON.xml2
-rw-r--r--doc/classes/JSONRPC.xml2
-rw-r--r--doc/classes/JavaClass.xml2
-rw-r--r--doc/classes/JavaClassWrapper.xml2
-rw-r--r--doc/classes/JavaScriptBridge.xml2
-rw-r--r--doc/classes/JavaScriptObject.xml2
-rw-r--r--doc/classes/Joint2D.xml2
-rw-r--r--doc/classes/Joint3D.xml2
-rw-r--r--doc/classes/KinematicCollision2D.xml2
-rw-r--r--doc/classes/KinematicCollision3D.xml2
-rw-r--r--doc/classes/Label.xml2
-rw-r--r--doc/classes/Label3D.xml2
-rw-r--r--doc/classes/LabelSettings.xml2
-rw-r--r--doc/classes/Light2D.xml2
-rw-r--r--doc/classes/Light3D.xml2
-rw-r--r--doc/classes/LightOccluder2D.xml2
-rw-r--r--doc/classes/LightmapGI.xml2
-rw-r--r--doc/classes/LightmapGIData.xml2
-rw-r--r--doc/classes/LightmapProbe.xml2
-rw-r--r--doc/classes/Lightmapper.xml2
-rw-r--r--doc/classes/LightmapperRD.xml2
-rw-r--r--doc/classes/Line2D.xml2
-rw-r--r--doc/classes/LineEdit.xml2
-rw-r--r--doc/classes/LinkButton.xml2
-rw-r--r--doc/classes/MainLoop.xml2
-rw-r--r--doc/classes/MarginContainer.xml2
-rw-r--r--doc/classes/Marker2D.xml2
-rw-r--r--doc/classes/Marker3D.xml2
-rw-r--r--doc/classes/Marshalls.xml2
-rw-r--r--doc/classes/Material.xml2
-rw-r--r--doc/classes/MenuBar.xml2
-rw-r--r--doc/classes/MenuButton.xml2
-rw-r--r--doc/classes/Mesh.xml2
-rw-r--r--doc/classes/MeshConvexDecompositionSettings.xml2
-rw-r--r--doc/classes/MeshDataTool.xml2
-rw-r--r--doc/classes/MeshInstance2D.xml2
-rw-r--r--doc/classes/MeshInstance3D.xml2
-rw-r--r--doc/classes/MeshLibrary.xml2
-rw-r--r--doc/classes/MeshTexture.xml2
-rw-r--r--doc/classes/MethodTweener.xml2
-rw-r--r--doc/classes/MissingNode.xml2
-rw-r--r--doc/classes/MissingResource.xml2
-rw-r--r--doc/classes/MovieWriter.xml2
-rw-r--r--doc/classes/MultiMesh.xml2
-rw-r--r--doc/classes/MultiMeshInstance2D.xml2
-rw-r--r--doc/classes/MultiMeshInstance3D.xml2
-rw-r--r--doc/classes/MultiplayerAPI.xml2
-rw-r--r--doc/classes/MultiplayerAPIExtension.xml2
-rw-r--r--doc/classes/MultiplayerPeer.xml2
-rw-r--r--doc/classes/MultiplayerPeerExtension.xml2
-rw-r--r--doc/classes/Mutex.xml2
-rw-r--r--doc/classes/NavigationAgent2D.xml18
-rw-r--r--doc/classes/NavigationAgent3D.xml22
-rw-r--r--doc/classes/NavigationLink2D.xml2
-rw-r--r--doc/classes/NavigationLink3D.xml2
-rw-r--r--doc/classes/NavigationMesh.xml14
-rw-r--r--doc/classes/NavigationMeshGenerator.xml3
-rw-r--r--doc/classes/NavigationMeshSourceGeometryData3D.xml2
-rw-r--r--doc/classes/NavigationObstacle2D.xml2
-rw-r--r--doc/classes/NavigationObstacle3D.xml2
-rw-r--r--doc/classes/NavigationPathQueryParameters2D.xml2
-rw-r--r--doc/classes/NavigationPathQueryParameters3D.xml2
-rw-r--r--doc/classes/NavigationPathQueryResult2D.xml2
-rw-r--r--doc/classes/NavigationPathQueryResult3D.xml2
-rw-r--r--doc/classes/NavigationPolygon.xml8
-rw-r--r--doc/classes/NavigationRegion2D.xml15
-rw-r--r--doc/classes/NavigationRegion3D.xml15
-rw-r--r--doc/classes/NavigationServer2D.xml32
-rw-r--r--doc/classes/NavigationServer3D.xml38
-rw-r--r--doc/classes/NinePatchRect.xml2
-rw-r--r--doc/classes/Node.xml10
-rw-r--r--doc/classes/Node2D.xml2
-rw-r--r--doc/classes/Node3D.xml4
-rw-r--r--doc/classes/Node3DGizmo.xml2
-rw-r--r--doc/classes/NodePath.xml2
-rw-r--r--doc/classes/ORMMaterial3D.xml2
-rw-r--r--doc/classes/OS.xml21
-rw-r--r--doc/classes/Object.xml2
-rw-r--r--doc/classes/Occluder3D.xml2
-rw-r--r--doc/classes/OccluderInstance3D.xml4
-rw-r--r--doc/classes/OccluderPolygon2D.xml2
-rw-r--r--doc/classes/OfflineMultiplayerPeer.xml2
-rw-r--r--doc/classes/OmniLight3D.xml2
-rw-r--r--doc/classes/OpenXRAPIExtension.xml114
-rw-r--r--doc/classes/OpenXRExtensionWrapperExtension.xml167
-rw-r--r--doc/classes/OptimizedTranslation.xml2
-rw-r--r--doc/classes/OptionButton.xml2
-rw-r--r--doc/classes/PCKPacker.xml2
-rw-r--r--doc/classes/PackedByteArray.xml4
-rw-r--r--doc/classes/PackedColorArray.xml2
-rw-r--r--doc/classes/PackedDataContainer.xml2
-rw-r--r--doc/classes/PackedDataContainerRef.xml2
-rw-r--r--doc/classes/PackedFloat32Array.xml2
-rw-r--r--doc/classes/PackedFloat64Array.xml2
-rw-r--r--doc/classes/PackedInt32Array.xml2
-rw-r--r--doc/classes/PackedInt64Array.xml2
-rw-r--r--doc/classes/PackedScene.xml2
-rw-r--r--doc/classes/PackedStringArray.xml2
-rw-r--r--doc/classes/PackedVector2Array.xml2
-rw-r--r--doc/classes/PackedVector3Array.xml2
-rw-r--r--doc/classes/PacketPeer.xml2
-rw-r--r--doc/classes/PacketPeerDTLS.xml2
-rw-r--r--doc/classes/PacketPeerExtension.xml2
-rw-r--r--doc/classes/PacketPeerStream.xml2
-rw-r--r--doc/classes/PacketPeerUDP.xml2
-rw-r--r--doc/classes/Panel.xml2
-rw-r--r--doc/classes/PanelContainer.xml2
-rw-r--r--doc/classes/PanoramaSkyMaterial.xml2
-rw-r--r--doc/classes/ParallaxBackground.xml2
-rw-r--r--doc/classes/ParallaxLayer.xml2
-rw-r--r--doc/classes/ParticleProcessMaterial.xml2
-rw-r--r--doc/classes/Path2D.xml2
-rw-r--r--doc/classes/Path3D.xml2
-rw-r--r--doc/classes/PathFollow2D.xml2
-rw-r--r--doc/classes/PathFollow3D.xml2
-rw-r--r--doc/classes/Performance.xml2
-rw-r--r--doc/classes/PhysicalBone2D.xml4
-rw-r--r--doc/classes/PhysicalBone3D.xml2
-rw-r--r--doc/classes/PhysicalSkyMaterial.xml2
-rw-r--r--doc/classes/PhysicsBody2D.xml2
-rw-r--r--doc/classes/PhysicsBody3D.xml2
-rw-r--r--doc/classes/PhysicsDirectBodyState2D.xml2
-rw-r--r--doc/classes/PhysicsDirectBodyState2DExtension.xml2
-rw-r--r--doc/classes/PhysicsDirectBodyState3D.xml2
-rw-r--r--doc/classes/PhysicsDirectBodyState3DExtension.xml2
-rw-r--r--doc/classes/PhysicsDirectSpaceState2D.xml2
-rw-r--r--doc/classes/PhysicsDirectSpaceState2DExtension.xml2
-rw-r--r--doc/classes/PhysicsDirectSpaceState3D.xml2
-rw-r--r--doc/classes/PhysicsDirectSpaceState3DExtension.xml2
-rw-r--r--doc/classes/PhysicsMaterial.xml2
-rw-r--r--doc/classes/PhysicsPointQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsPointQueryParameters3D.xml2
-rw-r--r--doc/classes/PhysicsRayQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsRayQueryParameters3D.xml2
-rw-r--r--doc/classes/PhysicsServer2D.xml2
-rw-r--r--doc/classes/PhysicsServer2DExtension.xml2
-rw-r--r--doc/classes/PhysicsServer2DManager.xml2
-rw-r--r--doc/classes/PhysicsServer3D.xml6
-rw-r--r--doc/classes/PhysicsServer3DExtension.xml2
-rw-r--r--doc/classes/PhysicsServer3DManager.xml2
-rw-r--r--doc/classes/PhysicsServer3DRenderingServerHandler.xml2
-rw-r--r--doc/classes/PhysicsShapeQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsShapeQueryParameters3D.xml2
-rw-r--r--doc/classes/PhysicsTestMotionParameters2D.xml2
-rw-r--r--doc/classes/PhysicsTestMotionParameters3D.xml2
-rw-r--r--doc/classes/PhysicsTestMotionResult2D.xml2
-rw-r--r--doc/classes/PhysicsTestMotionResult3D.xml2
-rw-r--r--doc/classes/PinJoint2D.xml2
-rw-r--r--doc/classes/PinJoint3D.xml4
-rw-r--r--doc/classes/PlaceholderCubemap.xml2
-rw-r--r--doc/classes/PlaceholderCubemapArray.xml2
-rw-r--r--doc/classes/PlaceholderMaterial.xml2
-rw-r--r--doc/classes/PlaceholderMesh.xml2
-rw-r--r--doc/classes/PlaceholderTexture2D.xml2
-rw-r--r--doc/classes/PlaceholderTexture2DArray.xml2
-rw-r--r--doc/classes/PlaceholderTexture3D.xml2
-rw-r--r--doc/classes/PlaceholderTextureLayered.xml2
-rw-r--r--doc/classes/Plane.xml2
-rw-r--r--doc/classes/PlaneMesh.xml2
-rw-r--r--doc/classes/PointLight2D.xml2
-rw-r--r--doc/classes/PointMesh.xml2
-rw-r--r--doc/classes/Polygon2D.xml2
-rw-r--r--doc/classes/PolygonOccluder3D.xml2
-rw-r--r--doc/classes/PolygonPathFinder.xml2
-rw-r--r--doc/classes/Popup.xml2
-rw-r--r--doc/classes/PopupMenu.xml2
-rw-r--r--doc/classes/PopupPanel.xml2
-rw-r--r--doc/classes/PortableCompressedTexture2D.xml2
-rw-r--r--doc/classes/PrimitiveMesh.xml2
-rw-r--r--doc/classes/PrismMesh.xml2
-rw-r--r--doc/classes/ProceduralSkyMaterial.xml2
-rw-r--r--doc/classes/ProgressBar.xml2
-rw-r--r--doc/classes/ProjectSettings.xml26
-rw-r--r--doc/classes/Projection.xml2
-rw-r--r--doc/classes/PropertyTweener.xml2
-rw-r--r--doc/classes/QuadMesh.xml2
-rw-r--r--doc/classes/QuadOccluder3D.xml2
-rw-r--r--doc/classes/Quaternion.xml2
-rw-r--r--doc/classes/RDAttachmentFormat.xml2
-rw-r--r--doc/classes/RDFramebufferPass.xml2
-rw-r--r--doc/classes/RDPipelineColorBlendState.xml2
-rw-r--r--doc/classes/RDPipelineColorBlendStateAttachment.xml2
-rw-r--r--doc/classes/RDPipelineDepthStencilState.xml2
-rw-r--r--doc/classes/RDPipelineMultisampleState.xml2
-rw-r--r--doc/classes/RDPipelineRasterizationState.xml2
-rw-r--r--doc/classes/RDPipelineSpecializationConstant.xml2
-rw-r--r--doc/classes/RDSamplerState.xml2
-rw-r--r--doc/classes/RDShaderFile.xml2
-rw-r--r--doc/classes/RDShaderSPIRV.xml2
-rw-r--r--doc/classes/RDShaderSource.xml2
-rw-r--r--doc/classes/RDTextureFormat.xml2
-rw-r--r--doc/classes/RDTextureView.xml2
-rw-r--r--doc/classes/RDUniform.xml2
-rw-r--r--doc/classes/RDVertexAttribute.xml2
-rw-r--r--doc/classes/RID.xml2
-rw-r--r--doc/classes/RandomNumberGenerator.xml2
-rw-r--r--doc/classes/Range.xml2
-rw-r--r--doc/classes/RayCast2D.xml2
-rw-r--r--doc/classes/RayCast3D.xml5
-rw-r--r--doc/classes/Rect2.xml2
-rw-r--r--doc/classes/Rect2i.xml2
-rw-r--r--doc/classes/RectangleShape2D.xml2
-rw-r--r--doc/classes/RefCounted.xml2
-rw-r--r--doc/classes/ReferenceRect.xml2
-rw-r--r--doc/classes/ReflectionProbe.xml2
-rw-r--r--doc/classes/RemoteTransform2D.xml2
-rw-r--r--doc/classes/RemoteTransform3D.xml2
-rw-r--r--doc/classes/RenderSceneBuffers.xml21
-rw-r--r--doc/classes/RenderSceneBuffersConfiguration.xml40
-rw-r--r--doc/classes/RenderSceneBuffersExtension.xml41
-rw-r--r--doc/classes/RenderSceneBuffersRD.xml167
-rw-r--r--doc/classes/RenderingDevice.xml49
-rw-r--r--doc/classes/RenderingServer.xml19
-rw-r--r--doc/classes/Resource.xml4
-rw-r--r--doc/classes/ResourceFormatLoader.xml2
-rw-r--r--doc/classes/ResourceFormatSaver.xml2
-rw-r--r--doc/classes/ResourceImporter.xml2
-rw-r--r--doc/classes/ResourceImporterBMFont.xml22
-rw-r--r--doc/classes/ResourceImporterBitMap.xml22
-rw-r--r--doc/classes/ResourceImporterCSVTranslation.xml28
-rw-r--r--doc/classes/ResourceImporterDynamicFont.xml77
-rw-r--r--doc/classes/ResourceImporterImage.xml12
-rw-r--r--doc/classes/ResourceImporterImageFont.xml38
-rw-r--r--doc/classes/ResourceImporterLayeredTexture.xml57
-rw-r--r--doc/classes/ResourceImporterOBJ.xml28
-rw-r--r--doc/classes/ResourceImporterScene.xml70
-rw-r--r--doc/classes/ResourceImporterShaderFile.xml11
-rw-r--r--doc/classes/ResourceImporterTexture.xml106
-rw-r--r--doc/classes/ResourceImporterTextureAtlas.xml29
-rw-r--r--doc/classes/ResourceImporterWAV.xml53
-rw-r--r--doc/classes/ResourceLoader.xml8
-rw-r--r--doc/classes/ResourcePreloader.xml2
-rw-r--r--doc/classes/ResourceSaver.xml2
-rw-r--r--doc/classes/ResourceUID.xml2
-rw-r--r--doc/classes/RibbonTrailMesh.xml2
-rw-r--r--doc/classes/RichTextEffect.xml2
-rw-r--r--doc/classes/RichTextLabel.xml25
-rw-r--r--doc/classes/RigidBody2D.xml4
-rw-r--r--doc/classes/RigidBody3D.xml4
-rw-r--r--doc/classes/RootMotionView.xml2
-rw-r--r--doc/classes/SceneState.xml2
-rw-r--r--doc/classes/SceneTree.xml6
-rw-r--r--doc/classes/SceneTreeTimer.xml2
-rw-r--r--doc/classes/Script.xml2
-rw-r--r--doc/classes/ScriptCreateDialog.xml2
-rw-r--r--doc/classes/ScriptEditor.xml2
-rw-r--r--doc/classes/ScriptEditorBase.xml2
-rw-r--r--doc/classes/ScriptExtension.xml2
-rw-r--r--doc/classes/ScriptLanguage.xml2
-rw-r--r--doc/classes/ScriptLanguageExtension.xml2
-rw-r--r--doc/classes/ScrollBar.xml2
-rw-r--r--doc/classes/ScrollContainer.xml2
-rw-r--r--doc/classes/SegmentShape2D.xml2
-rw-r--r--doc/classes/Semaphore.xml2
-rw-r--r--doc/classes/SeparationRayShape2D.xml2
-rw-r--r--doc/classes/SeparationRayShape3D.xml4
-rw-r--r--doc/classes/Separator.xml2
-rw-r--r--doc/classes/Shader.xml2
-rw-r--r--doc/classes/ShaderGlobalsOverride.xml2
-rw-r--r--doc/classes/ShaderInclude.xml2
-rw-r--r--doc/classes/ShaderMaterial.xml3
-rw-r--r--doc/classes/Shape2D.xml2
-rw-r--r--doc/classes/Shape3D.xml2
-rw-r--r--doc/classes/ShapeCast2D.xml2
-rw-r--r--doc/classes/ShapeCast3D.xml6
-rw-r--r--doc/classes/Shortcut.xml2
-rw-r--r--doc/classes/Signal.xml2
-rw-r--r--doc/classes/Skeleton2D.xml2
-rw-r--r--doc/classes/Skeleton3D.xml2
-rw-r--r--doc/classes/SkeletonIK3D.xml2
-rw-r--r--doc/classes/SkeletonModification2D.xml2
-rw-r--r--doc/classes/SkeletonModification2DCCDIK.xml2
-rw-r--r--doc/classes/SkeletonModification2DFABRIK.xml2
-rw-r--r--doc/classes/SkeletonModification2DJiggle.xml2
-rw-r--r--doc/classes/SkeletonModification2DLookAt.xml2
-rw-r--r--doc/classes/SkeletonModification2DPhysicalBones.xml2
-rw-r--r--doc/classes/SkeletonModification2DStackHolder.xml2
-rw-r--r--doc/classes/SkeletonModification2DTwoBoneIK.xml2
-rw-r--r--doc/classes/SkeletonModificationStack2D.xml2
-rw-r--r--doc/classes/SkeletonProfile.xml2
-rw-r--r--doc/classes/SkeletonProfileHumanoid.xml2
-rw-r--r--doc/classes/Skin.xml2
-rw-r--r--doc/classes/SkinReference.xml2
-rw-r--r--doc/classes/Sky.xml2
-rw-r--r--doc/classes/Slider.xml2
-rw-r--r--doc/classes/SliderJoint3D.xml4
-rw-r--r--doc/classes/SoftBody3D.xml2
-rw-r--r--doc/classes/SphereMesh.xml2
-rw-r--r--doc/classes/SphereOccluder3D.xml2
-rw-r--r--doc/classes/SphereShape3D.xml2
-rw-r--r--doc/classes/SpinBox.xml2
-rw-r--r--doc/classes/SplitContainer.xml2
-rw-r--r--doc/classes/SpotLight3D.xml2
-rw-r--r--doc/classes/SpringArm3D.xml2
-rw-r--r--doc/classes/Sprite2D.xml2
-rw-r--r--doc/classes/Sprite3D.xml2
-rw-r--r--doc/classes/SpriteBase3D.xml2
-rw-r--r--doc/classes/SpriteFrames.xml2
-rw-r--r--doc/classes/StandardMaterial3D.xml2
-rw-r--r--doc/classes/StaticBody2D.xml2
-rw-r--r--doc/classes/StaticBody3D.xml2
-rw-r--r--doc/classes/StreamPeer.xml2
-rw-r--r--doc/classes/StreamPeerBuffer.xml2
-rw-r--r--doc/classes/StreamPeerExtension.xml2
-rw-r--r--doc/classes/StreamPeerGZIP.xml2
-rw-r--r--doc/classes/StreamPeerTCP.xml2
-rw-r--r--doc/classes/StreamPeerTLS.xml2
-rw-r--r--doc/classes/String.xml14
-rw-r--r--doc/classes/StringName.xml4
-rw-r--r--doc/classes/StyleBox.xml2
-rw-r--r--doc/classes/StyleBoxEmpty.xml2
-rw-r--r--doc/classes/StyleBoxFlat.xml2
-rw-r--r--doc/classes/StyleBoxLine.xml2
-rw-r--r--doc/classes/StyleBoxTexture.xml2
-rw-r--r--doc/classes/SubViewport.xml2
-rw-r--r--doc/classes/SubViewportContainer.xml3
-rw-r--r--doc/classes/SurfaceTool.xml2
-rw-r--r--doc/classes/SyntaxHighlighter.xml2
-rw-r--r--doc/classes/SystemFont.xml2
-rw-r--r--doc/classes/TCPServer.xml2
-rw-r--r--doc/classes/TLSOptions.xml10
-rw-r--r--doc/classes/TabBar.xml2
-rw-r--r--doc/classes/TabContainer.xml2
-rw-r--r--doc/classes/TextEdit.xml4
-rw-r--r--doc/classes/TextLine.xml2
-rw-r--r--doc/classes/TextMesh.xml2
-rw-r--r--doc/classes/TextParagraph.xml2
-rw-r--r--doc/classes/TextServer.xml2
-rw-r--r--doc/classes/TextServerDummy.xml2
-rw-r--r--doc/classes/TextServerExtension.xml2
-rw-r--r--doc/classes/TextServerManager.xml2
-rw-r--r--doc/classes/Texture.xml2
-rw-r--r--doc/classes/Texture2D.xml2
-rw-r--r--doc/classes/Texture2DArray.xml2
-rw-r--r--doc/classes/Texture2DArrayRD.xml11
-rw-r--r--doc/classes/Texture2DRD.xml17
-rw-r--r--doc/classes/Texture3D.xml2
-rw-r--r--doc/classes/Texture3DRD.xml16
-rw-r--r--doc/classes/TextureButton.xml2
-rw-r--r--doc/classes/TextureCubemapArrayRD.xml11
-rw-r--r--doc/classes/TextureCubemapRD.xml11
-rw-r--r--doc/classes/TextureLayered.xml2
-rw-r--r--doc/classes/TextureLayeredRD.xml16
-rw-r--r--doc/classes/TextureProgressBar.xml2
-rw-r--r--doc/classes/TextureRect.xml2
-rw-r--r--doc/classes/Theme.xml2
-rw-r--r--doc/classes/ThemeDB.xml2
-rw-r--r--doc/classes/Thread.xml3
-rw-r--r--doc/classes/TileData.xml2
-rw-r--r--doc/classes/TileMap.xml58
-rw-r--r--doc/classes/TileMapPattern.xml2
-rw-r--r--doc/classes/TileSet.xml2
-rw-r--r--doc/classes/TileSetAtlasSource.xml28
-rw-r--r--doc/classes/TileSetScenesCollectionSource.xml2
-rw-r--r--doc/classes/TileSetSource.xml2
-rw-r--r--doc/classes/Time.xml2
-rw-r--r--doc/classes/Timer.xml2
-rw-r--r--doc/classes/TorusMesh.xml2
-rw-r--r--doc/classes/TouchScreenButton.xml2
-rw-r--r--doc/classes/Transform2D.xml2
-rw-r--r--doc/classes/Transform3D.xml2
-rw-r--r--doc/classes/Translation.xml2
-rw-r--r--doc/classes/TranslationServer.xml2
-rw-r--r--doc/classes/Tree.xml14
-rw-r--r--doc/classes/TreeItem.xml11
-rw-r--r--doc/classes/TriangleMesh.xml2
-rw-r--r--doc/classes/TubeTrailMesh.xml2
-rw-r--r--doc/classes/Tween.xml4
-rw-r--r--doc/classes/Tweener.xml2
-rw-r--r--doc/classes/UDPServer.xml2
-rw-r--r--doc/classes/UndoRedo.xml2
-rw-r--r--doc/classes/VBoxContainer.xml2
-rw-r--r--doc/classes/VFlowContainer.xml2
-rw-r--r--doc/classes/VScrollBar.xml2
-rw-r--r--doc/classes/VSeparator.xml2
-rw-r--r--doc/classes/VSlider.xml2
-rw-r--r--doc/classes/VSplitContainer.xml2
-rw-r--r--doc/classes/Variant.xml2
-rw-r--r--doc/classes/Vector2.xml2
-rw-r--r--doc/classes/Vector2i.xml2
-rw-r--r--doc/classes/Vector3.xml2
-rw-r--r--doc/classes/Vector3i.xml2
-rw-r--r--doc/classes/Vector4.xml2
-rw-r--r--doc/classes/Vector4i.xml2
-rw-r--r--doc/classes/VehicleBody3D.xml2
-rw-r--r--doc/classes/VehicleWheel3D.xml2
-rw-r--r--doc/classes/VideoStream.xml2
-rw-r--r--doc/classes/VideoStreamPlayback.xml2
-rw-r--r--doc/classes/VideoStreamPlayer.xml12
-rw-r--r--doc/classes/Viewport.xml6
-rw-r--r--doc/classes/ViewportTexture.xml2
-rw-r--r--doc/classes/VisibleOnScreenEnabler2D.xml2
-rw-r--r--doc/classes/VisibleOnScreenEnabler3D.xml2
-rw-r--r--doc/classes/VisibleOnScreenNotifier2D.xml2
-rw-r--r--doc/classes/VisibleOnScreenNotifier3D.xml2
-rw-r--r--doc/classes/VisualInstance3D.xml2
-rw-r--r--doc/classes/VisualShader.xml2
-rw-r--r--doc/classes/VisualShaderNode.xml9
-rw-r--r--doc/classes/VisualShaderNodeBillboard.xml2
-rw-r--r--doc/classes/VisualShaderNodeBooleanConstant.xml2
-rw-r--r--doc/classes/VisualShaderNodeBooleanParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeClamp.xml2
-rw-r--r--doc/classes/VisualShaderNodeColorConstant.xml2
-rw-r--r--doc/classes/VisualShaderNodeColorFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeColorOp.xml2
-rw-r--r--doc/classes/VisualShaderNodeColorParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeComment.xml2
-rw-r--r--doc/classes/VisualShaderNodeCompare.xml2
-rw-r--r--doc/classes/VisualShaderNodeConstant.xml2
-rw-r--r--doc/classes/VisualShaderNodeCubemap.xml2
-rw-r--r--doc/classes/VisualShaderNodeCubemapParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeCurveTexture.xml2
-rw-r--r--doc/classes/VisualShaderNodeCurveXYZTexture.xml2
-rw-r--r--doc/classes/VisualShaderNodeCustom.xml10
-rw-r--r--doc/classes/VisualShaderNodeDerivativeFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeDeterminant.xml2
-rw-r--r--doc/classes/VisualShaderNodeDistanceFade.xml2
-rw-r--r--doc/classes/VisualShaderNodeDotProduct.xml2
-rw-r--r--doc/classes/VisualShaderNodeExpression.xml2
-rw-r--r--doc/classes/VisualShaderNodeFaceForward.xml2
-rw-r--r--doc/classes/VisualShaderNodeFloatConstant.xml2
-rw-r--r--doc/classes/VisualShaderNodeFloatFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeFloatOp.xml2
-rw-r--r--doc/classes/VisualShaderNodeFloatParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeFresnel.xml2
-rw-r--r--doc/classes/VisualShaderNodeGlobalExpression.xml2
-rw-r--r--doc/classes/VisualShaderNodeGroupBase.xml2
-rw-r--r--doc/classes/VisualShaderNodeIf.xml2
-rw-r--r--doc/classes/VisualShaderNodeInput.xml2
-rw-r--r--doc/classes/VisualShaderNodeIntConstant.xml2
-rw-r--r--doc/classes/VisualShaderNodeIntFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeIntOp.xml2
-rw-r--r--doc/classes/VisualShaderNodeIntParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeIs.xml2
-rw-r--r--doc/classes/VisualShaderNodeLinearSceneDepth.xml2
-rw-r--r--doc/classes/VisualShaderNodeMix.xml2
-rw-r--r--doc/classes/VisualShaderNodeMultiplyAdd.xml2
-rw-r--r--doc/classes/VisualShaderNodeOuterProduct.xml2
-rw-r--r--doc/classes/VisualShaderNodeOutput.xml2
-rw-r--r--doc/classes/VisualShaderNodeParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeParameterRef.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleAccelerator.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleBoxEmitter.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleConeVelocity.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleEmit.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleEmitter.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleMeshEmitter.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleOutput.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleRandomness.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleRingEmitter.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleSphereEmitter.xml2
-rw-r--r--doc/classes/VisualShaderNodeProximityFade.xml2
-rw-r--r--doc/classes/VisualShaderNodeRandomRange.xml2
-rw-r--r--doc/classes/VisualShaderNodeRemap.xml2
-rw-r--r--doc/classes/VisualShaderNodeResizableBase.xml2
-rw-r--r--doc/classes/VisualShaderNodeRotationByAxis.xml11
-rw-r--r--doc/classes/VisualShaderNodeSDFRaymarch.xml2
-rw-r--r--doc/classes/VisualShaderNodeSDFToScreenUV.xml2
-rw-r--r--doc/classes/VisualShaderNodeSample3D.xml2
-rw-r--r--doc/classes/VisualShaderNodeScreenNormalWorldSpace.xml11
-rw-r--r--doc/classes/VisualShaderNodeScreenUVToSDF.xml2
-rw-r--r--doc/classes/VisualShaderNodeSmoothStep.xml2
-rw-r--r--doc/classes/VisualShaderNodeStep.xml2
-rw-r--r--doc/classes/VisualShaderNodeSwitch.xml2
-rw-r--r--doc/classes/VisualShaderNodeTexture.xml2
-rw-r--r--doc/classes/VisualShaderNodeTexture2DArray.xml2
-rw-r--r--doc/classes/VisualShaderNodeTexture2DArrayParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeTexture2DParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeTexture3D.xml2
-rw-r--r--doc/classes/VisualShaderNodeTexture3DParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeTextureParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeTextureParameterTriplanar.xml2
-rw-r--r--doc/classes/VisualShaderNodeTextureSDF.xml2
-rw-r--r--doc/classes/VisualShaderNodeTextureSDFNormal.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformCompose.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformConstant.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformDecompose.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformOp.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformVecMult.xml2
-rw-r--r--doc/classes/VisualShaderNodeUIntConstant.xml2
-rw-r--r--doc/classes/VisualShaderNodeUIntFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeUIntOp.xml2
-rw-r--r--doc/classes/VisualShaderNodeUIntParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeUVFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeUVPolarCoord.xml2
-rw-r--r--doc/classes/VisualShaderNodeVarying.xml2
-rw-r--r--doc/classes/VisualShaderNodeVaryingGetter.xml2
-rw-r--r--doc/classes/VisualShaderNodeVaryingSetter.xml2
-rw-r--r--doc/classes/VisualShaderNodeVec2Constant.xml2
-rw-r--r--doc/classes/VisualShaderNodeVec2Parameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeVec3Constant.xml2
-rw-r--r--doc/classes/VisualShaderNodeVec3Parameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeVec4Constant.xml2
-rw-r--r--doc/classes/VisualShaderNodeVec4Parameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeVectorBase.xml2
-rw-r--r--doc/classes/VisualShaderNodeVectorCompose.xml2
-rw-r--r--doc/classes/VisualShaderNodeVectorDecompose.xml2
-rw-r--r--doc/classes/VisualShaderNodeVectorDistance.xml2
-rw-r--r--doc/classes/VisualShaderNodeVectorFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeVectorLen.xml2
-rw-r--r--doc/classes/VisualShaderNodeVectorOp.xml2
-rw-r--r--doc/classes/VisualShaderNodeVectorRefract.xml2
-rw-r--r--doc/classes/VisualShaderNodeWorldPositionFromDepth.xml11
-rw-r--r--doc/classes/VoxelGI.xml2
-rw-r--r--doc/classes/VoxelGIData.xml2
-rw-r--r--doc/classes/WeakRef.xml2
-rw-r--r--doc/classes/Window.xml5
-rw-r--r--doc/classes/WorkerThreadPool.xml2
-rw-r--r--doc/classes/World2D.xml2
-rw-r--r--doc/classes/World3D.xml2
-rw-r--r--doc/classes/WorldBoundaryShape2D.xml2
-rw-r--r--doc/classes/WorldBoundaryShape3D.xml2
-rw-r--r--doc/classes/WorldEnvironment.xml2
-rw-r--r--doc/classes/X509Certificate.xml2
-rw-r--r--doc/classes/XMLParser.xml2
-rw-r--r--doc/classes/XRAnchor3D.xml2
-rw-r--r--doc/classes/XRCamera3D.xml2
-rw-r--r--doc/classes/XRController3D.xml2
-rw-r--r--doc/classes/XRInterface.xml2
-rw-r--r--doc/classes/XRInterfaceExtension.xml2
-rw-r--r--doc/classes/XRNode3D.xml2
-rw-r--r--doc/classes/XROrigin3D.xml2
-rw-r--r--doc/classes/XRPose.xml2
-rw-r--r--doc/classes/XRPositionalTracker.xml2
-rw-r--r--doc/classes/XRServer.xml2
-rw-r--r--doc/classes/bool.xml2
-rw-r--r--doc/classes/float.xml2
-rw-r--r--doc/classes/int.xml2
-rwxr-xr-xdoc/tools/doc_status.py6
-rwxr-xr-xdoc/tools/make_rst.py52
-rw-r--r--doc/translations/es.po67
-rw-r--r--doc/translations/zh_CN.po1891
-rw-r--r--drivers/gles3/effects/copy_effects.cpp76
-rw-r--r--drivers/gles3/effects/copy_effects.h1
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp182
-rw-r--r--drivers/gles3/shader_gles3.cpp6
-rw-r--r--drivers/gles3/shaders/copy.glsl39
-rw-r--r--drivers/gles3/shaders/scene.glsl18
-rw-r--r--drivers/gles3/shaders/sky.glsl12
-rw-r--r--drivers/gles3/storage/material_storage.cpp2
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp9
-rw-r--r--drivers/gles3/storage/particles_storage.cpp19
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp28
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h2
-rw-r--r--drivers/gles3/storage/texture_storage.cpp17
-rw-r--r--drivers/gles3/storage/texture_storage.h34
-rw-r--r--drivers/png/resource_saver_png.cpp2
-rw-r--r--drivers/unix/file_access_unix.cpp5
-rw-r--r--drivers/unix/net_socket_posix.cpp20
-rw-r--r--drivers/unix/net_socket_posix.h1
-rw-r--r--drivers/unix/os_unix.cpp4
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp130
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h1
-rw-r--r--drivers/vulkan/vulkan_context.cpp10
-rw-r--r--editor/animation_track_editor.cpp12
-rw-r--r--editor/animation_track_editor_plugins.cpp4
-rw-r--r--editor/code_editor.cpp19
-rw-r--r--editor/code_editor.h1
-rw-r--r--editor/connections_dialog.cpp2
-rw-r--r--editor/create_dialog.cpp6
-rw-r--r--editor/debugger/editor_debugger_inspector.cpp2
-rw-r--r--editor/debugger/editor_profiler.cpp1
-rw-r--r--editor/debugger/editor_profiler.h2
-rw-r--r--editor/debugger/editor_visual_profiler.cpp1
-rw-r--r--editor/debugger/editor_visual_profiler.h2
-rw-r--r--editor/debugger/script_editor_debugger.cpp207
-rw-r--r--editor/debugger/script_editor_debugger.h37
-rw-r--r--editor/doc_tools.cpp55
-rw-r--r--editor/editor_data.cpp14
-rw-r--r--editor/editor_data.h1
-rw-r--r--editor/editor_feature_profile.cpp54
-rw-r--r--editor/editor_feature_profile.h2
-rw-r--r--editor/editor_file_system.cpp3
-rw-r--r--editor/editor_help.cpp126
-rw-r--r--editor/editor_inspector.cpp4
-rw-r--r--editor/editor_inspector.h1
-rw-r--r--editor/editor_interface.cpp17
-rw-r--r--editor/editor_interface.h4
-rw-r--r--editor/editor_log.cpp8
-rw-r--r--editor/editor_node.cpp145
-rw-r--r--editor/editor_node.h3
-rw-r--r--editor/editor_plugin.cpp18
-rw-r--r--editor/editor_plugin.h5
-rw-r--r--editor/editor_plugin_settings.cpp11
-rw-r--r--editor/editor_properties.cpp8
-rw-r--r--editor/editor_resource_picker.cpp124
-rw-r--r--editor/editor_resource_picker.h19
-rw-r--r--editor/editor_resource_preview.cpp1
-rw-r--r--editor/editor_resource_preview.h4
-rw-r--r--editor/editor_run_native.cpp1
-rw-r--r--editor/editor_settings.cpp18
-rw-r--r--editor/editor_settings.h1
-rw-r--r--editor/editor_themes.cpp38
-rw-r--r--editor/editor_undo_redo_manager.cpp2
-rw-r--r--editor/export/editor_export.cpp38
-rw-r--r--editor/export/editor_export.h1
-rw-r--r--editor/export/editor_export_platform.cpp32
-rw-r--r--editor/export/editor_export_platform.h1
-rw-r--r--editor/export/editor_export_platform_pc.cpp1
-rw-r--r--editor/export/editor_export_plugin.cpp81
-rw-r--r--editor/export/editor_export_plugin.h27
-rw-r--r--editor/export/editor_export_preset.cpp33
-rw-r--r--editor/export/editor_export_preset.h5
-rw-r--r--editor/export/export_template_manager.cpp7
-rw-r--r--editor/export/project_export.cpp4
-rw-r--r--editor/filesystem_dock.cpp4
-rw-r--r--editor/gui/editor_toaster.cpp1
-rw-r--r--editor/gui/editor_toaster.h1
-rw-r--r--editor/gui/scene_tree_editor.cpp41
-rw-r--r--editor/icons/AnimatedSprite2D.svg2
-rw-r--r--editor/icons/AnimatedSprite3D.svg2
-rw-r--r--editor/icons/AssetLib.svg2
-rw-r--r--editor/icons/AutoKey.svg2
-rw-r--r--editor/icons/Bone.svg2
-rw-r--r--editor/icons/Bone2D.svg2
-rw-r--r--editor/icons/BoneAttachment3D.svg2
-rw-r--r--editor/icons/ClassList.svg2
-rw-r--r--editor/icons/CopyNodePath.svg2
-rw-r--r--editor/icons/CryptoKey.svg2
-rw-r--r--editor/icons/EditorPositionUnselected.svg2
-rw-r--r--editor/icons/Enum.svg2
-rw-r--r--editor/icons/ExpandBottomDock.svg2
-rw-r--r--editor/icons/ExternalLink.svg2
-rw-r--r--editor/icons/Gizmo3DSamplePlayer.svg2
-rw-r--r--editor/icons/GizmoAudioListener3D.svg2
-rw-r--r--editor/icons/GizmoCPUParticles3D.svg2
-rw-r--r--editor/icons/GizmoDirectionalLight.svg2
-rw-r--r--editor/icons/GizmoSpotLight.svg2
-rw-r--r--editor/icons/GizmoVoxelGI.svg2
-rw-r--r--editor/icons/GridToggle.svg1
-rw-r--r--editor/icons/GuiGraphNodePort.svg2
-rw-r--r--editor/icons/GuiIndeterminate.svg2
-rw-r--r--editor/icons/GuiSpinboxUpdown.svg2
-rw-r--r--editor/icons/GuiSpinboxUpdownDisabled.svg2
-rw-r--r--editor/icons/GuiTabMenu.svg2
-rw-r--r--editor/icons/GuiTabMenuHl.svg2
-rw-r--r--editor/icons/GuiVisibilityHidden.svg2
-rw-r--r--editor/icons/HSlider.svg2
-rw-r--r--editor/icons/Heart.svg2
-rw-r--r--editor/icons/Help.svg2
-rw-r--r--editor/icons/IOSDeviceWired.svg1
-rw-r--r--editor/icons/IOSDeviceWireless.svg1
-rw-r--r--editor/icons/IOSSimulator.svg1
-rw-r--r--editor/icons/Info.svg1
-rw-r--r--editor/icons/KeyInvalid.svg2
-rw-r--r--editor/icons/KeyPosition.svg2
-rw-r--r--editor/icons/KeyScale.svg2
-rw-r--r--editor/icons/Load.svg2
-rw-r--r--editor/icons/LockViewport.svg2
-rw-r--r--editor/icons/Loop.svg2
-rw-r--r--editor/icons/MatchCase.svg2
-rw-r--r--editor/icons/MeshLibrary.svg2
-rw-r--r--editor/icons/MeshTexture.svg2
-rw-r--r--editor/icons/MethodOverrideAndSlot.svg2
-rw-r--r--editor/icons/NodeInfo.svg2
-rw-r--r--editor/icons/ORMMaterial3D.svg2
-rw-r--r--editor/icons/Play.svg2
-rw-r--r--editor/icons/Popup.svg2
-rw-r--r--editor/icons/ProgressBar.svg2
-rw-r--r--editor/icons/ProxyTexture.svg2
-rw-r--r--editor/icons/Rename.svg2
-rw-r--r--editor/icons/ShaderGlobalsOverride.svg2
-rw-r--r--editor/icons/Sort.svg2
-rw-r--r--editor/icons/SpotLight3D.svg2
-rw-r--r--editor/icons/SpriteFrames.svg2
-rw-r--r--editor/icons/SpriteSheet.svg2
-rw-r--r--editor/icons/TextureButton.svg2
-rw-r--r--editor/icons/ToolPan.svg2
-rw-r--r--editor/icons/Tools.svg2
-rw-r--r--editor/icons/TouchScreenButton.svg2
-rw-r--r--editor/icons/TrackCapture.svg2
-rw-r--r--editor/icons/TrackContinuous.svg2
-rw-r--r--editor/icons/TransitionImmediate.svg2
-rw-r--r--editor/icons/TransitionImmediateAuto.svg2
-rw-r--r--editor/icons/Transpose.svg1
-rw-r--r--editor/icons/Tree.svg2
-rw-r--r--editor/icons/VSlider.svg2
-rw-r--r--editor/icons/VehicleBody3D.svg2
-rw-r--r--editor/icons/ViewportTexture.svg2
-rw-r--r--editor/icons/VisualShaderNodeBooleanUniform.svg2
-rw-r--r--editor/icons/VisualShaderNodeCubemap.svg2
-rw-r--r--editor/icons/VisualShaderNodeExpression.svg2
-rw-r--r--editor/icons/VisualShaderNodeGlobalExpression.svg2
-rw-r--r--editor/icons/VisualShaderNodeTransformUniform.svg2
-rw-r--r--editor/icons/VoxelGIData.svg2
-rw-r--r--editor/import/audio_stream_import_settings.cpp4
-rw-r--r--editor/import/resource_importer_imagefont.cpp2
-rw-r--r--editor/import/resource_importer_layered_texture.cpp1
-rw-r--r--editor/import/resource_importer_scene.cpp10
-rw-r--r--editor/import/resource_importer_texture.cpp8
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp4
-rw-r--r--editor/import/scene_import_settings.cpp217
-rw-r--r--editor/import/scene_import_settings.h20
-rw-r--r--editor/import_defaults_editor.cpp8
-rw-r--r--editor/import_dock.cpp95
-rw-r--r--editor/import_dock.h6
-rw-r--r--editor/node_dock.cpp7
-rw-r--r--editor/node_dock.h2
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp13
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp1
-rw-r--r--editor/plugins/animation_player_editor_plugin.h1
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp5
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp19
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp5
-rw-r--r--editor/plugins/bit_map_editor_plugin.cpp1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp9
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h3
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp16
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.h1
-rw-r--r--editor/plugins/curve_editor_plugin.cpp10
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp3
-rw-r--r--editor/plugins/dedicated_server_export_plugin.h2
-rw-r--r--editor/plugins/editor_preview_plugins.cpp3
-rw-r--r--editor/plugins/font_config_plugin.cpp1
-rw-r--r--editor/plugins/gdextension_export_plugin.h2
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp19
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.h1
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp1
-rw-r--r--editor/plugins/gradient_editor.cpp3
-rw-r--r--editor/plugins/gradient_editor.h2
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp3
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.h1
-rw-r--r--editor/plugins/input_event_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp40
-rw-r--r--editor/plugins/node_3d_editor_plugin.h3
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp5
-rw-r--r--editor/plugins/script_editor_plugin.cpp78
-rw-r--r--editor/plugins/script_editor_plugin.h2
-rw-r--r--editor/plugins/script_text_editor.cpp86
-rw-r--r--editor/plugins/script_text_editor.h1
-rw-r--r--editor/plugins/shader_editor_plugin.cpp21
-rw-r--r--editor/plugins/shader_editor_plugin.h1
-rw-r--r--editor/plugins/shader_file_editor_plugin.cpp4
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp17
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h1
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp5
-rw-r--r--editor/plugins/text_shader_editor.cpp18
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp6
-rw-r--r--editor/plugins/texture_editor_plugin.cpp7
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp4
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp11
-rw-r--r--editor/plugins/texture_region_editor_plugin.h6
-rw-r--r--editor/plugins/theme_editor_plugin.cpp16
-rw-r--r--editor/plugins/theme_editor_preview.cpp2
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp1
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp48
-rw-r--r--editor/plugins/tiles/tile_data_editors.h5
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp64
-rw-r--r--editor/plugins/tiles/tile_map_editor.h16
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp234
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h19
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp158
-rw-r--r--editor/plugins/tiles/tile_set_editor.h21
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp4
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp310
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.h77
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp124
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp9
-rw-r--r--editor/project_converter_3_to_4.cpp55
-rw-r--r--editor/project_manager.cpp33
-rw-r--r--editor/project_manager.h2
-rw-r--r--editor/register_editor_types.cpp30
-rw-r--r--editor/shader_create_dialog.cpp73
-rw-r--r--editor/translations/editor/ar.po535
-rw-r--r--editor/translations/editor/de.po140
-rw-r--r--editor/translations/editor/es.po1158
-rw-r--r--editor/translations/editor/fr.po15
-rw-r--r--editor/translations/editor/ko.po5242
-rw-r--r--editor/translations/editor/pl.po105
-rw-r--r--editor/translations/editor/ro.po9
-rw-r--r--editor/translations/editor/ru.po548
-rw-r--r--editor/translations/editor/tr.po212
-rw-r--r--editor/translations/editor/uk.po9
-rw-r--r--editor/translations/editor/zh_CN.po91
-rw-r--r--editor/translations/editor/zh_TW.po3490
-rw-r--r--editor/translations/properties/de.po45
-rw-r--r--editor/translations/properties/es.po105
-rw-r--r--editor/translations/properties/ko.po2941
-rw-r--r--editor/translations/properties/pl.po6
-rw-r--r--editor/translations/properties/pt_BR.po8
-rw-r--r--editor/translations/properties/ru.po52
-rw-r--r--editor/translations/properties/tr.po23
-rw-r--r--editor/translations/properties/uk.po9
-rw-r--r--editor/translations/properties/zh_CN.po16
-rw-r--r--editor/translations/properties/zh_TW.po76
-rw-r--r--editor/window_wrapper.cpp2
-rw-r--r--main/main.cpp23
-rw-r--r--misc/dist/macos_tools.app/Contents/Info.plist4
-rw-r--r--misc/dist/windows/godot.iss2
-rw-r--r--modules/csg/csg_shape.cpp4
-rw-r--r--modules/csg/doc_classes/CSGBox3D.xml2
-rw-r--r--modules/csg/doc_classes/CSGCombiner3D.xml2
-rw-r--r--modules/csg/doc_classes/CSGCylinder3D.xml2
-rw-r--r--modules/csg/doc_classes/CSGMesh3D.xml2
-rw-r--r--modules/csg/doc_classes/CSGPolygon3D.xml2
-rw-r--r--modules/csg/doc_classes/CSGPrimitive3D.xml2
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml2
-rw-r--r--modules/csg/doc_classes/CSGSphere3D.xml2
-rw-r--r--modules/csg/doc_classes/CSGTorus3D.xml2
-rw-r--r--modules/dds/texture_loader_dds.cpp1
-rw-r--r--modules/dds/texture_loader_dds.h1
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml2
-rw-r--r--modules/enet/doc_classes/ENetMultiplayerPeer.xml2
-rw-r--r--modules/enet/doc_classes/ENetPacketPeer.xml2
-rw-r--r--modules/enet/enet_packet_peer.cpp2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml2
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/editor/gdscript_docgen.cpp3
-rw-r--r--modules/gdscript/gdscript.cpp43
-rw-r--r--modules/gdscript/gdscript.h68
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp51
-rw-r--r--modules/gdscript/gdscript_analyzer.h3
-rw-r--r--modules/gdscript/gdscript_cache.cpp5
-rw-r--r--modules/gdscript/gdscript_compiler.cpp13
-rw-r--r--modules/gdscript/gdscript_editor.cpp80
-rw-r--r--modules/gdscript/gdscript_function.h12
-rw-r--r--modules/gdscript/gdscript_parser.cpp18
-rw-r--r--modules/gdscript/gdscript_vm.cpp20
-rw-r--r--modules/gdscript/register_types.cpp2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out16
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.out2
-rw-r--r--modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml2
-rw-r--r--modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml2
-rw-r--r--modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFAccessor.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFAnimation.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFBufferView.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFCamera.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFLight.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFMesh.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFPhysicsBody.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFPhysicsShape.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFSkeleton.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFSkin.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFSpecGloss.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFTexture.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFTextureSampler.xml2
-rw-r--r--modules/gltf/gltf_document.cpp66
-rw-r--r--modules/gltf/register_types.cpp4
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml6
-rw-r--r--modules/gridmap/grid_map.cpp13
-rw-r--r--modules/gridmap/grid_map.h2
-rw-r--r--modules/minimp3/config.py1
-rw-r--r--modules/minimp3/doc_classes/AudioStreamMP3.xml2
-rw-r--r--modules/minimp3/doc_classes/ResourceImporterMP3.xml37
-rw-r--r--modules/minimp3/register_types.cpp4
-rw-r--r--modules/mobile_vr/doc_classes/MobileVRInterface.xml2
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py16
-rw-r--r--modules/mono/csharp_script.cpp2
-rw-r--r--modules/mono/doc_classes/CSharpScript.xml2
-rw-r--r--modules/mono/doc_classes/GodotSharp.xml2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props13
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs60
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs18
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs42
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs22
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs36
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs15
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs23
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs7
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderLocatorEnvironment.cs51
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs474
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs8
-rw-r--r--modules/mono/editor/bindings_generator.cpp61
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs30
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs45
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs25
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs40
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj2
-rw-r--r--modules/multiplayer/doc_classes/MultiplayerSpawner.xml2
-rw-r--r--modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml2
-rw-r--r--modules/multiplayer/doc_classes/SceneMultiplayer.xml2
-rw-r--r--modules/multiplayer/doc_classes/SceneReplicationConfig.xml2
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.cpp4
-rw-r--r--modules/navigation/SCsub18
-rw-r--r--modules/navigation/godot_navigation_server.cpp36
-rw-r--r--modules/navigation/godot_navigation_server.h7
-rw-r--r--modules/navigation/nav_link.cpp10
-rw-r--r--modules/navigation/nav_link.h4
-rw-r--r--modules/navigation/nav_map.cpp107
-rw-r--r--modules/navigation/nav_region.cpp14
-rw-r--r--modules/navigation/nav_region.h4
-rw-r--r--modules/noise/doc_classes/FastNoiseLite.xml2
-rw-r--r--modules/noise/doc_classes/Noise.xml2
-rw-r--r--modules/noise/doc_classes/NoiseTexture2D.xml2
-rw-r--r--modules/noise/doc_classes/NoiseTexture3D.xml2
-rw-r--r--modules/noise/noise_texture_2d.cpp10
-rw-r--r--modules/noise/noise_texture_3d.cpp10
-rw-r--r--modules/noise/tests/test_noise_texture_2d.h8
-rw-r--r--modules/noise/tests/test_noise_texture_3d.h6
-rw-r--r--modules/ogg/doc_classes/OggPacketSequence.xml2
-rw-r--r--modules/ogg/doc_classes/OggPacketSequencePlayback.xml2
-rw-r--r--modules/openxr/SCsub114
-rw-r--r--modules/openxr/config.py2
-rw-r--r--modules/openxr/doc_classes/OpenXRAction.xml2
-rw-r--r--modules/openxr/doc_classes/OpenXRActionMap.xml2
-rw-r--r--modules/openxr/doc_classes/OpenXRActionSet.xml2
-rw-r--r--modules/openxr/doc_classes/OpenXRHand.xml2
-rw-r--r--modules/openxr/doc_classes/OpenXRIPBinding.xml2
-rw-r--r--modules/openxr/doc_classes/OpenXRInteractionProfile.xml2
-rw-r--r--modules/openxr/doc_classes/OpenXRInterface.xml2
-rw-r--r--modules/openxr/extensions/openxr_android_extension.cpp1
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper.h2
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper_extension.cpp207
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper_extension.h115
-rw-r--r--modules/openxr/extensions/openxr_hand_tracking_extension.cpp4
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.cpp4
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.cpp4
-rw-r--r--modules/openxr/openxr_api.cpp7
-rw-r--r--modules/openxr/openxr_api.h2
-rw-r--r--modules/openxr/openxr_api_extension.cpp130
-rw-r--r--modules/openxr/openxr_api_extension.h (renamed from core/os/threaded_array_processor.h)83
-rw-r--r--modules/openxr/openxr_util.cpp88
-rw-r--r--modules/openxr/openxr_util.h21
-rw-r--r--modules/openxr/register_types.cpp8
-rw-r--r--modules/openxr/util.h11
-rw-r--r--modules/regex/doc_classes/RegEx.xml2
-rw-r--r--modules/regex/doc_classes/RegExMatch.xml2
-rw-r--r--modules/svg/image_loader_svg.cpp22
-rw-r--r--modules/svg/image_loader_svg.h12
-rw-r--r--modules/text_server_adv/doc_classes/TextServerAdvanced.xml2
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct1
-rw-r--r--modules/text_server_adv/text_server_adv.cpp1
-rw-r--r--modules/text_server_adv/text_server_adv.h2
-rw-r--r--modules/text_server_fb/doc_classes/TextServerFallback.xml2
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct1
-rw-r--r--modules/text_server_fb/text_server_fb.h2
-rw-r--r--modules/theora/doc_classes/VideoStreamTheora.xml2
-rw-r--r--modules/theora/video_stream_theora.cpp1
-rw-r--r--modules/theora/video_stream_theora.h2
-rw-r--r--modules/upnp/doc_classes/UPNP.xml2
-rw-r--r--modules/upnp/doc_classes/UPNPDevice.xml2
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp12
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.h2
-rw-r--r--modules/vorbis/config.py1
-rw-r--r--modules/vorbis/doc_classes/AudioStreamOggVorbis.xml22
-rw-r--r--modules/vorbis/doc_classes/AudioStreamPlaybackOggVorbis.xml2
-rw-r--r--modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml53
-rw-r--r--modules/vorbis/register_types.cpp7
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.cpp94
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.h9
-rw-r--r--modules/webp/resource_saver_webp.cpp2
-rw-r--r--modules/webp/webp_common.cpp1
-rw-r--r--modules/webrtc/doc_classes/WebRTCDataChannel.xml2
-rw-r--r--modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml2
-rw-r--r--modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml2
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnection.xml2
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketPeer.xml2
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml2
-rw-r--r--modules/zip/doc_classes/ZIPPacker.xml2
-rw-r--r--modules/zip/doc_classes/ZIPReader.xml2
-rw-r--r--platform/android/android_input_handler.cpp5
-rw-r--r--platform/android/android_input_handler.h2
-rw-r--r--platform/android/doc_classes/EditorExportPlatformAndroid.xml14
-rw-r--r--platform/android/export/export_plugin.cpp217
-rw-r--r--platform/android/export/export_plugin.h36
-rw-r--r--platform/android/export/godot_plugin_config.cpp36
-rw-r--r--platform/android/export/godot_plugin_config.h12
-rw-r--r--platform/android/export/gradle_export_util.cpp101
-rw-r--r--platform/android/export/gradle_export_util.h20
-rw-r--r--platform/android/java/app/src/com/godot/game/GodotApp.java4
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt8
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java154
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java1195
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.kt965
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt167
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java429
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java20
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotHost.java9
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotService.kt54
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java13
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java16
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/tts/GodotTTS.java9
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java11
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java32
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java12
-rw-r--r--platform/android/java_godot_lib_jni.cpp6
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/android/java_godot_wrapper.cpp76
-rw-r--r--platform/android/java_godot_wrapper.h11
-rw-r--r--platform/android/os_android.cpp2
-rw-r--r--platform/ios/doc_classes/EditorExportPlatformIOS.xml5
-rw-r--r--platform/ios/export/export.cpp5
-rw-r--r--platform/ios/export/export_plugin.cpp486
-rw-r--r--platform/ios/export/export_plugin.h98
-rw-r--r--platform/ios/export/run_icon.svg1
-rw-r--r--platform/ios/os_ios.mm2
-rw-r--r--platform/linuxbsd/detect.py9
-rw-r--r--platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml2
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp5
-rw-r--r--platform/linuxbsd/export/export_plugin.h2
-rw-r--r--platform/linuxbsd/export/run_icon.svg2
-rw-r--r--platform/linuxbsd/joypad_linux.cpp34
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp34
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp34
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h1
-rw-r--r--platform/macos/display_server_macos.h6
-rw-r--r--platform/macos/display_server_macos.mm302
-rw-r--r--platform/macos/doc_classes/EditorExportPlatformMacOS.xml5
-rw-r--r--platform/macos/export/codesign.cpp22
-rw-r--r--platform/macos/export/export_plugin.cpp17
-rw-r--r--platform/macos/export/run_icon.svg2
-rw-r--r--platform/macos/os_macos.h4
-rw-r--r--platform/macos/os_macos.mm61
-rw-r--r--platform/uwp/export/export_plugin.cpp20
-rw-r--r--platform/uwp/export/export_plugin.h1
-rw-r--r--platform/uwp/os_uwp.cpp2
-rw-r--r--platform/web/display_server_web.cpp52
-rw-r--r--platform/web/doc_classes/EditorExportPlatformWeb.xml2
-rw-r--r--platform/web/export/export_plugin.cpp22
-rw-r--r--platform/web/export/run_icon.svg2
-rw-r--r--platform/web/http_client_web.cpp10
-rw-r--r--platform/web/http_client_web.h1
-rw-r--r--platform/web/js/libs/library_godot_display.js27
-rw-r--r--platform/web/js/libs/library_godot_fetch.js15
-rw-r--r--platform/web/os_web.cpp2
-rw-r--r--platform/windows/display_server_windows.cpp330
-rw-r--r--platform/windows/display_server_windows.h6
-rw-r--r--platform/windows/doc_classes/EditorExportPlatformWindows.xml2
-rw-r--r--platform/windows/export/export_plugin.cpp5
-rw-r--r--platform/windows/export/run_icon.svg2
-rw-r--r--platform/windows/gl_manager_windows.cpp1
-rw-r--r--platform/windows/os_windows.cpp6
-rw-r--r--scene/2d/camera_2d.cpp2
-rw-r--r--scene/2d/collision_shape_2d.cpp4
-rw-r--r--scene/2d/cpu_particles_2d.cpp42
-rw-r--r--scene/2d/cpu_particles_2d.h2
-rw-r--r--scene/2d/gpu_particles_2d.cpp64
-rw-r--r--scene/2d/gpu_particles_2d.h7
-rw-r--r--scene/2d/light_occluder_2d.cpp4
-rw-r--r--scene/2d/line_2d.cpp9
-rw-r--r--scene/2d/multimesh_instance_2d.cpp5
-rw-r--r--scene/2d/navigation_agent_2d.cpp9
-rw-r--r--scene/2d/navigation_link_2d.cpp10
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp24
-rw-r--r--scene/2d/navigation_region_2d.cpp143
-rw-r--r--scene/2d/navigation_region_2d.h7
-rw-r--r--scene/2d/path_2d.cpp4
-rw-r--r--scene/2d/physics_body_2d.cpp13
-rw-r--r--scene/2d/shape_cast_2d.cpp5
-rw-r--r--scene/2d/skeleton_2d.cpp4
-rw-r--r--scene/2d/sprite_2d.cpp5
-rw-r--r--scene/2d/tile_map.compat.inc45
-rw-r--r--scene/2d/tile_map.cpp4160
-rw-r--r--scene/2d/tile_map.h407
-rw-r--r--scene/2d/touch_screen_button.cpp17
-rw-r--r--scene/2d/touch_screen_button.h3
-rw-r--r--scene/3d/camera_3d.cpp73
-rw-r--r--scene/3d/camera_3d.h3
-rw-r--r--scene/3d/collision_object_3d.cpp14
-rw-r--r--scene/3d/collision_shape_3d.cpp17
-rw-r--r--scene/3d/collision_shape_3d.h2
-rw-r--r--scene/3d/cpu_particles_3d.cpp37
-rw-r--r--scene/3d/cpu_particles_3d.h2
-rw-r--r--scene/3d/gpu_particles_3d.cpp62
-rw-r--r--scene/3d/gpu_particles_3d.h9
-rw-r--r--scene/3d/label_3d.cpp19
-rw-r--r--scene/3d/lightmap_gi.cpp1
-rw-r--r--scene/3d/mesh_instance_3d.cpp5
-rw-r--r--scene/3d/navigation_agent_3d.cpp11
-rw-r--r--scene/3d/navigation_link_3d.cpp10
-rw-r--r--scene/3d/navigation_region_3d.cpp139
-rw-r--r--scene/3d/navigation_region_3d.h9
-rw-r--r--scene/3d/occluder_instance_3d.cpp5
-rw-r--r--scene/3d/path_3d.cpp4
-rw-r--r--scene/3d/physics_body_3d.cpp13
-rw-r--r--scene/3d/ray_cast_3d.cpp13
-rw-r--r--scene/3d/ray_cast_3d.h4
-rw-r--r--scene/3d/shape_cast_3d.cpp21
-rw-r--r--scene/3d/shape_cast_3d.h4
-rw-r--r--scene/3d/skeleton_3d.cpp2
-rw-r--r--scene/3d/sprite_3d.cpp11
-rw-r--r--scene/animation/animation_blend_tree.cpp22
-rw-r--r--scene/animation/animation_blend_tree.h2
-rw-r--r--scene/animation/animation_node_state_machine.cpp10
-rw-r--r--scene/animation/tween.cpp8
-rw-r--r--scene/debugger/scene_debugger.cpp8
-rw-r--r--scene/gui/button.cpp14
-rw-r--r--scene/gui/code_edit.cpp26
-rw-r--r--scene/gui/code_edit.h3
-rw-r--r--scene/gui/color_mode.cpp85
-rw-r--r--scene/gui/color_mode.h10
-rw-r--r--scene/gui/color_picker.cpp15
-rw-r--r--scene/gui/color_picker.h6
-rw-r--r--scene/gui/control.cpp34
-rw-r--r--scene/gui/dialogs.cpp61
-rw-r--r--scene/gui/dialogs.h4
-rw-r--r--scene/gui/file_dialog.cpp45
-rw-r--r--scene/gui/file_dialog.h8
-rw-r--r--scene/gui/graph_edit.cpp1486
-rw-r--r--scene/gui/graph_edit.h178
-rw-r--r--scene/gui/graph_edit_arranger.cpp565
-rw-r--r--scene/gui/graph_edit_arranger.h67
-rw-r--r--scene/gui/graph_node.cpp46
-rw-r--r--scene/gui/graph_node.h5
-rw-r--r--scene/gui/item_list.cpp3
-rw-r--r--scene/gui/label.cpp8
-rw-r--r--scene/gui/menu_bar.cpp2
-rw-r--r--scene/gui/nine_patch_rect.cpp5
-rw-r--r--scene/gui/option_button.cpp12
-rw-r--r--scene/gui/popup_menu.cpp20
-rw-r--r--scene/gui/popup_menu.h3
-rw-r--r--scene/gui/rich_text_label.cpp143
-rw-r--r--scene/gui/rich_text_label.h22
-rw-r--r--scene/gui/slider.cpp2
-rw-r--r--scene/gui/subviewport_container.cpp27
-rw-r--r--scene/gui/subviewport_container.h2
-rw-r--r--scene/gui/tab_bar.cpp3
-rw-r--r--scene/gui/texture_button.cpp5
-rw-r--r--scene/gui/texture_progress_bar.cpp6
-rw-r--r--scene/gui/texture_rect.cpp6
-rw-r--r--scene/gui/tree.cpp65
-rw-r--r--scene/gui/tree.h5
-rw-r--r--scene/gui/video_stream_player.cpp25
-rw-r--r--scene/gui/video_stream_player.h7
-rw-r--r--scene/main/canvas_item.h4
-rw-r--r--scene/main/node.cpp11
-rw-r--r--scene/main/scene_tree.cpp76
-rw-r--r--scene/main/scene_tree.h5
-rw-r--r--scene/main/viewport.cpp91
-rw-r--r--scene/main/viewport.h5
-rw-r--r--scene/main/window.cpp36
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/register_scene_types.cpp25
-rw-r--r--scene/resources/animated_texture.cpp286
-rw-r--r--scene/resources/animated_texture.h109
-rw-r--r--scene/resources/animation.cpp15
-rw-r--r--scene/resources/animation_library.cpp12
-rw-r--r--scene/resources/atlas_texture.cpp255
-rw-r--r--scene/resources/atlas_texture.h79
-rw-r--r--scene/resources/box_shape_3d.cpp2
-rw-r--r--scene/resources/camera_attributes.cpp2
-rw-r--r--scene/resources/camera_texture.cpp131
-rw-r--r--scene/resources/camera_texture.h68
-rw-r--r--scene/resources/capsule_shape_3d.cpp4
-rw-r--r--scene/resources/compressed_texture.cpp907
-rw-r--r--scene/resources/compressed_texture.h273
-rw-r--r--scene/resources/concave_polygon_shape_3d.cpp4
-rw-r--r--scene/resources/convex_polygon_shape_3d.cpp2
-rw-r--r--scene/resources/curve_texture.cpp376
-rw-r--r--scene/resources/curve_texture.h122
-rw-r--r--scene/resources/cylinder_shape_3d.cpp4
-rw-r--r--scene/resources/default_theme/default_theme.cpp200
-rw-r--r--scene/resources/default_theme/grid_toggle.svg1
-rw-r--r--scene/resources/environment.cpp7
-rw-r--r--scene/resources/font.cpp44
-rw-r--r--scene/resources/gradient_texture.cpp438
-rw-r--r--scene/resources/gradient_texture.h144
-rw-r--r--scene/resources/height_map_shape_3d.cpp6
-rw-r--r--scene/resources/image_texture.cpp514
-rw-r--r--scene/resources/image_texture.h203
-rw-r--r--scene/resources/label_settings.cpp6
-rw-r--r--scene/resources/material.cpp11
-rw-r--r--scene/resources/mesh_library.cpp8
-rw-r--r--scene/resources/mesh_texture.cpp156
-rw-r--r--scene/resources/mesh_texture.h75
-rw-r--r--scene/resources/navigation_mesh.cpp7
-rw-r--r--scene/resources/navigation_mesh.h17
-rw-r--r--scene/resources/navigation_polygon.cpp11
-rw-r--r--scene/resources/navigation_polygon.h2
-rw-r--r--scene/resources/packed_scene.h1
-rw-r--r--scene/resources/particle_process_material.cpp1
-rw-r--r--scene/resources/placeholder_textures.cpp177
-rw-r--r--scene/resources/placeholder_textures.h130
-rw-r--r--scene/resources/portable_compressed_texture.cpp339
-rw-r--r--scene/resources/portable_compressed_texture.h110
-rw-r--r--scene/resources/primitive_meshes.cpp13
-rw-r--r--scene/resources/resource_format_text.cpp22
-rw-r--r--scene/resources/resource_format_text.h2
-rw-r--r--scene/resources/separation_ray_shape_3d.cpp6
-rw-r--r--scene/resources/shader.cpp33
-rw-r--r--scene/resources/shader_include.cpp4
-rw-r--r--scene/resources/sphere_shape_3d.cpp2
-rw-r--r--scene/resources/style_box.cpp924
-rw-r--r--scene/resources/style_box.h188
-rw-r--r--scene/resources/style_box_flat.cpp642
-rw-r--r--scene/resources/style_box_flat.h118
-rw-r--r--scene/resources/style_box_line.cpp132
-rw-r--r--scene/resources/style_box_line.h70
-rw-r--r--scene/resources/style_box_texture.cpp243
-rw-r--r--scene/resources/style_box_texture.h99
-rw-r--r--scene/resources/texture.cpp3292
-rw-r--r--scene/resources/texture.h949
-rw-r--r--scene/resources/texture_rd.cpp346
-rw-r--r--scene/resources/texture_rd.h153
-rw-r--r--scene/resources/theme.cpp34
-rw-r--r--scene/resources/tile_set.cpp45
-rw-r--r--scene/resources/tile_set.h14
-rw-r--r--scene/resources/visual_shader.cpp27
-rw-r--r--scene/resources/visual_shader.h3
-rw-r--r--scene/resources/visual_shader_nodes.cpp236
-rw-r--r--scene/resources/visual_shader_nodes.h70
-rw-r--r--scene/resources/visual_shader_particle_nodes.cpp16
-rw-r--r--scene/resources/visual_shader_particle_nodes.h2
-rw-r--r--scene/resources/world_3d.cpp1
-rw-r--r--scene/resources/world_boundary_shape_3d.cpp2
-rw-r--r--scene/scene_string_names.cpp3
-rw-r--r--scene/scene_string_names.h3
-rw-r--r--servers/display_server.cpp28
-rw-r--r--servers/display_server.h13
-rw-r--r--servers/navigation_server_2d.cpp8
-rw-r--r--servers/navigation_server_2d.h6
-rw-r--r--servers/navigation_server_3d.cpp13
-rw-r--r--servers/navigation_server_3d.h8
-rw-r--r--servers/navigation_server_3d_dummy.h6
-rw-r--r--servers/register_server_types.cpp7
-rw-r--r--servers/rendering/dummy/storage/texture_storage.h3
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp4
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.h2
-rw-r--r--servers/rendering/renderer_rd/effects/debug_effects.cpp328
-rw-r--r--servers/rendering/renderer_rd/effects/debug_effects.h85
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.cpp3
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp28
-rw-r--r--servers/rendering/renderer_rd/environment/fog.h2
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp242
-rw-r--r--servers/rendering/renderer_rd/environment/sky.h3
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp150
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h13
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp3
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp66
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h11
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp3
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp28
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp51
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h4
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl15
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl41
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sky.glsl29
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl15
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl76
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl15
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl42
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl15
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl37
-rw-r--r--servers/rendering/renderer_rd/shaders/samplers_inc.glsl12
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl12
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl14
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp20
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.h2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp42
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp125
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h91
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp436
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h24
-rw-r--r--servers/rendering/renderer_scene_cull.cpp5
-rw-r--r--servers/rendering/renderer_viewport.cpp14
-rw-r--r--servers/rendering/rendering_device.cpp13
-rw-r--r--servers/rendering/rendering_device.h13
-rw-r--r--servers/rendering/rendering_device_binds.h3
-rw-r--r--servers/rendering/rendering_server_default.cpp12
-rw-r--r--servers/rendering/rendering_server_default.h35
-rw-r--r--servers/rendering/shader_compiler.cpp20
-rw-r--r--servers/rendering/shader_compiler.h1
-rw-r--r--servers/rendering/shader_language.cpp56
-rw-r--r--servers/rendering/storage/render_scene_buffers.cpp57
-rw-r--r--servers/rendering/storage/render_scene_buffers.h92
-rw-r--r--servers/rendering/storage/texture_storage.h3
-rw-r--r--servers/rendering_server.cpp21
-rw-r--r--servers/rendering_server.h3
-rw-r--r--servers/text_server.cpp4
-rw-r--r--tests/core/input/test_input_event.h115
-rw-r--r--tests/core/io/test_image.h80
-rw-r--r--tests/core/io/test_json.h84
-rw-r--r--tests/core/io/test_resource.h52
-rw-r--r--tests/core/object/test_object.h23
-rw-r--r--tests/core/string/test_string.h2
-rw-r--r--tests/core/variant/test_array.h26
-rw-r--r--tests/scene/test_theme.h2
-rw-r--r--tests/scene/test_viewport.h41
-rw-r--r--tests/servers/test_navigation_server_3d.h481
-rw-r--r--tests/test_main.cpp1
-rw-r--r--thirdparty/README.md28
-rw-r--r--thirdparty/enet/enet/enet.h16
-rw-r--r--thirdparty/enet/godot.cpp4
-rw-r--r--thirdparty/enet/host.c16
-rw-r--r--thirdparty/enet/packet.c77
-rw-r--r--thirdparty/enet/peer.c84
-rw-r--r--thirdparty/enet/protocol.c210
-rw-r--r--thirdparty/freetype/include/freetype/config/ftoption.h47
-rw-r--r--thirdparty/freetype/include/freetype/config/ftstdlib.h14
-rw-r--r--thirdparty/freetype/include/freetype/freetype.h563
-rw-r--r--thirdparty/freetype/include/freetype/ftcache.h88
-rw-r--r--thirdparty/freetype/include/freetype/ftchapters.h23
-rw-r--r--thirdparty/freetype/include/freetype/ftdriver.h11
-rw-r--r--thirdparty/freetype/include/freetype/ftimage.h10
-rw-r--r--thirdparty/freetype/include/freetype/ftlogging.h2
-rw-r--r--thirdparty/freetype/include/freetype/ftmm.h57
-rw-r--r--thirdparty/freetype/include/freetype/ftoutln.h2
-rw-r--r--thirdparty/freetype/include/freetype/ftrender.h2
-rw-r--r--thirdparty/freetype/include/freetype/ftsynth.h12
-rw-r--r--thirdparty/freetype/include/freetype/ftsystem.h16
-rw-r--r--thirdparty/freetype/include/freetype/internal/compiler-macros.h7
-rw-r--r--thirdparty/freetype/include/freetype/internal/ftdrv.h1
-rw-r--r--thirdparty/freetype/include/freetype/internal/ftmmtypes.h20
-rw-r--r--thirdparty/freetype/include/freetype/internal/services/svmetric.h10
-rw-r--r--thirdparty/freetype/include/freetype/internal/services/svmm.h109
-rw-r--r--thirdparty/freetype/include/freetype/internal/services/svpscmap.h2
-rw-r--r--thirdparty/freetype/include/freetype/internal/t1types.h26
-rw-r--r--thirdparty/freetype/include/freetype/internal/tttypes.h122
-rw-r--r--thirdparty/freetype/src/autofit/afcjk.c56
-rw-r--r--thirdparty/freetype/src/autofit/afcjk.h20
-rw-r--r--thirdparty/freetype/src/autofit/afglobal.c5
-rw-r--r--thirdparty/freetype/src/autofit/afglobal.h2
-rw-r--r--thirdparty/freetype/src/autofit/afhints.c58
-rw-r--r--thirdparty/freetype/src/autofit/afindic.c32
-rw-r--r--thirdparty/freetype/src/autofit/aflatin.c49
-rw-r--r--thirdparty/freetype/src/autofit/aflatin.h4
-rw-r--r--thirdparty/freetype/src/autofit/afloader.c6
-rw-r--r--thirdparty/freetype/src/autofit/afmodule.c37
-rw-r--r--thirdparty/freetype/src/autofit/afshaper.c6
-rw-r--r--thirdparty/freetype/src/autofit/ft-hb.c2
-rw-r--r--thirdparty/freetype/src/base/ftbbox.c42
-rw-r--r--thirdparty/freetype/src/base/ftcalc.c4
-rw-r--r--thirdparty/freetype/src/base/ftdbgmem.c2
-rw-r--r--thirdparty/freetype/src/base/ftmac.c2
-rw-r--r--thirdparty/freetype/src/base/ftmm.c146
-rw-r--r--thirdparty/freetype/src/base/ftobjs.c23
-rw-r--r--thirdparty/freetype/src/base/ftoutln.c52
-rw-r--r--thirdparty/freetype/src/base/ftstroke.c21
-rw-r--r--thirdparty/freetype/src/base/ftsynth.c20
-rw-r--r--thirdparty/freetype/src/base/ftsystem.c9
-rw-r--r--thirdparty/freetype/src/bdf/bdf.h4
-rw-r--r--thirdparty/freetype/src/bdf/bdfdrivr.c116
-rw-r--r--thirdparty/freetype/src/bdf/bdflib.c67
-rw-r--r--thirdparty/freetype/src/bzip2/ftbzip2.c19
-rw-r--r--thirdparty/freetype/src/cache/ftcbasic.c8
-rw-r--r--thirdparty/freetype/src/cache/ftccache.c125
-rw-r--r--thirdparty/freetype/src/cache/ftccache.h17
-rw-r--r--thirdparty/freetype/src/cache/ftcglyph.c46
-rw-r--r--thirdparty/freetype/src/cache/ftcglyph.h15
-rw-r--r--thirdparty/freetype/src/cache/ftcmanag.c42
-rw-r--r--thirdparty/freetype/src/cache/ftcmru.c28
-rw-r--r--thirdparty/freetype/src/cache/ftcsbits.c17
-rw-r--r--thirdparty/freetype/src/cache/ftcsbits.h11
-rw-r--r--thirdparty/freetype/src/cff/cffcmap.c107
-rw-r--r--thirdparty/freetype/src/cff/cffdrivr.c443
-rw-r--r--thirdparty/freetype/src/cff/cffgload.c6
-rw-r--r--thirdparty/freetype/src/cff/cffload.c31
-rw-r--r--thirdparty/freetype/src/cff/cffload.h4
-rw-r--r--thirdparty/freetype/src/cff/cffobjs.c24
-rw-r--r--thirdparty/freetype/src/cff/cffparse.c228
-rw-r--r--thirdparty/freetype/src/cff/cffparse.h9
-rw-r--r--thirdparty/freetype/src/cid/cidgload.c141
-rw-r--r--thirdparty/freetype/src/cid/cidgload.h8
-rw-r--r--thirdparty/freetype/src/cid/cidload.c51
-rw-r--r--thirdparty/freetype/src/cid/cidobjs.c14
-rw-r--r--thirdparty/freetype/src/cid/cidparse.c16
-rw-r--r--thirdparty/freetype/src/cid/cidriver.c97
-rw-r--r--thirdparty/freetype/src/gxvalid/gxvfgen.c3
-rw-r--r--thirdparty/freetype/src/gzip/ftgzip.c5
-rw-r--r--thirdparty/freetype/src/gzip/infback.c644
-rw-r--r--thirdparty/freetype/src/pcf/pcfdrivr.c122
-rw-r--r--thirdparty/freetype/src/pfr/pfrcmap.c48
-rw-r--r--thirdparty/freetype/src/pfr/pfrdrivr.c26
-rw-r--r--thirdparty/freetype/src/pfr/pfrgload.c3
-rw-r--r--thirdparty/freetype/src/pfr/pfrload.c60
-rw-r--r--thirdparty/freetype/src/pfr/pfrobjs.c6
-rw-r--r--thirdparty/freetype/src/psaux/afmparse.c2
-rw-r--r--thirdparty/freetype/src/psaux/t1cmap.c141
-rw-r--r--thirdparty/freetype/src/pshinter/pshalgo.c2
-rw-r--r--thirdparty/freetype/src/pshinter/pshmod.c9
-rw-r--r--thirdparty/freetype/src/pshinter/pshrec.c63
-rw-r--r--thirdparty/freetype/src/psnames/psmodule.c42
-rw-r--r--thirdparty/freetype/src/raster/ftraster.c44
-rw-r--r--thirdparty/freetype/src/raster/ftrend1.c21
-rw-r--r--thirdparty/freetype/src/sdf/ftbsdf.c7
-rw-r--r--thirdparty/freetype/src/sdf/ftsdf.c21
-rw-r--r--thirdparty/freetype/src/sdf/ftsdfrend.c35
-rw-r--r--thirdparty/freetype/src/sfnt/pngshim.c7
-rw-r--r--thirdparty/freetype/src/sfnt/sfdriver.c143
-rw-r--r--thirdparty/freetype/src/sfnt/sfobjs.c30
-rw-r--r--thirdparty/freetype/src/sfnt/sfwoff.c2
-rw-r--r--thirdparty/freetype/src/sfnt/sfwoff2.c2
-rw-r--r--thirdparty/freetype/src/sfnt/ttbdf.c13
-rw-r--r--thirdparty/freetype/src/sfnt/ttbdf.h2
-rw-r--r--thirdparty/freetype/src/sfnt/ttcmap.c547
-rw-r--r--thirdparty/freetype/src/sfnt/ttcolr.c6
-rw-r--r--thirdparty/freetype/src/sfnt/ttcpal.c2
-rw-r--r--thirdparty/freetype/src/sfnt/ttload.c7
-rw-r--r--thirdparty/freetype/src/sfnt/ttmtx.c2
-rw-r--r--thirdparty/freetype/src/sfnt/ttpost.c284
-rw-r--r--thirdparty/freetype/src/sfnt/ttsbit.c2
-rw-r--r--thirdparty/freetype/src/sfnt/ttsvg.c2
-rw-r--r--thirdparty/freetype/src/sfnt/woff2tags.c2
-rw-r--r--thirdparty/freetype/src/smooth/ftgrays.c49
-rw-r--r--thirdparty/freetype/src/smooth/ftsmooth.c22
-rw-r--r--thirdparty/freetype/src/svg/ftsvg.c45
-rw-r--r--thirdparty/freetype/src/truetype/ttdriver.c158
-rw-r--r--thirdparty/freetype/src/truetype/ttgload.c270
-rw-r--r--thirdparty/freetype/src/truetype/ttgxvar.c518
-rw-r--r--thirdparty/freetype/src/truetype/ttgxvar.h40
-rw-r--r--thirdparty/freetype/src/truetype/ttinterp.c145
-rw-r--r--thirdparty/freetype/src/truetype/ttinterp.h10
-rw-r--r--thirdparty/freetype/src/truetype/ttobjs.c85
-rw-r--r--thirdparty/freetype/src/truetype/ttobjs.h6
-rw-r--r--thirdparty/freetype/src/truetype/ttpload.c37
-rw-r--r--thirdparty/freetype/src/truetype/ttpload.h6
-rw-r--r--thirdparty/freetype/src/truetype/ttsubpix.c2
-rw-r--r--thirdparty/freetype/src/type1/t1afm.c4
-rw-r--r--thirdparty/freetype/src/type1/t1driver.c93
-rw-r--r--thirdparty/freetype/src/type1/t1load.c256
-rw-r--r--thirdparty/freetype/src/type1/t1load.h22
-rw-r--r--thirdparty/freetype/src/type1/t1objs.c8
-rw-r--r--thirdparty/freetype/src/type42/t42drivr.c43
-rw-r--r--thirdparty/freetype/src/type42/t42parse.c92
-rw-r--r--thirdparty/freetype/src/winfonts/winfnt.c40
-rw-r--r--thirdparty/harfbuzz/src/OT/Color/CBDT/CBDT.hh11
-rw-r--r--thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh4
-rw-r--r--thirdparty/harfbuzz/src/OT/Color/sbix/sbix.hh5
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh3
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh3
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh9
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh15
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh1
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh11
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh5
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh3
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh3
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh64
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh3
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh1
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh41
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/Glyph.hh40
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh12
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh4
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/coord-setter.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh67
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/glyf.hh82
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/path-builder.hh23
-rw-r--r--thirdparty/harfbuzz/src/OT/name/name.hh19
-rw-r--r--thirdparty/harfbuzz/src/graph/classdef-graph.hh8
-rw-r--r--thirdparty/harfbuzz/src/graph/coverage-graph.hh8
-rw-r--r--thirdparty/harfbuzz/src/graph/graph.hh7
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-context.cc6
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-context.hh4
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh12
-rw-r--r--thirdparty/harfbuzz/src/graph/pairpos-graph.hh10
-rw-r--r--thirdparty/harfbuzz/src/graph/serialize.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-algs.hh183
-rw-r--r--thirdparty/harfbuzz/src/hb-array.hh70
-rw-r--r--thirdparty/harfbuzz/src/hb-atomic.hh1
-rw-r--r--thirdparty/harfbuzz/src/hb-bimap.hh74
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-page.hh5
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-set-invertible.hh7
-rw-r--r--thirdparty/harfbuzz/src/hb-bit-set.hh9
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-verify.cc76
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.hh7
-rw-r--r--thirdparty/harfbuzz/src/hb-cache.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-cairo-utils.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-cairo.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-cff-interp-common.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-common.h10
-rw-r--r--thirdparty/harfbuzz/src/hb-config.hh1
-rw-r--r--thirdparty/harfbuzz/src/hb-debug.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-deprecated.h46
-rw-r--r--thirdparty/harfbuzz/src/hb-draw.hh30
-rw-r--r--thirdparty/harfbuzz/src/hb-font.cc7
-rw-r--r--thirdparty/harfbuzz/src/hb-font.h45
-rw-r--r--thirdparty/harfbuzz/src/hb-ft.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-gobject-structs.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-graphite2.cc42
-rw-r--r--thirdparty/harfbuzz/src/hb-iter.hh9
-rw-r--r--thirdparty/harfbuzz/src/hb-kern.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-limits.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-machinery.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-map.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-map.hh174
-rw-r--r--thirdparty/harfbuzz/src/hb-meta.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-multimap.hh34
-rw-r--r--thirdparty/harfbuzz/src/hb-null.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-open-file.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-open-type.hh63
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff-common.hh271
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.cc6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.hh286
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff2-table.hh33
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cmap-table.hh38
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-font.cc14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-hdmx-table.hh43
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh77
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh21
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-common.hh137
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh180
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.cc195
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.h30
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-map.cc8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-map.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-math-table.hh13
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-os2-table.hh7
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-post-table.hh5
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.cc7
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc12
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use.cc3
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-stat-table.hh53
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-common.hh942
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-cvar-table.hh69
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh82
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh123
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh59
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-vorg-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-pool.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-sanitize.hh97
-rw-r--r--thirdparty/harfbuzz/src/hb-serialize.hh34
-rw-r--r--thirdparty/harfbuzz/src/hb-set-digest.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-set.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-set.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-shape.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-shaper-list.hh5
-rw-r--r--thirdparty/harfbuzz/src/hb-static.cc3
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-accelerator.hh51
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff-common.cc29
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff-common.hh110
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff1.cc298
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-cff2.cc93
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-input.cc49
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-input.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-instancer-solver.cc175
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-instancer-solver.hh90
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan-member-list.hh16
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.cc177
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.hh77
-rw-r--r--thirdparty/harfbuzz/src/hb-subset.cc144
-rw-r--r--thirdparty/harfbuzz/src/hb-subset.h7
-rw-r--r--thirdparty/harfbuzz/src/hb-vector.hh122
-rw-r--r--thirdparty/harfbuzz/src/hb-version.h6
-rw-r--r--thirdparty/harfbuzz/src/hb.hh8
-rw-r--r--thirdparty/icu4c/common/unicode/ures.h9
-rw-r--r--thirdparty/icu4c/common/unicode/uvernum.h6
-rw-r--r--thirdparty/icu4c/icudt73l.datbin4624736 -> 4624768 bytes
-rw-r--r--thirdparty/minizip/patches/empty-zip-fix.patch193
-rw-r--r--thirdparty/minizip/unzip.c92
-rw-r--r--thirdparty/openxr/COPYING.adoc2
-rw-r--r--thirdparty/openxr/include/openxr/openxr.h1399
-rw-r--r--thirdparty/openxr/include/openxr/openxr_platform.h32
-rw-r--r--thirdparty/openxr/include/openxr/openxr_platform_defines.h8
-rw-r--r--thirdparty/openxr/include/openxr/openxr_reflection.h996
-rw-r--r--thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h6
-rw-r--r--thirdparty/openxr/include/openxr/openxr_reflection_structs.h76
-rw-r--r--thirdparty/openxr/patches/fix-gcc13-stdint.patch12
-rw-r--r--thirdparty/openxr/src/.clang-format10
-rw-r--r--thirdparty/openxr/src/common/extra_algorithms.h2
-rw-r--r--thirdparty/openxr/src/common/filesystem_utils.cpp2
-rw-r--r--thirdparty/openxr/src/common/filesystem_utils.hpp2
-rw-r--r--thirdparty/openxr/src/common/hex_and_handles.h2
-rw-r--r--thirdparty/openxr/src/common/loader_interfaces.h2
-rw-r--r--thirdparty/openxr/src/common/object_info.cpp6
-rw-r--r--thirdparty/openxr/src/common/object_info.h2
-rw-r--r--thirdparty/openxr/src/common/platform_utils.hpp43
-rw-r--r--thirdparty/openxr/src/common/stdfs_conditions.h2
-rw-r--r--thirdparty/openxr/src/common/unique_asset.h2
-rw-r--r--thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp63
-rw-r--r--thirdparty/openxr/src/common/xr_dependencies.h32
-rw-r--r--thirdparty/openxr/src/common/xr_linear.h122
-rw-r--r--thirdparty/openxr/src/loader/android_utilities.cpp10
-rw-r--r--thirdparty/openxr/src/loader/android_utilities.h2
-rw-r--r--thirdparty/openxr/src/loader/api_layer_interface.cpp16
-rw-r--r--thirdparty/openxr/src/loader/api_layer_interface.hpp2
-rw-r--r--thirdparty/openxr/src/loader/exception_handling.hpp2
-rw-r--r--thirdparty/openxr/src/loader/loader_core.cpp2
-rw-r--r--thirdparty/openxr/src/loader/loader_instance.cpp6
-rw-r--r--thirdparty/openxr/src/loader/loader_instance.hpp2
-rw-r--r--thirdparty/openxr/src/loader/loader_logger.cpp5
-rw-r--r--thirdparty/openxr/src/loader/loader_logger.hpp2
-rw-r--r--thirdparty/openxr/src/loader/loader_logger_recorders.cpp12
-rw-r--r--thirdparty/openxr/src/loader/loader_logger_recorders.hpp2
-rw-r--r--thirdparty/openxr/src/loader/loader_platform.hpp2
-rw-r--r--thirdparty/openxr/src/loader/manifest_file.cpp15
-rw-r--r--thirdparty/openxr/src/loader/manifest_file.hpp2
-rw-r--r--thirdparty/openxr/src/loader/runtime_interface.cpp10
-rw-r--r--thirdparty/openxr/src/loader/runtime_interface.hpp2
-rw-r--r--thirdparty/openxr/src/loader/xr_generated_loader.cpp4
-rw-r--r--thirdparty/openxr/src/loader/xr_generated_loader.hpp4
-rw-r--r--thirdparty/openxr/src/xr_generated_dispatch_table.c81
-rw-r--r--thirdparty/openxr/src/xr_generated_dispatch_table.h80
-rw-r--r--thirdparty/rvo2/rvo2_2d/Agent2d.cc693
-rw-r--r--thirdparty/rvo2/rvo2_2d/Agent2d.cpp594
-rw-r--r--thirdparty/rvo2/rvo2_2d/Agent2d.h219
-rw-r--r--thirdparty/rvo2/rvo2_2d/Definitions.h110
-rw-r--r--thirdparty/rvo2/rvo2_2d/KdTree2d.cc517
-rw-r--r--thirdparty/rvo2/rvo2_2d/KdTree2d.cpp357
-rw-r--r--thirdparty/rvo2/rvo2_2d/KdTree2d.h314
-rw-r--r--thirdparty/rvo2/rvo2_2d/Line.h67
-rw-r--r--thirdparty/rvo2/rvo2_2d/Obstacle2d.cc46
-rw-r--r--thirdparty/rvo2/rvo2_2d/Obstacle2d.cpp (renamed from thirdparty/rvo2/rvo2_2d/Line.cc)21
-rw-r--r--thirdparty/rvo2/rvo2_2d/Obstacle2d.h72
-rw-r--r--thirdparty/rvo2/rvo2_2d/RVOSimulator2d.cc371
-rw-r--r--thirdparty/rvo2/rvo2_2d/RVOSimulator2d.cpp363
-rw-r--r--thirdparty/rvo2/rvo2_2d/RVOSimulator2d.h1175
-rw-r--r--thirdparty/rvo2/rvo2_2d/Vector2.cc136
-rw-r--r--thirdparty/rvo2/rvo2_2d/Vector2.h525
-rw-r--r--thirdparty/rvo2/rvo2_3d/Agent3d.cc474
-rw-r--r--thirdparty/rvo2/rvo2_3d/Agent3d.cpp449
-rw-r--r--thirdparty/rvo2/rvo2_3d/Agent3d.h148
-rw-r--r--thirdparty/rvo2/rvo2_3d/Definitions.h (renamed from thirdparty/rvo2/rvo2_3d/Plane.cc)27
-rw-r--r--thirdparty/rvo2/rvo2_3d/KdTree3d.cc264
-rw-r--r--thirdparty/rvo2/rvo2_3d/KdTree3d.cpp161
-rw-r--r--thirdparty/rvo2/rvo2_3d/KdTree3d.h161
-rw-r--r--thirdparty/rvo2/rvo2_3d/Plane.h67
-rw-r--r--thirdparty/rvo2/rvo2_3d/RVOSimulator3d.cc250
-rw-r--r--thirdparty/rvo2/rvo2_3d/RVOSimulator3d.cpp274
-rw-r--r--thirdparty/rvo2/rvo2_3d/RVOSimulator3d.h662
-rw-r--r--thirdparty/rvo2/rvo2_3d/Vector3.cc170
-rw-r--r--thirdparty/rvo2/rvo2_3d/Vector3.h593
-rw-r--r--version.py4
2019 files changed, 59082 insertions, 27435 deletions
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 6133780688..b47ef135a2 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -86,6 +86,7 @@ jobs:
- name: Documentation checks
run: |
+ doc/tools/doc_status.py doc/classes modules/*/doc_classes platform/*/doc_classes
doc/tools/make_rst.py --dry-run --color doc/classes modules platform
- name: Style checks via clang-format (clang_format.sh)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f795394ad..735cca7212 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,441 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## [4.1] - 2023-07-06
+
+See the [release announcement](https://godotengine.org/article/godot-4-1-is-here) for details.
+
+### Added
+
+#### 2D
+
+- Add "Center View" button to 2D editor ([GH-57252](https://github.com/godotengine/godot/pull/57252)).
+- Add proper snapping to tile polygon editor ([GH-70488](https://github.com/godotengine/godot/pull/70488)).
+
+#### 3D
+
+- Add the ability to look-at in model-space ([GH-76082](https://github.com/godotengine/godot/pull/76082)).
+- Add move control points button to Path3D Editor ([GH-77860](https://github.com/godotengine/godot/pull/77860)).
+
+#### Animation
+
+- Implement `AnimationNodeSub2` and allow less or greater value in mathematical `AnimationNode` ([GH-76616](https://github.com/godotengine/godot/pull/76616)).
+- Add `TRANS_SPRING` mode to `Tween` ([GH-76899](https://github.com/godotengine/godot/pull/76899)).
+
+#### Buildsystem
+
+- Add support for single compilation unit builds ([GH-77170](https://github.com/godotengine/godot/pull/77170)).
+
+#### C#/.NET
+
+- Add fine-grained disabling of SourceGenerators ([GH-71049](https://github.com/godotengine/godot/pull/71049)).
+- Add global class support ([GH-72619](https://github.com/godotengine/godot/pull/72619)).
+- Add `[Obsolete]` attribute to deprecated members ([GH-77904](https://github.com/godotengine/godot/pull/77904)).
+- Add version defines to help users deal with breaking changes ([GH-78249](https://github.com/godotengine/godot/pull/78249), [GH-78466](https://github.com/godotengine/godot/pull/78466)).
+- Add compatibility overloads ([GH-78452](https://github.com/godotengine/godot/pull/78452)).
+
+#### Core
+
+- Add frame delta smoothing option ([GH-52314](https://github.com/godotengine/godot/pull/52314)).
+- Refactor Node processing to allow Scene multi-threading ([GH-75901](https://github.com/godotengine/godot/pull/75901)).
+- Add a square fill mode to GradientTexture2D ([GH-76151](https://github.com/godotengine/godot/pull/76151)).
+- Expose `ProjectSettings.set_as_basic()` to scripting ([GH-77417](https://github.com/godotengine/godot/pull/77417)).
+- Expose `ProjectSettings.set_as_internal()` to scripting ([GH-77668](https://github.com/godotengine/godot/pull/77668)).
+- Let user scripts disable thread safety checks ([GH-78000](https://github.com/godotengine/godot/pull/78000)).
+
+#### Editor
+
+- Add editor setting for spin slider sensibility ([GH-50671](https://github.com/godotengine/godot/pull/50671)).
+- Add multi-window code and shader editors ([GH-62378](https://github.com/godotengine/godot/pull/62378)).
+- Improve editor state persistence ([GH-72277](https://github.com/godotengine/godot/pull/72277)).
+- Properly remember snapping options per-project ([GH-74682](https://github.com/godotengine/godot/pull/74682)).
+- Add project tags ([GH-75047](https://github.com/godotengine/godot/pull/75047)).
+- Improve editor state initialization ([GH-75563](https://github.com/godotengine/godot/pull/75563)).
+- Android: Add the `scale_gizmo_handles` editor setting for touchscreens ([GH-75718](https://github.com/godotengine/godot/pull/75718)).
+- Make create folder popup support nested folders ([GH-76084](https://github.com/godotengine/godot/pull/76084)).
+- Display enum value descriptions in the editor inspector help tooltips ([GH-76238](https://github.com/godotengine/godot/pull/76238)).
+- Add indicator for `StringName` properties ([GH-77521](https://github.com/godotengine/godot/pull/77521)).
+- Add relative path support for `EditorPlugin.add_autoload_singleton` ([GH-78109](https://github.com/godotengine/godot/pull/78109)).
+
+#### Export
+
+- Allow EditorExportPlugins to provide export options ([GH-72895](https://github.com/godotengine/godot/pull/72895)).
+- Add readable descriptions and validation warnings to the export options ([GH-74644](https://github.com/godotengine/godot/pull/74644)).
+
+#### GDExtension
+
+- Improve editor support for icons of custom, scripted, and GDExtension classes ([GH-75472](https://github.com/godotengine/godot/pull/75472)).
+- Add a backwards compatibility system for GDExtension ([GH-76446](https://github.com/godotengine/godot/pull/76446)).
+- Allow GDExtensions to add editor plugins ([GH-77010](https://github.com/godotengine/godot/pull/77010)).
+- Add GDExtension `@since` attribute ([GH-78518](https://github.com/godotengine/godot/pull/78518)).
+
+#### GDScript
+
+- Allow to reference a class constructor as a `Callable` ([GH-73657](https://github.com/godotengine/godot/pull/73657)).
+- Allow boolean operators for all Variant types ([GH-74741](https://github.com/godotengine/godot/pull/74741)).
+- Add support for static variables in GDScript ([GH-76264](https://github.com/godotengine/godot/pull/76264)).
+
+#### GUI
+
+- Add support for multiline cells to `Tree` ([GH-61714](https://github.com/godotengine/godot/pull/61714)).
+- Expose horizontal/vertical `custom_step` as editor property for the `ScrollContainer` ([GH-70868](https://github.com/godotengine/godot/pull/70868)).
+- Implement `screen_get_pixel` method for LinuxBSD/X11, macOS and Windows ([GH-74087](https://github.com/godotengine/godot/pull/74087)).
+- Implement vertical icon alignment for buttons ([GH-74369](https://github.com/godotengine/godot/pull/74369)).
+- Expose all auto-wrap modes in `TextEdit` ([GH-74813](https://github.com/godotengine/godot/pull/74813)).
+- Expose `TextServer` justification flags to `Label`, `Label3D`, `TextMesh`, and `RichTextLabel` ([GH-75250](https://github.com/godotengine/godot/pull/75250)).
+- Expose dialog parent-and-popup logic to the API ([GH-76025](https://github.com/godotengine/godot/pull/76025)).
+- Add support for tab stops to `Label` ([GH-76129](https://github.com/godotengine/godot/pull/76129)).
+- Add support for tab stops to `RichTextLabel` ([GH-76401](https://github.com/godotengine/godot/pull/76401)).
+- Expose `Window.get_window_id()` ([GH-77288](https://github.com/godotengine/godot/pull/77288)).
+- Implement `TreeItem.add_child` ([GH-77446](https://github.com/godotengine/godot/pull/77446)).
+- Add method to check if native window is focused ([GH-78262](https://github.com/godotengine/godot/pull/78262)).
+
+#### Import
+
+- Expose more compression formats in Image and fix compress check ([GH-76014](https://github.com/godotengine/godot/pull/76014)).
+- Add support for extending GLTF with more texture formats and support WebP ([GH-76895](https://github.com/godotengine/godot/pull/76895)).
+- Add support for non-standard OBJ vertex entries ([GH-77042](https://github.com/godotengine/godot/pull/77042)).
+
+#### Input
+
+- Detect host OS and use macOS keys on Mac hosts on Web ([GH-75451](https://github.com/godotengine/godot/pull/75451)).
+
+#### Navigation
+
+- Expose NavigationAgent path postprocessing and pathfinding algorithm options ([GH-75326](https://github.com/godotengine/godot/pull/75326)).
+- Add agent pause mode to `NavigationServer` ([GH-75888](https://github.com/godotengine/godot/pull/75888)).
+- Add NavigationPolygon `cell_size` property ([GH-78172](https://github.com/godotengine/godot/pull/78172)).
+
+#### Networking
+
+- Implement "watched" properties (reliable/on change) ([GH-75467](https://github.com/godotengine/godot/pull/75467)).
+- Add support for platform-specific CA bundles ([GH-76836](https://github.com/godotengine/godot/pull/76836)).
+
+#### Porting
+
+- Implement and expose `OS.shell_show_in_file_manager()` ([GH-69698](https://github.com/godotengine/godot/pull/69698), [GH-76428](https://github.com/godotengine/godot/pull/76428)).
+- Add `audio/general/text_to_speech` project setting to enable/disable TTS ([GH-77132](https://github.com/godotengine/godot/pull/77132)).
+- Android: Allow concurrent buffering and dispatch of input events ([GH-76399](https://github.com/godotengine/godot/pull/76399)).
+- Android: Add editor setting to control the window used to run the project ([GH-77676](https://github.com/godotengine/godot/pull/77676)).
+- Android: Allow exporting release builds without a debug keystore ([GH-78123](https://github.com/godotengine/godot/pull/78123)).
+- Linux/BSD: Add a default error handler for X11 to avoid crashes ([GH-75099](https://github.com/godotengine/godot/pull/75099)).
+
+#### Rendering
+
+- Add shader cache to GLES3 ([GH-76092](https://github.com/godotengine/godot/pull/76092)).
+- Implement Vulkan pipeline caching ([GH-76348](https://github.com/godotengine/godot/pull/76348)).
+- Add NoiseTexture3D ([GH-76486](https://github.com/godotengine/godot/pull/76486)).
+
+#### Shaders
+
+- Add `EXPOSURE` built-in to spatial shaders ([GH-71364](https://github.com/godotengine/godot/pull/71364)).
+- Add `LIGHT_IS_DIRECTIONAL` built-in for spatial shaders ([GH-76290](https://github.com/godotengine/godot/pull/76290)).
+
+#### XR
+
+- Add support for getting and setting display refresh rate in WebXR ([GH-72938](https://github.com/godotengine/godot/pull/72938)).
+
+### Changed
+
+#### 2D
+
+- Improve the `Gradient2D` editor ([GH-70940](https://github.com/godotengine/godot/pull/70940)).
+- Overhaul the `Curve` editor ([GH-74959](https://github.com/godotengine/godot/pull/74959)).
+- Draw materials in tile atlas view ([GH-77909](https://github.com/godotengine/godot/pull/77909)).
+
+#### Animation
+
+- Improve SpriteFrameEditor frame addition ordering ([GH-68091](https://github.com/godotengine/godot/pull/68091)).
+
+#### Buildsystem
+
+- SCons: Move platform logo/run icon to `export` folder ([GH-78435](https://github.com/godotengine/godot/pull/78435)).
+
+#### C#/.NET
+
+- Make include scripts contents an export option ([GH-72896](https://github.com/godotengine/godot/pull/72896)).
+- Truncate instead of round in Vector2/3/4 to Vector2I/3I/4I conversion ([GH-75477](https://github.com/godotengine/godot/pull/75477)).
+
+#### Core
+
+- The strings returned by `ResourceLoader::get_dependencies()` now include paths in addition to UIDs ([GH-73131](https://github.com/godotengine/godot/pull/73131)).
+- Optimize Node children management ([GH-75627](https://github.com/godotengine/godot/pull/75627)).
+- Deprecate `NOTIFICATION_MOVED_IN_PARENT` for `NOTIFICATION_CHILD_ORDER_CHANGED` ([GH-75701](https://github.com/godotengine/godot/pull/75701)).
+- Optimize `Node::add_child` validation ([GH-75760](https://github.com/godotengine/godot/pull/75760)).
+- Replace invalid characters in node names by underscores instead of removing them ([GH-75760](https://github.com/godotengine/godot/pull/75760)).
+- Optimize `Object::get_class_name` ([GH-75797](https://github.com/godotengine/godot/pull/75797)).
+- Ensure `RID`, `Callable`, and `Signal` are stored as strings ([GH-78517](https://github.com/godotengine/godot/pull/78517)).
+
+#### Editor
+
+- Remove constrained view in the 2D editor ([GH-47628](https://github.com/godotengine/godot/pull/47628)).
+- Enhance FileSystem dock tooltips ([GH-63263](https://github.com/godotengine/godot/pull/63263)).
+- Get rid of mouse wheel switch in scene tabs ([GH-70800](https://github.com/godotengine/godot/pull/70800)).
+- Reorganize context menu in FileSystem dock to put more used options higher ([GH-73519](https://github.com/godotengine/godot/pull/73519)).
+- Improve file move and copy operations ([GH-75330](https://github.com/godotengine/godot/pull/75330)).
+- Preserve scene unique names when saving branch as scene ([GH-76609](https://github.com/godotengine/godot/pull/76609)).
+- Allow showing messages from threads in "Editor Log" ([GH-77080](https://github.com/godotengine/godot/pull/77080)).
+
+#### Export
+
+- Store sensitive export options in dedicated credentials file ([GH-76165](https://github.com/godotengine/godot/pull/76165)).
+- Check if the required texture format is imported in the export dialog ([GH-78456](https://github.com/godotengine/godot/pull/78456)).
+
+#### GDExtension
+
+- Rework GDExtension interface from a struct to loading function pointers ([GH-76406](https://github.com/godotengine/godot/pull/76406)).
+- Standardize Object ptrcall encoding on `Object **` ([GH-77410](https://github.com/godotengine/godot/pull/77410)).
+
+#### GDScript
+
+- Improve GDScript documentation generation & behavior ([GH-72095](https://github.com/godotengine/godot/pull/72095)).
+- Sort code autocompletion with rules ([GH-75746](https://github.com/godotengine/godot/pull/75746)).
+- Allow `String`s and `StringName`s match each other in a `match` statement ([GH-78389](https://github.com/godotengine/godot/pull/78389)).
+
+#### GUI
+
+- Add a warning when accessing theme prematurely and fix surfaced issues ([GH-73475](https://github.com/godotengine/godot/pull/73475)).
+- Make main editor window border margin controllable by theme ([GH-74767](https://github.com/godotengine/godot/pull/74767)).
+- Make sure to normalize subtags when parsing BBCode ([GH-75622](https://github.com/godotengine/godot/pull/75622)).
+- Add an option for ButtonGroups to be unpressed ([GH-76279](https://github.com/godotengine/godot/pull/76279)).
+- Make `TextureButton` and `Button` update on texture change ([GH-77159](https://github.com/godotengine/godot/pull/77159)).
+- Use defined key mapping for closing popups and dialogs ([GH-77297](https://github.com/godotengine/godot/pull/77297)).
+
+#### Import
+
+- Split editor-specific import metadata for textures ([GH-75949](https://github.com/godotengine/godot/pull/75949)).
+- Use DXT1 when compressing PNGs with RGB format ([GH-76516](https://github.com/godotengine/godot/pull/76516)).
+- Respect `compress_binary_resources` editor setting on scene import ([GH-76630](https://github.com/godotengine/godot/pull/76630)).
+- Disable texture format import overrides by default ([GH-77105](https://github.com/godotengine/godot/pull/77105), [GH-78147](https://github.com/godotengine/godot/pull/78147)).
+- Ensure that "detect 3D" is only called when using 3D shaders ([GH-78199](https://github.com/godotengine/godot/pull/78199)).
+
+#### Input
+
+- Create a virtual mouse move event after moving child nodes in tree ([GH-66625](https://github.com/godotengine/godot/pull/66625)).
+- Propagate shortcut events to `SubViewport`s ([GH-76926](https://github.com/godotengine/godot/pull/76926)).
+- Improve touchpad and mouse support for the Android editor ([GH-77498](https://github.com/godotengine/godot/pull/77498)).
+- Generate missing values instead of disabling options ([GH-77900](https://github.com/godotengine/godot/pull/77900)).
+
+#### Navigation
+
+- Rework Navigation avoidance ([GH-69988](https://github.com/godotengine/godot/pull/69988)).
+- Make navigation mesh edge connections optional ([GH-75601](https://github.com/godotengine/godot/pull/75601)).
+- Prevent unnecessary navigation map synchronizations ([GH-75678](https://github.com/godotengine/godot/pull/75678)).
+- Update NavigationObstacle API ([GH-78081](https://github.com/godotengine/godot/pull/78081)).
+
+#### Networking
+
+- mbedTLS: Disable weak crypto and TLS versions ([GH-76905](https://github.com/godotengine/godot/pull/76905)).
+- Allow `ENetConnection` to send a packet to an arbitrary destination ([GH-77627](https://github.com/godotengine/godot/pull/77627)).
+
+#### Physics
+
+- Propagate previously unused `NOTIFICATION_WORLD_2D_CHANGED`, make CanvasItem/CollisionObject2D use it ([GH-57179](https://github.com/godotengine/godot/pull/57179)).
+
+#### Porting
+
+- Android: Downgrade android gradle plugin to version 7.2.1 ([GH-76325](https://github.com/godotengine/godot/pull/76325)).
+- macOS: Bump min. version to 10.13, and remove deprecated code ([GH-76394](https://github.com/godotengine/godot/pull/76394)).
+- Windows: Support long path in file access ([GH-76739](https://github.com/godotengine/godot/pull/76739)).
+
+#### Rendering
+
+- Disable NVIDIA's threaded OpenGL optimization on Windows ([GH-71472](https://github.com/godotengine/godot/pull/71472)).
+- Use `MODELVIEW_MATRIX` when on double precision ([GH-75462](https://github.com/godotengine/godot/pull/75462)).
+- Move sky luminance scaling to before fog is applied ([GH-75812](https://github.com/godotengine/godot/pull/75812)).
+- Clamp normal when calculating 2D lighting to avoid artifacts ([GH-76240](https://github.com/godotengine/godot/pull/76240)).
+- Rework particle turbulence ([GH-77154](https://github.com/godotengine/godot/pull/77154)).
+- (Re-)Implement `Light3D.shadow_reverse_cull_face` ([GH-77238](https://github.com/godotengine/godot/pull/77238)).
+- Take 3D resolution scaling into account for mesh LOD ([GH-77294](https://github.com/godotengine/godot/pull/77294)).
+
+#### Thirdparty
+
+- astcenc updated to version 4.4.0.
+- basis_universal updated to version 1.16.4.
+- brotli updated to version ed1995b6b.
+- doctest updated to version 2.4.11.
+- FreeType updated to version 2.13.0.
+- HarfBuzz updated to version 7.3.0.
+- ICU4C updated to version 73.1.
+- MbedTLS updated to version 2.28.3.
+- PCRE2 updated to version 10.42.
+- recast updated to version 1.6.0.
+- ThorVG updated to version 0.9.0.
+- tinyexr updated to version 1.0.5.
+- wslay updated to version 0e7d106ff.
+- Vulkan and related libraries updated to version 1.3.250.0.
+- zstd updated to version 1.5.5.
+- CA root certificates updated to 2023-06-02 bundle from Mozilla.
+
+### Removed
+
+#### C#/.NET
+
+- Discontinue `GodotNuGetFallbackFolder` ([GH-73984](https://github.com/godotengine/godot/pull/73984)).
+
+#### Input
+
+- Deprecate `push_unhandled_input` ([GH-77452](https://github.com/godotengine/godot/pull/77452)).
+
+### Fixed
+
+#### 2D
+
+- Fix click-selecting Sprites with repeated texture ([GH-78566](https://github.com/godotengine/godot/pull/78566)).
+- Tilemaps: Fix rendering odd-sized tiles ([GH-74814](https://github.com/godotengine/godot/pull/74814)).
+- Tilemaps: Fix tile resizing towards atlas boundary ([GH-76152](https://github.com/godotengine/godot/pull/76152)).
+- Tilemaps: Fix crashes when painting a large area in a tilemap ([GH-76548](https://github.com/godotengine/godot/pull/76548)).
+- Tilemaps: Fix TileMap draw preview when switching CanvasItem editor tool ([GH-78467](https://github.com/godotengine/godot/pull/78467)).
+- Tilemaps: Fix TileSet set as local to scene ([GH-78477](https://github.com/godotengine/godot/pull/78477)).
+- Tilemaps: Update indices after removing custom data layers ([GH-78492](https://github.com/godotengine/godot/pull/78492)).
+
+#### 3D
+
+- Fix `PathFollow` direction and add Z forward option ([GH-72842](https://github.com/godotengine/godot/pull/72842)).
+- Improve CSG robustness ([GH-74771](https://github.com/godotengine/godot/pull/74771)).
+- Fix 3D viewport front/rear axis and "Focus" button ([GH-76052](https://github.com/godotengine/godot/pull/76052)).
+- Fix infinite loop in CSG `Build2DFaces::_find_edge_intersections` ([GH-76521](https://github.com/godotengine/godot/pull/76521)).
+- Fix `CSGPolygon3D` in path mode disappearing at runtime ([GH-77118](https://github.com/godotengine/godot/pull/77118)).
+
+#### Animation
+
+- Fix `get_bone_pose_global_no_override()` returning incorrect values ([GH-77194](https://github.com/godotengine/godot/pull/77194)).
+- Fix for SkeletonIK3D interpolation and bone roll ([GH-77469](https://github.com/godotengine/godot/pull/77469)).
+- Only reset `rest_dirty` after ALL bone transforms have finished update ([GH-78025](https://github.com/godotengine/godot/pull/78025)).
+
+#### Audio
+
+- Fix AudioListener2D ignoring rotation for positional audio ([GH-69027](https://github.com/godotengine/godot/pull/69027)).
+- Fix trim when importing WAV ([GH-75261](https://github.com/godotengine/godot/pull/75261)).
+- Fix crash in the Android editor when creating `AudioStreamMicrophone` ([GH-77686](https://github.com/godotengine/godot/pull/77686)).
+
+#### C#/.NET
+
+- Fix exception when using base types of extension-based types from C# ([GH-75955](https://github.com/godotengine/godot/pull/75955)).
+- Fix C# glue generation for enums with negative values ([GH-77018](https://github.com/godotengine/godot/pull/77018)).
+- Mostly fix hash of ManagedCallable ([GH-77199](https://github.com/godotengine/godot/pull/77199)).
+
+#### Core
+
+- Fix multi-threaded resource loading ([GH-74405](https://github.com/godotengine/godot/pull/74405), [GH-77143](https://github.com/godotengine/godot/pull/77143)).
+- Fix recursive `Node.find_children` ([GH-75459](https://github.com/godotengine/godot/pull/75459)).
+- Fix invalid 2D global position when read outside tree ([GH-75509](https://github.com/godotengine/godot/pull/75509)).
+- Prevent errors when using ViewportTexture ([GH-75751](https://github.com/godotengine/godot/pull/75751)).
+- Properly update NodePaths with batch rename ([GH-76376](https://github.com/godotengine/godot/pull/76376)).
+- Fix multiple issues in `WorkerThreadPool` ([GH-76945](https://github.com/godotengine/godot/pull/76945), [GH-76999](https://github.com/godotengine/godot/pull/76999)).
+- Fix `StringName` comparison ([GH-77197](https://github.com/godotengine/godot/pull/77197)).
+- Fix grayscale alpha for `Image::convert` `FORMAT_L8` using REC.709 ([GH-77456](https://github.com/godotengine/godot/pull/77456)).
+- Fix external resource ids lost ([GH-77749](https://github.com/godotengine/godot/pull/77749)).
+
+#### Editor
+
+- Fix "View Owners" dialog not acknowledging that some resources aren't scenes ([GH-68697](https://github.com/godotengine/godot/pull/68697)).
+- Fix typed array export ([GH-73256](https://github.com/godotengine/godot/pull/73256)).
+- Various fixes to the 3-to-4 project conversion tool ([GH-75002](https://github.com/godotengine/godot/pull/75002), [GH-75900](https://github.com/godotengine/godot/pull/75900), [GH-77615](https://github.com/godotengine/godot/pull/77615), [GH-78097](https://github.com/godotengine/godot/pull/78097)).
+- Prevent quoted args in `editor/main_run_args` from being split at spaces ([GH-75444](https://github.com/godotengine/godot/pull/75444)).
+- Fix connect signal dialog not allowing Unicode method name ([GH-75814](https://github.com/godotengine/godot/pull/75814)).
+- Avoid error spam on first opening of a not yet imported project ([GH-77276](https://github.com/godotengine/godot/pull/77276)).
+75900), [GH-77615](https://github.com/godotengine/godot/pull/77615), [GH-78097](https://github.com/godotengine/godot/pull/78097)).
+
+#### Export
+
+- Make sure script cache is created after reimport ([GH-75798](https://github.com/godotengine/godot/pull/75798)).
+
+#### GDExtension
+
+- Fix GDExtension Variant type conversion ([GH-75758](https://github.com/godotengine/godot/pull/75758)).
+- Fix wrapping Objects in GDExtension that aren't exposed ([GH-78061](https://github.com/godotengine/godot/pull/78061)).
+- Fix `Ref<>.is_valid()` for ScriptInstanceExtension ([GH-78392](https://github.com/godotengine/godot/pull/78392)).
+- Use `Uninitialized*Ptr` for constructors/converters using placement new ([GH-78419](https://github.com/godotengine/godot/pull/78419)).
+
+#### GDScript
+
+- Fix access to identifiers that are reserved keywords ([GH-62830](https://github.com/godotengine/godot/pull/62830)).
+- Fix typed arrays not working with concatenation operator `+` ([GH-73540](https://github.com/godotengine/godot/pull/73540)).
+- Fix missing warning for shadowing of built-in types ([GH-74842](https://github.com/godotengine/godot/pull/74842)).
+
+#### GUI
+
+- Fix deselecting behavior in Tree ([GH-71307](https://github.com/godotengine/godot/pull/71307), [GH-71405](https://github.com/godotengine/godot/pull/71405)).
+- Fix RichTextLabel wrong selection offsets ([GH-71742](https://github.com/godotengine/godot/pull/71742), [GH-71747](https://github.com/godotengine/godot/pull/71747)).
+- Fix a blocking black rectangle that appears during color picking ([GH-74962](https://github.com/godotengine/godot/pull/74962)).
+- Fix blurry borders on antialiased StyleBoxFlat ([GH-76132](https://github.com/godotengine/godot/pull/76132)).
+- Fix `MenuBar` item order in RTL layout ([GH-77519](https://github.com/godotengine/godot/pull/77519)).
+- Fix input handling for unfocusable embedded windows ([GH-77842](https://github.com/godotengine/godot/pull/77842)).
+- Fix VideoStreamPlayer seamless loop ([GH-77856](https://github.com/godotengine/godot/pull/77856)).
+- Fix editor log flicker ([GH-77973](https://github.com/godotengine/godot/pull/77973)).
+- Ensure that controls update all their sizing information when required ([GH-78009](https://github.com/godotengine/godot/pull/78009)).
+- Fix passive mouse hovering for physics ([GH-78017](https://github.com/godotengine/godot/pull/78017)).
+
+#### Import
+
+- Fix Basis Universal compressing with normal maps ([GH-62718](https://github.com/godotengine/godot/pull/62718)).
+- Fix OBJ mesh importer smoothing handling ([GH-75315](https://github.com/godotengine/godot/pull/75315)).
+- Fix Silhouette used incorrect index ([GH-76499](https://github.com/godotengine/godot/pull/76499)).
+- Fix GLTFSkin binding for the `godot_skin` property ([GH-77413](https://github.com/godotengine/godot/pull/77413)).
+- Fix exporting MeshInstances without a Skeleton in the GLTF module ([GH-77545](https://github.com/godotengine/godot/pull/77545)).
+- Fix center of mass when importing GLTF physics bodies ([GH-77602](https://github.com/godotengine/godot/pull/77602)).
+
+#### Input
+
+- Fix guide button detection with XInput and Xbox Series controllers ([GH-73200](https://github.com/godotengine/godot/pull/73200)).
+- Fix just pressed and released with short presses ([GH-77055](https://github.com/godotengine/godot/pull/77055)).
+- Fix mouse position with screen transform ([GH-77923](https://github.com/godotengine/godot/pull/77923)).
+- Fix IME focus in Popup on Windows and macOS ([GH-77977](https://github.com/godotengine/godot/pull/77977), [GH-78029](https://github.com/godotengine/godot/pull/78029)).
+
+#### Networking
+
+- Fix incorrect value returned by `HTTPClient.get_response_body_length` on Web ([GH-77648](https://github.com/godotengine/godot/pull/77648)).
+- Fix delta variables index decoding ([GH-78709](https://github.com/godotengine/godot/pull/78709)).
+
+#### Physics
+
+- Fix various issues with PhysicsDirectBodyState3D contacts ([GH-58880](https://github.com/godotengine/godot/pull/58880)).
+- Improve rigid body CCD against moving bodies ([GH-76138](https://github.com/godotengine/godot/pull/76138)).
+
+#### Porting
+
+- Android: Fix UI responsiveness to touch taps ([GH-75703](https://github.com/godotengine/godot/pull/75703)).
+- Android: Fix double tap & drag on Android ([GH-76791](https://github.com/godotengine/godot/pull/76791)).
+- Android: Fix issue causing the last edited project to open while switching to another one ([GH-78129](https://github.com/godotengine/godot/pull/78129)).
+- iOS: Fix loading of GDExtension dylibs auto converted to framework ([GH-76510](https://github.com/godotengine/godot/pull/76510)).
+- iOS: Fix orientation change in runtime ([GH-78132](https://github.com/godotengine/godot/pull/78132)).
+- Linux/BSD: Fix the sliding window problem ([GH-76040](https://github.com/godotengine/godot/pull/76040)).
+- Linux/BSD: Fix temporary file permissions ([GH-78347](https://github.com/godotengine/godot/pull/78347)).
+- Windows: Fix queuing utterances in rapid succession in TTS ([GH-75880](https://github.com/godotengine/godot/pull/75880)).
+- Windows: Fix minimize button missing in non-resizable projects ([GH-77770](https://github.com/godotengine/godot/pull/77770)).
+
+#### Rendering
+
+- Fix GLES3 rendering on Android studio emulator ([GH-74945](https://github.com/godotengine/godot/pull/74945)).
+- Fix "Light Only" mode of `CanvasItemMaterial` ([GH-75181](https://github.com/godotengine/godot/pull/75181)).
+- Fix GLES texture uniform array binding ([GH-75313](https://github.com/godotengine/godot/pull/75313)).
+- Fix the limit for interpolation with respect to metallic and calculations in the SSR Fresnel Shlick ([GH-75368](https://github.com/godotengine/godot/pull/75368)).
+- Fix GLES3 GPUParticles3D not working in HTML export ([GH-75795](https://github.com/godotengine/godot/pull/75795)).
+- Fix voxel GI issues ([GH-76437](https://github.com/godotengine/godot/pull/76437), [GH-76550](https://github.com/godotengine/godot/pull/76550)).
+- Fix reflections in mobile renderer ([GH-76692](https://github.com/godotengine/godot/pull/76692)).
+- Fix modulation propagation for Y-sorted `CanvasItem`s ([GH-77079](https://github.com/godotengine/godot/pull/77079)).
+- Fix LightmapGI dynamic object lighting ([GH-77089](https://github.com/godotengine/godot/pull/77089)).
+- Fix calculation of skinned AABB for unused bones ([GH-77265](https://github.com/godotengine/godot/pull/77265)).
+- Fix various issues with blend modes in the OpenGL 3 renderer ([GH-77409](https://github.com/godotengine/godot/pull/77409)).
+- Fix Subtract blend mode of Forward+ and Mobile renderers ([GH-77520](https://github.com/godotengine/godot/pull/77520)).
+- Fix LCD blend mode color caching in OpenGL ([GH-77946](https://github.com/godotengine/godot/pull/77946)).
+- Ensure filter/repeat is cached by Viewport texture in GL Compatibility renderer ([GH-78285](https://github.com/godotengine/godot/pull/78285)).
+- Copy texture filter/repeat modes when replacing a texture in the GL Compatibility backend ([GH-78287](https://github.com/godotengine/godot/pull/78287)).
+- Fix volumetric fog in stereo by projection vertex in combined space ([GH-78436](https://github.com/godotengine/godot/pull/78436)).
+- Use a filter with mipmaps when initializing textures with mipmaps in GL Compatibility renderer ([GH-78720](https://github.com/godotengine/godot/pull/78720)).
+
+#### Shaders
+
+- Fix shader preprocessor cyclic include handling ([GH-77608](https://github.com/godotengine/godot/pull/77608)).
+
+#### XR
+
+- Fix OpenXR Passthrough mode ([GH-78135](https://github.com/godotengine/godot/pull/78135)).
+- Apply reprojection in multiview for our cluster lookup ([GH-78499](https://github.com/godotengine/godot/pull/78499)).
+- Fix incorrect depth buffer option in OpenXR ([GH-78550](https://github.com/godotengine/godot/pull/78550)).
+
+
## [4.0] - 2023-03-01
The Godot 4.0 release was our biggest released to date, spanning 4 years of
@@ -197,6 +632,8 @@ See the [release announcement](https://godotengine.org/article/godot-3-5-cant-st
- WebXR: Rendering and touch events now supported on smartphone AR ([GH-55869](https://github.com/godotengine/godot/pull/55869), [GH-56819](https://github.com/godotengine/godot/pull/56819)).
- WebXR: Allow mapping VR controller joystick/button IDs to match other AR/VR interfaces ([GH-59994](https://github.com/godotengine/godot/pull/59994)).### Changed
+### Changed
+
#### Audio
- Instance audio streams before `AudioServer::lock` call ([GH-59413](https://github.com/godotengine/godot/pull/59413)).
@@ -1333,7 +1770,7 @@ See the [release announcement](https://godotengine.org/article/godot-3-3-has-arr
- Support for automatically building Android templates before exporting.
- This makes 3rd-party SDK integration easier.
- Support for [texture atlases in 2D](https://godotengine.org/article/atlas-support-returns-godot-3-2).
-- Major improvements to the visual shader system. ([News post 1](https://godotengine.org/article/major-update-for-visual-shader-in-godot-3-2), [News post 2](https://godotengine.org/article/major-update-visual-shaders-godot-3-2-part-2))
+- Major improvements to the visual shader system ([News post 1](https://godotengine.org/article/major-update-for-visual-shader-in-godot-3-2), [News post 2](https://godotengine.org/article/major-update-visual-shaders-godot-3-2-part-2)).
- Redesigned visual shader editor with drag-and-drop capability.
- Textures can be dragged from the FileSystem dock to be added as nodes.
- Most functions available in GLSL are now exposed.
@@ -2440,6 +2877,7 @@ See the [release announcement](https://godotengine.org/article/godot-3-3-has-arr
- Only WebAssembly is supported now, since all browsers supporting WebGL 2.0 also support WebAssembly.
+[4.1]: https://github.com/godotengine/godot/compare/4.0-stable...4.1-stable
[4.0]: https://github.com/godotengine/godot/compare/3.2-stable...4.0-stable
[3.5]: https://github.com/godotengine/godot/compare/3.4-stable...3.5-stable
[3.4]: https://github.com/godotengine/godot/compare/3.3-stable...3.4-stable
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 5512aec234..582784d78e 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -409,7 +409,7 @@ License: Apache-2.0
Files: ./thirdparty/openxr/
Comment: OpenXR Loader
-Copyright: 2020-2022, The Khronos Group Inc.
+Copyright: 2020-2023, The Khronos Group Inc.
License: Apache-2.0
Files: ./thirdparty/pcre2/
@@ -425,7 +425,7 @@ License: Zlib
Files: ./thirdparty/rvo2/
Comment: RVO2
-Copyright: 2008, University of North Carolina at Chapel Hill
+Copyright: 2016, University of North Carolina at Chapel Hill
License: Apache-2.0
Files: ./thirdparty/spirv-reflect/
diff --git a/SConstruct b/SConstruct
index f65e6bab04..f82c9c656e 100644
--- a/SConstruct
+++ b/SConstruct
@@ -222,6 +222,7 @@ opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise e
opts.Add(BoolVariable("scu_build", "Use single compilation unit build", False))
# Thirdparty libraries
+opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
opts.Add(BoolVariable("builtin_certs", "Use the built-in SSL certificates bundles", True))
opts.Add(BoolVariable("builtin_embree", "Use the built-in Embree library", True))
opts.Add(BoolVariable("builtin_enet", "Use the built-in ENet library", True))
@@ -239,6 +240,7 @@ opts.Add(BoolVariable("builtin_libwebp", "Use the built-in libwebp library", Tru
opts.Add(BoolVariable("builtin_wslay", "Use the built-in wslay library", True))
opts.Add(BoolVariable("builtin_mbedtls", "Use the built-in mbedTLS library", True))
opts.Add(BoolVariable("builtin_miniupnpc", "Use the built-in miniupnpc library", True))
+opts.Add(BoolVariable("builtin_openxr", "Use the built-in OpenXR library", True))
opts.Add(BoolVariable("builtin_pcre2", "Use the built-in PCRE2 library", True))
opts.Add(BoolVariable("builtin_pcre2_with_jit", "Use JIT compiler for the built-in PCRE2 library", True))
opts.Add(BoolVariable("builtin_recastnavigation", "Use the built-in Recast navigation library", True))
@@ -296,21 +298,21 @@ else:
if selected_platform in ["macos", "osx"]:
if selected_platform == "osx":
# Deprecated alias kept for compatibility.
- print('Platform "osx" has been renamed to "macos" in Godot 4.0. Building for platform "macos".')
+ print('Platform "osx" has been renamed to "macos" in Godot 4. Building for platform "macos".')
# Alias for convenience.
selected_platform = "macos"
if selected_platform in ["ios", "iphone"]:
if selected_platform == "iphone":
# Deprecated alias kept for compatibility.
- print('Platform "iphone" has been renamed to "ios" in Godot 4.0. Building for platform "ios".')
+ print('Platform "iphone" has been renamed to "ios" in Godot 4. Building for platform "ios".')
# Alias for convenience.
selected_platform = "ios"
if selected_platform in ["linux", "bsd", "x11"]:
if selected_platform == "x11":
# Deprecated alias kept for compatibility.
- print('Platform "x11" has been renamed to "linuxbsd" in Godot 4.0. Building for platform "linuxbsd".')
+ print('Platform "x11" has been renamed to "linuxbsd" in Godot 4. Building for platform "linuxbsd".')
# Alias for convenience.
selected_platform = "linuxbsd"
diff --git a/core/SCsub b/core/SCsub
index a0176f6c33..ab78eeedc7 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -65,7 +65,7 @@ thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_mis
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
# Brotli
-if env["brotli"]:
+if env["brotli"] and env["builtin_brotli"]:
thirdparty_brotli_dir = "#thirdparty/brotli/"
thirdparty_brotli_sources = [
"common/constants.c",
@@ -97,7 +97,6 @@ if env["builtin_zlib"]:
"compress.c",
"crc32.c",
"deflate.c",
- "infback.c",
"inffast.c",
"inflate.c",
"inftrees.c",
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 79fab50882..715ed61770 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1344,7 +1344,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/occlusion_culling/bvh_build_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), 2);
GLOBAL_DEF(PropertyInfo(Variant::INT, "memory/limits/multithreaded_server/rid_pool_prealloc", PROPERTY_HINT_RANGE, "0,500,1"), 60); // No negative and limit to 500 due to crashes.
GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false);
- GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "internationalization/rendering/root_node_layout_direction", PROPERTY_HINT_RANGE, "Based on Locale,Left-to-Right,Right-to-Left"), 0);
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "internationalization/rendering/root_node_layout_direction", PROPERTY_HINT_ENUM, "Based on Locale,Left-to-Right,Right-to-Left"), 0);
GLOBAL_DEF(PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"), 2000);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 2d0d24406c..a73b198be2 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -442,6 +442,10 @@ bool OS::has_feature(const String &p_feature) const {
}
}
+bool OS::is_sandboxed() const {
+ return ::OS::get_singleton()->is_sandboxed();
+}
+
uint64_t OS::get_static_memory_usage() const {
return ::OS::get_singleton()->get_static_memory_usage();
}
@@ -545,6 +549,10 @@ Vector<String> OS::get_granted_permissions() const {
return ::OS::get_singleton()->get_granted_permissions();
}
+void OS::revoke_granted_permissions() {
+ ::OS::get_singleton()->revoke_granted_permissions();
+}
+
String OS::get_unique_id() const {
return ::OS::get_singleton()->get_unique_id();
}
@@ -636,10 +644,12 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_main_thread_id"), &OS::get_main_thread_id);
ClassDB::bind_method(D_METHOD("has_feature", "tag_name"), &OS::has_feature);
+ ClassDB::bind_method(D_METHOD("is_sandboxed"), &OS::is_sandboxed);
ClassDB::bind_method(D_METHOD("request_permission", "name"), &OS::request_permission);
ClassDB::bind_method(D_METHOD("request_permissions"), &OS::request_permissions);
ClassDB::bind_method(D_METHOD("get_granted_permissions"), &OS::get_granted_permissions);
+ ClassDB::bind_method(D_METHOD("revoke_granted_permissions"), &OS::revoke_granted_permissions);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "low_processor_usage_mode"), "set_low_processor_usage_mode", "is_in_low_processor_usage_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "low_processor_usage_mode_sleep_usec"), "set_low_processor_usage_mode_sleep_usec", "get_low_processor_usage_mode_sleep_usec");
diff --git a/core/core_bind.h b/core/core_bind.h
index 6b25510b14..dc0b2a1cf5 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -230,14 +230,16 @@ public:
String get_cache_dir() const;
Error set_thread_name(const String &p_name);
- Thread::ID get_thread_caller_id() const;
- Thread::ID get_main_thread_id() const;
+ ::Thread::ID get_thread_caller_id() const;
+ ::Thread::ID get_main_thread_id() const;
bool has_feature(const String &p_feature) const;
+ bool is_sandboxed() const;
bool request_permission(const String &p_name);
bool request_permissions();
Vector<String> get_granted_permissions() const;
+ void revoke_granted_permissions();
static OS *get_singleton() { return singleton; }
diff --git a/core/debugger/debugger_marshalls.cpp b/core/debugger/debugger_marshalls.cpp
index 591b44869f..3e6b7501c7 100644
--- a/core/debugger/debugger_marshalls.cpp
+++ b/core/debugger/debugger_marshalls.cpp
@@ -67,6 +67,7 @@ Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
Array arr;
arr.push_back(name);
arr.push_back(type);
+ arr.push_back(value.get_type());
Variant var = value;
if (value.get_type() == Variant::OBJECT && value.get_validated_object() == nullptr) {
@@ -74,7 +75,7 @@ Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
}
int len = 0;
- Error err = encode_variant(var, nullptr, len, true);
+ Error err = encode_variant(var, nullptr, len, false);
if (err != OK) {
ERR_PRINT("Failed to encode variant.");
}
@@ -88,11 +89,12 @@ Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
}
bool DebuggerMarshalls::ScriptStackVariable::deserialize(const Array &p_arr) {
- CHECK_SIZE(p_arr, 3, "ScriptStackVariable");
+ CHECK_SIZE(p_arr, 4, "ScriptStackVariable");
name = p_arr[0];
type = p_arr[1];
- value = p_arr[2];
- CHECK_END(p_arr, 3, "ScriptStackVariable");
+ var_type = p_arr[2];
+ value = p_arr[3];
+ CHECK_END(p_arr, 4, "ScriptStackVariable");
return true;
}
diff --git a/core/debugger/debugger_marshalls.h b/core/debugger/debugger_marshalls.h
index 8ba93c3092..1b81623688 100644
--- a/core/debugger/debugger_marshalls.h
+++ b/core/debugger/debugger_marshalls.h
@@ -38,6 +38,7 @@ struct DebuggerMarshalls {
String name;
Variant value;
int type = -1;
+ int var_type = -1;
Array serialize(int max_size = 1 << 20); // 1 MiB default.
bool deserialize(const Array &p_arr);
diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp
index 6c9293a2cf..32dc060aa2 100644
--- a/core/debugger/engine_debugger.cpp
+++ b/core/debugger/engine_debugger.cpp
@@ -111,14 +111,6 @@ Error EngineDebugger::capture_parse(const StringName &p_name, const String &p_ms
return cap.capture(cap.data, p_msg, p_args, r_captured);
}
-void EngineDebugger::line_poll() {
- // The purpose of this is just processing events every now and then when the script might get too busy otherwise bugs like infinite loops can't be caught
- if (poll_every % 2048 == 0) {
- poll_events(false);
- }
- poll_every++;
-}
-
void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, double p_physics_frame_time) {
frame_time = USEC_TO_SEC(p_frame_ticks);
process_time = USEC_TO_SEC(p_process_ticks);
diff --git a/core/debugger/engine_debugger.h b/core/debugger/engine_debugger.h
index 1bae71e37a..88d5490794 100644
--- a/core/debugger/engine_debugger.h
+++ b/core/debugger/engine_debugger.h
@@ -126,7 +126,13 @@ public:
void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
Error capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured);
- void line_poll();
+ void line_poll() {
+ // The purpose of this is just processing events every now and then when the script might get too busy otherwise bugs like infinite loops can't be caught.
+ if (unlikely(poll_every % 2048) == 0) {
+ poll_events(false);
+ }
+ poll_every++;
+ }
virtual void poll_events(bool p_is_idle) {}
virtual void send_message(const String &p_msg, const Array &p_data) = 0;
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index b7471d7c82..b4d6fa4174 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -94,6 +94,7 @@ public:
Error RemoteDebugger::_put_msg(String p_message, Array p_data) {
Array msg;
msg.push_back(p_message);
+ msg.push_back(Thread::get_caller_id());
msg.push_back(p_data);
Error err = peer->put_message(msg);
if (err != OK) {
@@ -185,9 +186,9 @@ RemoteDebugger::ErrorMessage RemoteDebugger::_create_overflow_error(const String
}
void RemoteDebugger::flush_output() {
+ MutexLock lock(mutex);
flush_thread = Thread::get_caller_id();
flushing = true;
- MutexLock lock(mutex);
if (!is_peer_connected()) {
return;
}
@@ -348,18 +349,65 @@ Error RemoteDebugger::_try_capture(const String &p_msg, const Array &p_data, boo
return capture_parse(cap, msg, p_data, r_captured);
}
+void RemoteDebugger::_poll_messages() {
+ MutexLock mutex_lock(mutex);
+
+ peer->poll();
+ while (peer->has_message()) {
+ Array cmd = peer->get_message();
+ ERR_CONTINUE(cmd.size() != 3);
+ ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);
+ ERR_CONTINUE(cmd[1].get_type() != Variant::INT);
+ ERR_CONTINUE(cmd[2].get_type() != Variant::ARRAY);
+
+ Thread::ID thread = cmd[1];
+
+ if (!messages.has(thread)) {
+ continue; // This thread is not around to receive the messages
+ }
+
+ Message msg;
+ msg.message = cmd[0];
+ msg.data = cmd[2];
+ messages[thread].push_back(msg);
+ }
+}
+
+bool RemoteDebugger::_has_messages() {
+ MutexLock mutex_lock(mutex);
+ return messages.has(Thread::get_caller_id()) && !messages[Thread::get_caller_id()].is_empty();
+}
+
+Array RemoteDebugger::_get_message() {
+ MutexLock mutex_lock(mutex);
+ ERR_FAIL_COND_V(!messages.has(Thread::get_caller_id()), Array());
+ List<Message> &message_list = messages[Thread::get_caller_id()];
+ ERR_FAIL_COND_V(message_list.is_empty(), Array());
+
+ Array msg;
+ msg.resize(2);
+ msg[0] = message_list.front()->get().message;
+ msg[1] = message_list.front()->get().data;
+ message_list.pop_front();
+ return msg;
+}
+
void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
//this function is called when there is a debugger break (bug on script)
//or when execution is paused from editor
- if (script_debugger->is_skipping_breakpoints() && !p_is_error_breakpoint) {
- return;
- }
+ {
+ MutexLock lock(mutex);
+ // Tests that require mutex.
+ if (script_debugger->is_skipping_breakpoints() && !p_is_error_breakpoint) {
+ return;
+ }
- ERR_FAIL_COND_MSG(!is_peer_connected(), "Script Debugger failed to connect, but being used anyway.");
+ ERR_FAIL_COND_MSG(!is_peer_connected(), "Script Debugger failed to connect, but being used anyway.");
- if (!peer->can_block()) {
- return; // Peer does not support blocking IO. We could at least send the error though.
+ if (!peer->can_block()) {
+ return; // Peer does not support blocking IO. We could at least send the error though.
+ }
}
ScriptLanguage *script_lang = script_debugger->get_break_language();
@@ -369,22 +417,33 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
msg.push_back(error_str);
ERR_FAIL_COND(!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) {
allow_focus_steal_fn();
}
send_message("debug_enter", msg);
- Input::MouseMode mouse_mode = Input::get_singleton()->get_mouse_mode();
- if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ Input::MouseMode mouse_mode = Input::MOUSE_MODE_VISIBLE;
+
+ if (Thread::get_caller_id() == Thread::get_main_id()) {
+ mouse_mode = Input::get_singleton()->get_mouse_mode();
+ if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ }
+ } else {
+ MutexLock mutex_lock(mutex);
+ messages.insert(Thread::get_caller_id(), List<Message>());
}
+ mutex.lock();
while (is_peer_connected()) {
+ mutex.unlock();
flush_output();
- peer->poll();
- if (peer->has_message()) {
- Array cmd = peer->get_message();
+ _poll_messages();
+
+ if (_has_messages()) {
+ Array cmd = _get_message();
ERR_CONTINUE(cmd.size() != 2);
ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);
@@ -479,14 +538,22 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
}
} else {
OS::get_singleton()->delay_usec(10000);
- OS::get_singleton()->process_and_drop_events();
+ if (Thread::get_caller_id() == Thread::get_main_id()) {
+ // If this is a busy loop on the main thread, events still need to be processed.
+ OS::get_singleton()->process_and_drop_events();
+ }
}
}
send_message("debug_exit", Array());
- if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
- Input::get_singleton()->set_mouse_mode(mouse_mode);
+ if (Thread::get_caller_id() == Thread::get_main_id()) {
+ if (mouse_mode != Input::MOUSE_MODE_VISIBLE) {
+ Input::get_singleton()->set_mouse_mode(mouse_mode);
+ }
+ } else {
+ MutexLock mutex_lock(mutex);
+ messages.erase(Thread::get_caller_id());
}
}
@@ -496,9 +563,11 @@ void RemoteDebugger::poll_events(bool p_is_idle) {
}
flush_output();
- peer->poll();
- while (peer->has_message()) {
- Array arr = peer->get_message();
+
+ _poll_messages();
+
+ while (_has_messages()) {
+ Array arr = _get_message();
ERR_CONTINUE(arr.size() != 2);
ERR_CONTINUE(arr[0].get_type() != Variant::STRING);
@@ -604,6 +673,8 @@ RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) {
eh.errfunc = _err_handler;
eh.userdata = this;
add_error_handler(&eh);
+
+ messages.insert(Thread::get_main_id(), List<Message>());
}
RemoteDebugger::~RemoteDebugger() {
diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h
index 24283b0ed6..7c399178c6 100644
--- a/core/debugger/remote_debugger.h
+++ b/core/debugger/remote_debugger.h
@@ -80,6 +80,17 @@ private:
bool flushing = false;
Thread::ID flush_thread = 0;
+ struct Message {
+ String message;
+ Array data;
+ };
+
+ HashMap<Thread::ID, List<Message>> messages;
+
+ void _poll_messages();
+ bool _has_messages();
+ Array _get_message();
+
PrintHandlerList phl;
static void _print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich);
ErrorHandlerList eh;
diff --git a/core/debugger/script_debugger.cpp b/core/debugger/script_debugger.cpp
index 32725b76c1..e7d8654a0b 100644
--- a/core/debugger/script_debugger.cpp
+++ b/core/debugger/script_debugger.cpp
@@ -32,22 +32,19 @@
#include "core/debugger/engine_debugger.h"
+thread_local int ScriptDebugger::lines_left = -1;
+thread_local int ScriptDebugger::depth = -1;
+thread_local ScriptLanguage *ScriptDebugger::break_lang = nullptr;
+thread_local Vector<ScriptDebugger::StackInfo> ScriptDebugger::error_stack_info;
+
void ScriptDebugger::set_lines_left(int p_left) {
lines_left = p_left;
}
-int ScriptDebugger::get_lines_left() const {
- return lines_left;
-}
-
void ScriptDebugger::set_depth(int p_depth) {
depth = p_depth;
}
-int ScriptDebugger::get_depth() const {
- return depth;
-}
-
void ScriptDebugger::insert_breakpoint(int p_line, const StringName &p_source) {
if (!breakpoints.has(p_line)) {
breakpoints[p_line] = HashSet<StringName>();
@@ -66,13 +63,6 @@ void ScriptDebugger::remove_breakpoint(int p_line, const StringName &p_source) {
}
}
-bool ScriptDebugger::is_breakpoint(int p_line, const StringName &p_source) const {
- if (!breakpoints.has(p_line)) {
- return false;
- }
- return breakpoints[p_line].has(p_source);
-}
-
String ScriptDebugger::breakpoint_find_source(const String &p_source) const {
return p_source;
}
@@ -100,7 +90,7 @@ void ScriptDebugger::send_error(const String &p_func, const String &p_file, int
// Store stack info, this is ugly, but allows us to separate EngineDebugger and ScriptDebugger. There might be a better way.
error_stack_info.append_array(p_stack_info);
EngineDebugger::get_singleton()->send_error(p_func, p_file, p_line, p_err, p_descr, p_editor_notify, p_type);
- error_stack_info.clear();
+ error_stack_info.clear(); // Clear because this is thread local
}
Vector<ScriptLanguage::StackInfo> ScriptDebugger::get_error_stack_info() const {
diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h
index edce089179..ee037b91fa 100644
--- a/core/debugger/script_debugger.h
+++ b/core/debugger/script_debugger.h
@@ -40,21 +40,25 @@
class ScriptDebugger {
typedef ScriptLanguage::StackInfo StackInfo;
- int lines_left = -1;
- int depth = -1;
bool skip_breakpoints = false;
HashMap<int, HashSet<StringName>> breakpoints;
- ScriptLanguage *break_lang = nullptr;
- Vector<StackInfo> error_stack_info;
+ static thread_local int lines_left;
+ static thread_local int depth;
+ static thread_local ScriptLanguage *break_lang;
+ static thread_local Vector<StackInfo> error_stack_info;
public:
void set_lines_left(int p_left);
- int get_lines_left() const;
+ _ALWAYS_INLINE_ int get_lines_left() const {
+ return lines_left;
+ }
void set_depth(int p_depth);
- int get_depth() const;
+ _ALWAYS_INLINE_ int get_depth() const {
+ return depth;
+ }
String breakpoint_find_source(const String &p_source) const;
void set_break_language(ScriptLanguage *p_lang) { break_lang = p_lang; }
@@ -63,7 +67,12 @@ public:
bool is_skipping_breakpoints();
void insert_breakpoint(int p_line, const StringName &p_source);
void remove_breakpoint(int p_line, const StringName &p_source);
- bool is_breakpoint(int p_line, const StringName &p_source) const;
+ _ALWAYS_INLINE_ bool is_breakpoint(int p_line, const StringName &p_source) const {
+ if (likely(!breakpoints.has(p_line))) {
+ return false;
+ }
+ return breakpoints[p_line].has(p_source);
+ }
void clear_breakpoints();
const HashMap<int, HashSet<StringName>> &get_breakpoints() const { return breakpoints; }
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 73526fae3e..67b55db3db 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -363,6 +363,10 @@ void GDExtension::_register_extension_class_integer_constant(GDExtensionClassLib
}
void GDExtension::_register_extension_class_property(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter) {
+ _register_extension_class_property_indexed(p_library, p_class_name, p_info, p_setter, p_getter, -1);
+}
+
+void GDExtension::_register_extension_class_property_indexed(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter, GDExtensionInt p_index) {
GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
@@ -371,10 +375,9 @@ void GDExtension::_register_extension_class_property(GDExtensionClassLibraryPtr
String property_name = *reinterpret_cast<const StringName *>(p_info->name);
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + property_name + "' for unexisting class '" + class_name + "'.");
- //Extension *extension = &self->extension_classes[class_name];
PropertyInfo pinfo(*p_info);
- ClassDB::add_property(class_name, pinfo, setter, getter);
+ ClassDB::add_property(class_name, pinfo, setter, getter, p_index);
}
void GDExtension::_register_extension_class_property_group(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringPtr p_group_name, GDExtensionConstStringPtr p_prefix) {
@@ -542,6 +545,7 @@ void GDExtension::initialize_gdextensions() {
register_interface_function("classdb_register_extension_class_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_method);
register_interface_function("classdb_register_extension_class_integer_constant", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_integer_constant);
register_interface_function("classdb_register_extension_class_property", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property);
+ register_interface_function("classdb_register_extension_class_property_indexed", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property_indexed);
register_interface_function("classdb_register_extension_class_property_group", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property_group);
register_interface_function("classdb_register_extension_class_property_subgroup", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property_subgroup);
register_interface_function("classdb_register_extension_class_signal", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_signal);
diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h
index 77ec458d30..b935f8706f 100644
--- a/core/extension/gdextension.h
+++ b/core/extension/gdextension.h
@@ -54,6 +54,7 @@ class GDExtension : public Resource {
static void _register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info);
static void _register_extension_class_integer_constant(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield);
static void _register_extension_class_property(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter);
+ static void _register_extension_class_property_indexed(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter, GDExtensionInt p_index);
static void _register_extension_class_property_group(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_group_name, GDExtensionConstStringNamePtr p_prefix);
static void _register_extension_class_property_subgroup(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_subgroup_name, GDExtensionConstStringNamePtr p_prefix);
static void _register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count);
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index 7fbf2d00a1..7ef956a470 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -726,6 +726,11 @@ static void gdextension_string_operator_plus_eq_c32str(GDExtensionStringPtr p_se
*self += p_b;
}
+static GDExtensionInt gdextension_string_resize(GDExtensionStringPtr p_self, GDExtensionInt p_length) {
+ String *self = (String *)p_self;
+ return (*self).resize(p_length);
+}
+
static GDExtensionInt gdextension_xml_parser_open_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size) {
XMLParser *xml = (XMLParser *)p_instance;
return (GDExtensionInt)xml->_open_buffer(p_buffer, p_size);
@@ -1167,6 +1172,7 @@ void gdextension_setup_interface() {
REGISTER_INTERFACE_FUNC(string_operator_plus_eq_cstr);
REGISTER_INTERFACE_FUNC(string_operator_plus_eq_wcstr);
REGISTER_INTERFACE_FUNC(string_operator_plus_eq_c32str);
+ REGISTER_INTERFACE_FUNC(string_resize);
REGISTER_INTERFACE_FUNC(xml_parser_open_buffer);
REGISTER_INTERFACE_FUNC(file_access_store_buffer);
REGISTER_INTERFACE_FUNC(file_access_get_buffer);
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 4d7bdf9502..6c05f3988b 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -1526,6 +1526,25 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqWcstr)(GDExtensionStringP
*/
typedef void (*GDExtensionInterfaceStringOperatorPlusEqC32str)(GDExtensionStringPtr p_self, const char32_t *p_b);
+/**
+ * @name string_resize
+ * @since 4.2
+ *
+ * Resizes the underlying string data to the given number of characters.
+ *
+ * Space needs to be allocated for the null terminating character ('\0') which
+ * also must be added manually, in order for all string functions to work correctly.
+ *
+ * Warning: This is an error-prone operation - only use it if there's no other
+ * efficient way to accomplish your goal.
+ *
+ * @param p_self A pointer to the String.
+ * @param p_resize The new length for the String.
+ *
+ * @return Error code signifying if the operation successful.
+ */
+typedef GDExtensionInt (*GDExtensionInterfaceStringResize)(GDExtensionStringPtr p_self, GDExtensionInt p_resize);
+
/* INTERFACE: XMLParser Utilities */
/**
@@ -2212,6 +2231,23 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant)
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassProperty)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter);
/**
+ * @name classdb_register_extension_class_property_indexed
+ * @since 4.2
+ *
+ * Registers an indexed property on an extension class in the ClassDB.
+ *
+ * Provided struct can be safely freed once the function returns.
+ *
+ * @param p_library A pointer the library received by the GDExtension's entry point function.
+ * @param p_class_name A pointer to a StringName with the class name.
+ * @param p_info A pointer to a GDExtensionPropertyInfo struct.
+ * @param p_setter A pointer to a StringName with the name of the setter method.
+ * @param p_getter A pointer to a StringName with the name of the getter method.
+ * @param p_index The index to pass as the first argument to the getter and setter methods.
+ */
+typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter, GDExtensionInt p_index);
+
+/**
* @name classdb_register_extension_class_property_group
* @since 4.1
*
diff --git a/core/input/input.cpp b/core/input/input.cpp
index cf8d71b9a7..d481acf005 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -113,6 +113,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis);
ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name);
ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid);
+ ClassDB::bind_method(D_METHOD("should_ignore_device", "vendor_id", "product_id"), &Input::should_ignore_device);
ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
@@ -1498,6 +1499,11 @@ String Input::get_joy_guid(int p_device) const {
return joy_names[p_device].uid;
}
+bool Input::should_ignore_device(int p_vendor_id, int p_product_id) const {
+ uint32_t full_id = (((uint32_t)p_vendor_id) << 16) | ((uint16_t)p_product_id);
+ return ignored_device_ids.has(full_id);
+}
+
TypedArray<int> Input::get_connected_joypads() {
TypedArray<int> ret;
HashMap<int, Joypad>::Iterator elem = joy_names.begin();
@@ -1542,6 +1548,27 @@ Input::Input() {
}
}
+ String env_ignore_devices = OS::get_singleton()->get_environment("SDL_GAMECONTROLLER_IGNORE_DEVICES");
+ if (!env_ignore_devices.is_empty()) {
+ Vector<String> entries = env_ignore_devices.split(",");
+ for (int i = 0; i < entries.size(); i++) {
+ Vector<String> vid_pid = entries[i].split("/");
+
+ if (vid_pid.size() < 2) {
+ continue;
+ }
+
+ print_verbose(vformat("Device Ignored -- Vendor: %s Product: %s", vid_pid[0], vid_pid[1]));
+ const uint16_t vid_unswapped = vid_pid[0].hex_to_int();
+ const uint16_t pid_unswapped = vid_pid[1].hex_to_int();
+ const uint16_t vid = BSWAP16(vid_unswapped);
+ const uint16_t pid = BSWAP16(pid_unswapped);
+
+ uint32_t full_id = (((uint32_t)vid) << 16) | ((uint16_t)pid);
+ ignored_device_ids.insert(full_id);
+ }
+ }
+
legacy_just_pressed_behavior = GLOBAL_DEF("input_devices/compatibility/legacy_just_pressed_behavior", false);
if (Engine::get_singleton()->is_editor_hint()) {
// Always use standard behavior in the editor.
diff --git a/core/input/input.h b/core/input/input.h
index 9cc596ee90..ec16871b72 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -154,6 +154,9 @@ private:
VelocityTrack mouse_velocity_track;
HashMap<int, VelocityTrack> touch_velocity_track;
HashMap<int, Joypad> joy_names;
+
+ HashSet<uint32_t> ignored_device_ids;
+
int fallback_mapping = -1;
CursorShape default_shape = CURSOR_ARROW;
@@ -328,6 +331,7 @@ public:
bool is_joy_known(int p_device);
String get_joy_guid(int p_device) const;
+ bool should_ignore_device(int p_vendor_id, int p_product_id) const;
void set_fallback_mapping(String p_guid);
void flush_buffered_events();
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index e547b04d0b..e37886cbe9 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -1192,7 +1192,7 @@ static const char *_joy_button_descriptions[(size_t)JoyButton::SDL_MAX] = {
TTRC("Top Action, Sony Triangle, Xbox Y, Nintendo X"),
TTRC("Back, Sony Select, Xbox Back, Nintendo -"),
TTRC("Guide, Sony PS, Xbox Home"),
- TTRC("Start, Nintendo +"),
+ TTRC("Start, Xbox Menu, Nintendo +"),
TTRC("Left Stick, Sony L3, Xbox L/LS"),
TTRC("Right Stick, Sony R3, Xbox R/RS"),
TTRC("Left Shoulder, Sony L1, Xbox LB"),
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index ac4a637597..e36fb0afa4 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -35,13 +35,13 @@
#include "thirdparty/misc/fastlz.h"
-#ifdef BROTLI_ENABLED
-#include "thirdparty/brotli/include/brotli/decode.h"
-#endif
-
#include <zlib.h>
#include <zstd.h>
+#ifdef BROTLI_ENABLED
+#include <brotli/decode.h>
+#endif
+
int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) {
switch (p_mode) {
case MODE_BROTLI: {
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 064353476f..c7f1a73f97 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -47,7 +47,7 @@ static void *godot_open(voidpf opaque, const char *p_fname, int mode) {
return nullptr;
}
- Ref<FileAccess> f = FileAccess::open(p_fname, FileAccess::READ);
+ Ref<FileAccess> f = FileAccess::open(String::utf8(p_fname), FileAccess::READ);
ERR_FAIL_COND_V(f.is_null(), nullptr);
ZipData *zd = memnew(ZipData);
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 9bb987b670..7326563f18 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -517,21 +517,31 @@ void Image::convert(Format p_new_format) {
return;
}
+ // Includes the main image.
+ const int mipmap_count = get_mipmap_count() + 1;
+
if (format > FORMAT_RGBE9995 || p_new_format > FORMAT_RGBE9995) {
ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
} else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8) {
//use put/set pixel which is slower but works with non byte formats
- Image new_img(width, height, false, p_new_format);
+ Image new_img(width, height, mipmaps, p_new_format);
- for (int i = 0; i < width; i++) {
- for (int j = 0; j < height; j++) {
- new_img.set_pixel(i, j, get_pixel(i, j));
+ for (int mip = 0; mip < mipmap_count; mip++) {
+ Ref<Image> src_mip = get_image_from_mipmap(mip);
+ Ref<Image> new_mip = new_img.get_image_from_mipmap(mip);
+
+ for (int y = 0; y < src_mip->height; y++) {
+ for (int x = 0; x < src_mip->width; x++) {
+ new_mip->set_pixel(x, y, src_mip->get_pixel(x, y));
+ }
}
- }
- if (has_mipmaps()) {
- new_img.generate_mipmaps();
+ int mip_offset = 0;
+ int mip_size = 0;
+ new_img.get_mipmap_offset_and_size(mip, mip_offset, mip_size);
+
+ memcpy(new_img.data.ptrw() + mip_offset, new_mip->data.ptr(), mip_size);
}
_copy_internals_from(new_img);
@@ -539,113 +549,115 @@ void Image::convert(Format p_new_format) {
return;
}
- Image new_img(width, height, false, p_new_format);
-
- const uint8_t *rptr = data.ptr();
- uint8_t *wptr = new_img.data.ptrw();
+ Image new_img(width, height, mipmaps, p_new_format);
int conversion_type = format | p_new_format << 8;
- switch (conversion_type) {
- case FORMAT_L8 | (FORMAT_LA8 << 8):
- _convert<1, false, 1, true, true, true>(width, height, rptr, wptr);
- break;
- case FORMAT_L8 | (FORMAT_R8 << 8):
- _convert<1, false, 1, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_L8 | (FORMAT_RG8 << 8):
- _convert<1, false, 2, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_L8 | (FORMAT_RGB8 << 8):
- _convert<1, false, 3, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_L8 | (FORMAT_RGBA8 << 8):
- _convert<1, false, 3, true, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_L8 << 8):
- _convert<1, true, 1, false, true, true>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_R8 << 8):
- _convert<1, true, 1, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_RG8 << 8):
- _convert<1, true, 2, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_RGB8 << 8):
- _convert<1, true, 3, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_RGBA8 << 8):
- _convert<1, true, 3, true, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_L8 << 8):
- _convert<1, false, 1, false, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_LA8 << 8):
- _convert<1, false, 1, true, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_RG8 << 8):
- _convert<1, false, 2, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_RGB8 << 8):
- _convert<1, false, 3, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_RGBA8 << 8):
- _convert<1, false, 3, true, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_L8 << 8):
- _convert<2, false, 1, false, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_LA8 << 8):
- _convert<2, false, 1, true, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_R8 << 8):
- _convert<2, false, 1, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_RGB8 << 8):
- _convert<2, false, 3, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_RGBA8 << 8):
- _convert<2, false, 3, true, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_L8 << 8):
- _convert<3, false, 1, false, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_LA8 << 8):
- _convert<3, false, 1, true, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_R8 << 8):
- _convert<3, false, 1, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_RG8 << 8):
- _convert<3, false, 2, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_RGBA8 << 8):
- _convert<3, false, 3, true, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_L8 << 8):
- _convert<3, true, 1, false, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_LA8 << 8):
- _convert<3, true, 1, true, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_R8 << 8):
- _convert<3, true, 1, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_RG8 << 8):
- _convert<3, true, 2, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_RGB8 << 8):
- _convert<3, true, 3, false, false, false>(width, height, rptr, wptr);
- break;
- }
-
- bool gen_mipmaps = mipmaps;
+ for (int mip = 0; mip < mipmap_count; mip++) {
+ int mip_offset = 0;
+ int mip_size = 0;
+ int mip_width = 0;
+ int mip_height = 0;
+ get_mipmap_offset_size_and_dimensions(mip, mip_offset, mip_size, mip_width, mip_height);
- _copy_internals_from(new_img);
+ const uint8_t *rptr = data.ptr() + mip_offset;
+ uint8_t *wptr = new_img.data.ptrw() + new_img.get_mipmap_offset(mip);
- if (gen_mipmaps) {
- generate_mipmaps();
+ switch (conversion_type) {
+ case FORMAT_L8 | (FORMAT_LA8 << 8):
+ _convert<1, false, 1, true, true, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_L8 | (FORMAT_R8 << 8):
+ _convert<1, false, 1, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_L8 | (FORMAT_RG8 << 8):
+ _convert<1, false, 2, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_L8 | (FORMAT_RGB8 << 8):
+ _convert<1, false, 3, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_L8 | (FORMAT_RGBA8 << 8):
+ _convert<1, false, 3, true, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_L8 << 8):
+ _convert<1, true, 1, false, true, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_R8 << 8):
+ _convert<1, true, 1, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_RG8 << 8):
+ _convert<1, true, 2, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_RGB8 << 8):
+ _convert<1, true, 3, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_RGBA8 << 8):
+ _convert<1, true, 3, true, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_L8 << 8):
+ _convert<1, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_LA8 << 8):
+ _convert<1, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_RG8 << 8):
+ _convert<1, false, 2, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_RGB8 << 8):
+ _convert<1, false, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_RGBA8 << 8):
+ _convert<1, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_L8 << 8):
+ _convert<2, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_LA8 << 8):
+ _convert<2, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_R8 << 8):
+ _convert<2, false, 1, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_RGB8 << 8):
+ _convert<2, false, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_RGBA8 << 8):
+ _convert<2, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_L8 << 8):
+ _convert<3, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_LA8 << 8):
+ _convert<3, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_R8 << 8):
+ _convert<3, false, 1, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_RG8 << 8):
+ _convert<3, false, 2, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_RGBA8 << 8):
+ _convert<3, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_L8 << 8):
+ _convert<3, true, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_LA8 << 8):
+ _convert<3, true, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_R8 << 8):
+ _convert<3, true, 1, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_RG8 << 8):
+ _convert<3, true, 2, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_RGB8 << 8):
+ _convert<3, true, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ }
}
+
+ _copy_internals_from(new_img);
}
Image::Format Image::get_format() const {
@@ -3004,6 +3016,7 @@ ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
+ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr;
void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr;
void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr;
@@ -3476,6 +3489,9 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer);
ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer);
+ ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0));
+
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
BIND_CONSTANT(MAX_WIDTH);
@@ -3825,6 +3841,28 @@ Error Image::load_bmp_from_buffer(const Vector<uint8_t> &p_array) {
return _load_from_buffer(p_array, _bmp_mem_loader_func);
}
+Error Image::load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale) {
+ ERR_FAIL_NULL_V_MSG(
+ _svg_scalable_mem_loader_func,
+ ERR_UNAVAILABLE,
+ "The SVG module isn't enabled. Recompile the Godot editor or export template binary with the `module_svg_enabled=yes` SCons option.");
+
+ int buffer_size = p_array.size();
+
+ ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER);
+
+ Ref<Image> image = _svg_scalable_mem_loader_func(p_array.ptr(), buffer_size, scale);
+ ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR);
+
+ copy_internals_from(image);
+
+ return OK;
+}
+
+Error Image::load_svg_from_string(const String &p_svg_str, float scale) {
+ return load_svg_from_buffer(p_svg_str.to_utf8_buffer(), scale);
+}
+
void Image::convert_rg_to_ra_rgba8() {
ERR_FAIL_COND(format != FORMAT_RGBA8);
ERR_FAIL_COND(!data.size());
diff --git a/core/io/image.h b/core/io/image.h
index 8e353a8bb7..f877b00ee6 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -48,6 +48,7 @@ typedef Vector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img);
typedef Error (*SaveJPGFunc)(const String &p_path, const Ref<Image> &p_img, float p_quality);
typedef Vector<uint8_t> (*SaveJPGBufferFunc)(const Ref<Image> &p_img, float p_quality);
typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
+typedef Ref<Image> (*ScalableImageMemLoadFunc)(const uint8_t *p_data, int p_size, float p_scale);
typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
@@ -148,6 +149,7 @@ public:
static ImageMemLoadFunc _webp_mem_loader_func;
static ImageMemLoadFunc _tga_mem_loader_func;
static ImageMemLoadFunc _bmp_mem_loader_func;
+ static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func;
static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels);
static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels);
@@ -401,6 +403,9 @@ public:
Error load_tga_from_buffer(const Vector<uint8_t> &p_array);
Error load_bmp_from_buffer(const Vector<uint8_t> &p_array);
+ Error load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale = 1.0);
+ Error load_svg_from_string(const String &p_svg_str, float scale = 1.0);
+
void convert_rg_to_ra_rgba8();
void convert_ra_rgba8_to_rg();
void convert_rgba8_to_bgra8();
diff --git a/core/io/json.cpp b/core/io/json.cpp
index a6e054a9fe..496400a5ea 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -299,9 +299,15 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to
}
} break;
- default: {
+ case '"':
+ case '\\':
+ case '/': {
res = next;
} break;
+ default: {
+ r_err_str = "Invalid escape sequence.";
+ return ERR_PARSE_ERROR;
+ }
}
str += res;
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 6b8ec8d5f6..07677337b4 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -147,15 +147,28 @@ bool Resource::editor_can_reload_from_file() {
return true; //by default yes
}
+void Resource::connect_changed(const Callable &p_callable, uint32_t p_flags) {
+ if (!is_connected(CoreStringNames::get_singleton()->changed, p_callable) || p_flags & CONNECT_REFERENCE_COUNTED) {
+ connect(CoreStringNames::get_singleton()->changed, p_callable, p_flags);
+ }
+}
+
+void Resource::disconnect_changed(const Callable &p_callable) {
+ if (is_connected(CoreStringNames::get_singleton()->changed, p_callable)) {
+ disconnect(CoreStringNames::get_singleton()->changed, p_callable);
+ }
+}
+
void Resource::reset_state() {
}
+
Error Resource::copy_from(const Ref<Resource> &p_resource) {
ERR_FAIL_COND_V(p_resource.is_null(), ERR_INVALID_PARAMETER);
if (get_class() != p_resource->get_class()) {
return ERR_INVALID_PARAMETER;
}
- reset_state(); //may want to reset state
+ reset_state(); // May want to reset state.
List<PropertyInfo> pi;
p_resource->get_property_list(&pi);
@@ -322,23 +335,6 @@ RID Resource::get_rid() const {
return RID();
}
-void Resource::register_owner(Object *p_owner) {
- owners.insert(p_owner->get_instance_id());
-}
-
-void Resource::unregister_owner(Object *p_owner) {
- owners.erase(p_owner->get_instance_id());
-}
-
-void Resource::notify_change_to_owners() {
- for (const ObjectID &E : owners) {
- Object *obj = ObjectDB::get_instance(E);
- ERR_CONTINUE_MSG(!obj, "Object was deleted, while still owning a resource."); //wtf
- //TODO store string
- obj->call("resource_changed", Ref<Resource>(this));
- }
-}
-
#ifdef TOOLS_ENABLED
uint32_t Resource::hash_edited_version() const {
@@ -443,6 +439,7 @@ void Resource::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_local_to_scene"), &Resource::is_local_to_scene);
ClassDB::bind_method(D_METHOD("get_local_scene"), &Resource::get_local_scene);
ClassDB::bind_method(D_METHOD("setup_local_to_scene"), &Resource::setup_local_to_scene);
+
ClassDB::bind_method(D_METHOD("emit_changed"), &Resource::emit_changed);
ClassDB::bind_method(D_METHOD("duplicate", "subresources"), &Resource::duplicate, DEFVAL(false));
@@ -469,9 +466,6 @@ Resource::~Resource() {
ResourceCache::resources.erase(path_cache);
ResourceCache::lock.unlock();
}
- if (owners.size()) {
- WARN_PRINT("Resource is still owned.");
- }
}
HashMap<String, Resource *> ResourceCache::resources;
diff --git a/core/io/resource.h b/core/io/resource.h
index 5135664f36..af8c275a1c 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -54,8 +54,6 @@ public:
virtual String get_base_extension() const { return "res"; }
private:
- HashSet<ObjectID> owners;
-
friend class ResBase;
friend class ResourceCache;
@@ -76,10 +74,6 @@ private:
SelfList<Resource> remapped_list;
protected:
- void emit_changed();
-
- void notify_change_to_owners();
-
virtual void _resource_path_changed();
static void _bind_methods();
@@ -96,8 +90,9 @@ public:
virtual Error copy_from(const Ref<Resource> &p_resource);
virtual void reload_from_file();
- void register_owner(Object *p_owner);
- void unregister_owner(Object *p_owner);
+ void emit_changed();
+ void connect_changed(const Callable &p_callable, uint32_t p_flags = 0);
+ void disconnect_changed(const Callable &p_callable);
void set_name(const String &p_name);
String get_name() const;
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 2a7a675f2d..551d3268b8 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1775,9 +1775,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V
case Variant::OBJECT: {
f->store_32(VARIANT_OBJECT);
Ref<Resource> res = p_property;
- if (res.is_null()) {
+ if (res.is_null() || res->get_meta(SNAME("_skip_save_"), false)) {
f->store_32(OBJECT_EMPTY);
- return; // don't save it
+ return; // Don't save it.
}
if (!res->is_built_in()) {
@@ -1942,7 +1942,7 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
case Variant::OBJECT: {
Ref<Resource> res = p_variant;
- if (res.is_null() || external_resources.has(res)) {
+ if (res.is_null() || external_resources.has(res) || res->get_meta(SNAME("_skip_save_"), false)) {
return;
}
@@ -1960,6 +1960,8 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
return;
}
+ resource_set.insert(res);
+
List<PropertyInfo> property_list;
res->get_property_list(&property_list);
@@ -1968,14 +1970,17 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
if (E.usage & PROPERTY_USAGE_STORAGE) {
Variant value = res->get(E.name);
if (E.usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) {
+ NonPersistentKey npk;
+ npk.base = res;
+ npk.property = E.name;
+ non_persistent_map[npk] = value;
+
Ref<Resource> sres = value;
if (sres.is_valid()) {
- NonPersistentKey npk;
- npk.base = res;
- npk.property = E.name;
- non_persistent_map[npk] = sres;
resource_set.insert(sres);
saved_resources.push_back(sres);
+ } else {
+ _find_resources(value);
}
} else {
_find_resources(value);
@@ -1983,7 +1988,6 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
}
}
- resource_set.insert(res);
saved_resources.push_back(res);
} break;
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 30f1664983..e64485d404 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -139,7 +139,7 @@ class ResourceFormatSaverBinaryInstance {
bool operator<(const NonPersistentKey &p_key) const { return base == p_key.base ? property < p_key.property : base < p_key.base; }
};
- RBMap<NonPersistentKey, Ref<Resource>> non_persistent_map;
+ RBMap<NonPersistentKey, Variant> non_persistent_map;
HashMap<StringName, int> string_map;
Vector<StringName> strings;
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index dc1de6b9ce..fcf4a727ca 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -394,6 +394,15 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_name(const String
return Ref<ResourceImporter>();
}
+void ResourceFormatImporter::add_importer(const Ref<ResourceImporter> &p_importer, bool p_first_priority) {
+ ERR_FAIL_COND(p_importer.is_null());
+ if (p_first_priority) {
+ importers.insert(0, p_importer);
+ } else {
+ importers.push_back(p_importer);
+ }
+}
+
void ResourceFormatImporter::get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter>> *r_importers) {
for (int i = 0; i < importers.size(); i++) {
List<String> local_exts;
@@ -472,20 +481,13 @@ ResourceFormatImporter::ResourceFormatImporter() {
singleton = this;
}
+//////////////
+
void ResourceImporter::_bind_methods() {
BIND_ENUM_CONSTANT(IMPORT_ORDER_DEFAULT);
BIND_ENUM_CONSTANT(IMPORT_ORDER_SCENE);
}
-void ResourceFormatImporter::add_importer(const Ref<ResourceImporter> &p_importer, bool p_first_priority) {
- ERR_FAIL_COND(p_importer.is_null());
- if (p_first_priority) {
- importers.insert(0, p_importer);
- } else {
- importers.push_back(p_importer);
- }
-}
-
/////
Error ResourceFormatImporterSaver::set_uid(const String &p_path, ResourceUID::ID p_uid) {
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 525c41cf87..1fe662b1fa 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -239,15 +239,15 @@ ResourceLoader::LoadToken::~LoadToken() {
Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
load_nesting++;
- if (load_paths_stack.size()) {
+ if (load_paths_stack->size()) {
thread_load_mutex.lock();
- HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(load_paths_stack[load_paths_stack.size() - 1]);
+ HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(load_paths_stack->get(load_paths_stack->size() - 1));
if (E) {
E->value.sub_tasks.insert(p_path);
}
thread_load_mutex.unlock();
}
- load_paths_stack.push_back(p_path);
+ load_paths_stack->push_back(p_path);
// Try all loaders and pick the first match for the type hint
bool found = false;
@@ -263,7 +263,7 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
}
}
- load_paths_stack.resize(load_paths_stack.size() - 1);
+ load_paths_stack->resize(load_paths_stack->size() - 1);
load_nesting--;
if (!res.is_null()) {
@@ -296,8 +296,10 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
// Thread-safe either if it's the current thread or a brand new one.
CallQueue *mq_override = nullptr;
if (load_nesting == 0) {
+ load_paths_stack = memnew(Vector<String>);
+
if (!load_task.dependent_path.is_empty()) {
- load_paths_stack.push_back(load_task.dependent_path);
+ load_paths_stack->push_back(load_task.dependent_path);
}
if (!Thread::is_main_thread()) {
mq_override = memnew(CallQueue);
@@ -309,6 +311,10 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
}
// --
+ if (!Thread::is_main_thread()) {
+ set_current_thread_safe_for_nodes(true);
+ }
+
Ref<Resource> res = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_task.error, load_task.use_sub_threads, &load_task.progress);
if (mq_override) {
mq_override->flush();
@@ -356,8 +362,11 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
thread_load_mutex.unlock();
- if (load_nesting == 0 && mq_override) {
- memdelete(mq_override);
+ if (load_nesting == 0) {
+ if (mq_override) {
+ memdelete(mq_override);
+ }
+ memdelete(load_paths_stack);
}
}
@@ -1166,7 +1175,7 @@ bool ResourceLoader::timestamp_on_load = false;
thread_local int ResourceLoader::load_nesting = 0;
thread_local WorkerThreadPool::TaskID ResourceLoader::caller_task_id = 0;
-thread_local Vector<String> ResourceLoader::load_paths_stack;
+thread_local Vector<String> *ResourceLoader::load_paths_stack;
template <>
thread_local uint32_t SafeBinaryMutex<ResourceLoader::BINARY_MUTEX_TAG>::count = 0;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 592befb603..2701caa3f4 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -182,7 +182,7 @@ private:
static thread_local int load_nesting;
static thread_local WorkerThreadPool::TaskID caller_task_id;
- static thread_local Vector<String> load_paths_stack;
+ static thread_local Vector<String> *load_paths_stack; // A pointer to avoid broken TLS implementations from double-running the destructor.
static SafeBinaryMutex<BINARY_MUTEX_TAG> thread_load_mutex;
static HashMap<String, ThreadLoadTask> thread_load_tasks;
static bool cleaning_tasks;
diff --git a/core/object/callable_method_pointer.cpp b/core/object/callable_method_pointer.cpp
index b53985e6b7..ed400788b1 100644
--- a/core/object/callable_method_pointer.cpp
+++ b/core/object/callable_method_pointer.cpp
@@ -38,13 +38,10 @@ bool CallableCustomMethodPointerBase::compare_equal(const CallableCustom *p_a, c
return false;
}
- for (uint32_t i = 0; i < a->comp_size; i++) {
- if (a->comp_ptr[i] != b->comp_ptr[i]) {
- return false;
- }
- }
-
- return true;
+ // Avoid sorting by memory address proximity, which leads to unpredictable performance over time
+ // due to the reuse of old addresses for newer objects. Use byte-wise comparison to leverage the
+ // backwards encoding of little-endian systems as a way to decouple spatiality and time.
+ return memcmp(a->comp_ptr, b->comp_ptr, a->comp_size * 4) == 0;
}
bool CallableCustomMethodPointerBase::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -55,15 +52,8 @@ bool CallableCustomMethodPointerBase::compare_less(const CallableCustom *p_a, co
return a->comp_size < b->comp_size;
}
- for (uint32_t i = 0; i < a->comp_size; i++) {
- if (a->comp_ptr[i] == b->comp_ptr[i]) {
- continue;
- }
-
- return a->comp_ptr[i] < b->comp_ptr[i];
- }
-
- return false;
+ // See note in compare_equal().
+ return memcmp(a->comp_ptr, b->comp_ptr, a->comp_size * 4) < 0;
}
CallableCustom::CompareEqualFunc CallableCustomMethodPointerBase::get_compare_equal_func() const {
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index cc4a29164d..c8c50fb957 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -53,7 +53,7 @@ MethodDefinition D_METHODP(const char *p_name, const char *const **p_args, uint3
#endif
ClassDB::APIType ClassDB::current_api = API_CORE;
-HashMap<ClassDB::APIType, uint64_t> ClassDB::api_hashes_cache;
+HashMap<ClassDB::APIType, uint32_t> ClassDB::api_hashes_cache;
void ClassDB::set_current_api(APIType p_api) {
DEV_ASSERT(!api_hashes_cache.has(p_api)); // This API type may not be suitable for caching of hash if it can change later.
@@ -163,7 +163,7 @@ ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) {
return ti->api;
}
-uint64_t ClassDB::get_api_hash(APIType p_api) {
+uint32_t ClassDB::get_api_hash(APIType p_api) {
OBJTYPE_RLOCK;
#ifdef DEBUG_METHODS_ENABLED
diff --git a/core/object/class_db.h b/core/object/class_db.h
index ce64336a45..3aae3b452e 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -155,7 +155,7 @@ public:
#endif
static APIType current_api;
- static HashMap<APIType, uint64_t> api_hashes_cache;
+ static HashMap<APIType, uint32_t> api_hashes_cache;
static void _add_class2(const StringName &p_class, const StringName &p_inherits);
@@ -246,7 +246,7 @@ public:
static APIType get_api_type(const StringName &p_class);
- static uint64_t get_api_hash(APIType p_api);
+ static uint32_t get_api_hash(APIType p_api);
template <typename>
struct member_function_traits;
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index 18ba5d5b30..506f8291eb 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -222,62 +222,66 @@ void CallQueue::_call_function(const Callable &p_callable, const Variant *p_args
}
}
-Error CallQueue::flush() {
- LOCK_MUTEX;
-
- // Thread overrides are not meant to be flushed, but appended to the main one.
- if (this == MessageQueue::thread_singleton) {
- if (pages.size() == 0) {
- return OK;
- }
+Error CallQueue::_transfer_messages_to_main_queue() {
+ if (pages.size() == 0) {
+ return OK;
+ }
- CallQueue *mq = MessageQueue::main_singleton;
- DEV_ASSERT(!mq->allocator_is_custom && !allocator_is_custom); // Transferring pages is only safe if using the same alloator parameters.
-
- mq->mutex.lock();
-
- // Here we're transferring the data from this queue to the main one.
- // However, it's very unlikely big amounts of messages will be queued here,
- // so PagedArray/Pool would be overkill. Also, in most cases the data will fit
- // an already existing page of the main queue.
-
- // Let's see if our first (likely only) page fits the current target queue page.
- uint32_t src_page = 0;
- {
- if (mq->pages_used) {
- uint32_t dst_page = mq->pages_used - 1;
- uint32_t dst_offset = mq->page_bytes[dst_page];
- if (dst_offset + page_bytes[0] < uint32_t(PAGE_SIZE_BYTES)) {
- memcpy(mq->pages[dst_page]->data + dst_offset, pages[0]->data, page_bytes[0]);
- mq->page_bytes[dst_page] += page_bytes[0];
- src_page++;
- }
+ CallQueue *mq = MessageQueue::main_singleton;
+ DEV_ASSERT(!mq->allocator_is_custom && !allocator_is_custom); // Transferring pages is only safe if using the same alloator parameters.
+
+ mq->mutex.lock();
+
+ // Here we're transferring the data from this queue to the main one.
+ // However, it's very unlikely big amounts of messages will be queued here,
+ // so PagedArray/Pool would be overkill. Also, in most cases the data will fit
+ // an already existing page of the main queue.
+
+ // Let's see if our first (likely only) page fits the current target queue page.
+ uint32_t src_page = 0;
+ {
+ if (mq->pages_used) {
+ uint32_t dst_page = mq->pages_used - 1;
+ uint32_t dst_offset = mq->page_bytes[dst_page];
+ if (dst_offset + page_bytes[0] < uint32_t(PAGE_SIZE_BYTES)) {
+ memcpy(mq->pages[dst_page]->data + dst_offset, pages[0]->data, page_bytes[0]);
+ mq->page_bytes[dst_page] += page_bytes[0];
+ src_page++;
}
}
+ }
- // Any other possibly existing source page needs to be added.
+ // Any other possibly existing source page needs to be added.
- if (mq->pages_used + (pages_used - src_page) > mq->max_pages) {
- ERR_PRINT("Failed appending thread queue. Message queue out of memory. " + mq->error_text);
- mq->statistics();
- mq->mutex.unlock();
- return ERR_OUT_OF_MEMORY;
- }
+ if (mq->pages_used + (pages_used - src_page) > mq->max_pages) {
+ ERR_PRINT("Failed appending thread queue. Message queue out of memory. " + mq->error_text);
+ mq->statistics();
+ mq->mutex.unlock();
+ return ERR_OUT_OF_MEMORY;
+ }
- for (; src_page < pages_used; src_page++) {
- mq->_add_page();
- memcpy(mq->pages[mq->pages_used - 1]->data, pages[src_page]->data, page_bytes[src_page]);
- mq->page_bytes[mq->pages_used - 1] = page_bytes[src_page];
- }
+ for (; src_page < pages_used; src_page++) {
+ mq->_add_page();
+ memcpy(mq->pages[mq->pages_used - 1]->data, pages[src_page]->data, page_bytes[src_page]);
+ mq->page_bytes[mq->pages_used - 1] = page_bytes[src_page];
+ }
- mq->mutex.unlock();
+ mq->mutex.unlock();
- page_bytes[0] = 0;
- pages_used = 1;
+ page_bytes[0] = 0;
+ pages_used = 1;
- return OK;
+ return OK;
+}
+
+Error CallQueue::flush() {
+ // Thread overrides are not meant to be flushed, but appended to the main one.
+ if (unlikely(this == MessageQueue::thread_singleton)) {
+ return _transfer_messages_to_main_queue();
}
+ LOCK_MUTEX;
+
if (pages.size() == 0) {
// Never allocated
UNLOCK_MUTEX;
diff --git a/core/object/message_queue.h b/core/object/message_queue.h
index 9f567e4dd0..c2f4ad1643 100644
--- a/core/object/message_queue.h
+++ b/core/object/message_queue.h
@@ -98,6 +98,8 @@ private:
}
}
+ Error _transfer_messages_to_main_queue();
+
void _add_page();
void _call_function(const Callable &p_callable, const Variant *p_args, int p_argcount, bool p_show_error);
diff --git a/core/object/object.cpp b/core/object/object.cpp
index c76188a2cd..4ae0ecdefd 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -486,19 +486,21 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
const ObjectGDExtension *current_extension = _extension;
while (current_extension) {
p_list->push_back(PropertyInfo(Variant::NIL, current_extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
+
ClassDB::get_property_list(current_extension->class_name, p_list, true, this);
- current_extension = current_extension->parent;
- }
- }
- if (_extension && _extension->get_property_list) {
- uint32_t pcount;
- const GDExtensionPropertyInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount);
- for (uint32_t i = 0; i < pcount; i++) {
- p_list->push_back(PropertyInfo(pinfo[i]));
- }
- if (_extension->free_property_list) {
- _extension->free_property_list(_extension_instance, pinfo);
+ if (current_extension->get_property_list) {
+ uint32_t pcount;
+ const GDExtensionPropertyInfo *pinfo = current_extension->get_property_list(_extension_instance, &pcount);
+ for (uint32_t i = 0; i < pcount; i++) {
+ p_list->push_back(PropertyInfo(pinfo[i]));
+ }
+ if (current_extension->free_property_list) {
+ current_extension->free_property_list(_extension_instance, pinfo);
+ }
+ }
+
+ current_extension = current_extension->parent;
}
}
@@ -836,14 +838,16 @@ void Object::set_script(const Variant &p_script) {
return;
}
+ Ref<Script> s = p_script;
+ ERR_FAIL_COND_MSG(s.is_null() && !p_script.is_null(), "Invalid parameter, it should be a reference to a valid script (or null).");
+
+ script = p_script;
+
if (script_instance) {
memdelete(script_instance);
script_instance = nullptr;
}
- script = p_script;
- Ref<Script> s = script;
-
if (!s.is_null()) {
if (s->can_instantiate()) {
OBJ_DEBUG_LOCK
diff --git a/core/object/object.h b/core/object/object.h
index a3e9d025ea..318dbf98de 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -430,6 +430,9 @@ protected:
_FORCE_INLINE_ static void (*_get_bind_methods())() { \
return &m_class::_bind_methods; \
} \
+ _FORCE_INLINE_ static void (*_get_bind_compatibility_methods())() { \
+ return &m_class::_bind_compatibility_methods; \
+ } \
\
public: \
static void initialize_class() { \
@@ -442,6 +445,9 @@ public:
if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \
_bind_methods(); \
} \
+ if (m_class::_get_bind_compatibility_methods() != m_inherits::_get_bind_compatibility_methods()) { \
+ _bind_compatibility_methods(); \
+ } \
initialized = true; \
} \
\
@@ -674,6 +680,7 @@ protected:
virtual void _notificationv(int p_notification, bool p_reversed) {}
static void _bind_methods();
+ static void _bind_compatibility_methods() {}
bool _set(const StringName &p_name, const Variant &p_property) { return false; };
bool _get(const StringName &p_name, Variant &r_property) const { return false; };
void _get_property_list(List<PropertyInfo> *p_list) const {};
@@ -685,6 +692,9 @@ protected:
_FORCE_INLINE_ static void (*_get_bind_methods())() {
return &Object::_bind_methods;
}
+ _FORCE_INLINE_ static void (*_get_bind_compatibility_methods())() {
+ return &Object::_bind_compatibility_methods;
+ }
_FORCE_INLINE_ bool (Object::*_get_get() const)(const StringName &p_name, Variant &r_ret) const {
return &Object::_get;
}
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 2b685c77a3..3ea6a6e4c3 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -263,6 +263,7 @@ public:
};
struct ScriptError {
+ String path;
int line = -1;
int column = -1;
String message;
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 2ee17867f2..389d8714f7 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -58,7 +58,7 @@ private:
TYPE_REFERENCE
} type;
- bool force_keep_in_merge_ends;
+ bool force_keep_in_merge_ends = false;
Ref<RefCounted> ref;
ObjectID object;
StringName name;
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index d285be3e70..5ec3e1a1a8 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -56,6 +56,8 @@ void WorkerThreadPool::_process_task(Task *p_task) {
Task *prev_low_prio_task = nullptr; // In case this is recursively called.
if (!use_native_low_priority_threads) {
+ // Tasks must start with this unset. They are free to set-and-forget otherwise.
+ set_current_thread_safe_for_nodes(false);
pool_thread_index = thread_ids[Thread::get_caller_id()];
ThreadData &curr_thread = threads[pool_thread_index];
task_mutex.lock();
@@ -179,9 +181,6 @@ void WorkerThreadPool::_process_task(Task *p_task) {
if (post) {
task_available_semaphore.post();
}
-
- // Engine/user tasks can set-and-forget, so we must be sure it's back to normal by the end of the task.
- set_current_thread_safe_for_nodes(false);
}
}
@@ -371,7 +370,9 @@ Error WorkerThreadPool::wait_for_task_completion(TaskID p_task_id) {
must_exit = true;
} else {
// Solve tasks while they are around.
+ bool safe_for_nodes_backup = is_current_thread_safe_for_nodes();
_process_task_queue();
+ set_current_thread_safe_for_nodes(safe_for_nodes_backup);
continue;
}
} else if (!use_native_low_priority_threads && task->low_priority) {
@@ -415,7 +416,7 @@ Error WorkerThreadPool::wait_for_task_completion(TaskID p_task_id) {
WorkerThreadPool::GroupID WorkerThreadPool::_add_group_task(const Callable &p_callable, void (*p_func)(void *, uint32_t), void *p_userdata, BaseTemplateUserdata *p_template_userdata, int p_elements, int p_tasks, bool p_high_priority, const String &p_description) {
ERR_FAIL_COND_V(p_elements < 0, INVALID_TASK_ID);
if (p_tasks < 0) {
- p_tasks = threads.size();
+ p_tasks = MAX(1u, threads.size());
}
task_mutex.lock();
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index b908b64d73..5e21490164 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -52,15 +52,7 @@ void MainLoop::_bind_methods() {
GDVIRTUAL_BIND(_finalize);
}
-void MainLoop::set_initialize_script(const Ref<Script> &p_initialize_script) {
- initialize_script = p_initialize_script;
-}
-
void MainLoop::initialize() {
- if (initialize_script.is_valid()) {
- set_script(initialize_script);
- }
-
GDVIRTUAL_CALL(_initialize);
}
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index 36eeb35aad..90cad009b1 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -39,8 +39,6 @@
class MainLoop : public Object {
GDCLASS(MainLoop, Object);
- Ref<Script> initialize_script;
-
protected:
static void _bind_methods();
@@ -69,8 +67,6 @@ public:
virtual bool process(double p_time);
virtual void finalize();
- void set_initialize_script(const Ref<Script> &p_initialize_script);
-
MainLoop() {}
virtual ~MainLoop() {}
};
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 5704ef7a40..38ea4a0fdd 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -295,12 +295,14 @@ Error OS::shell_open(String p_uri) {
}
Error OS::shell_show_in_file_manager(String p_path, bool p_open_folder) {
- if (!p_path.begins_with("file://")) {
- p_path = String("file://") + p_path;
- }
- if (!p_path.ends_with("/")) {
+ p_path = p_path.trim_prefix("file://");
+
+ if (!DirAccess::dir_exists_absolute(p_path)) {
p_path = p_path.get_base_dir();
}
+
+ p_path = String("file://") + p_path;
+
return shell_open(p_path);
}
// implement these with the canvas?
@@ -503,6 +505,10 @@ bool OS::has_feature(const String &p_feature) {
return false;
}
+bool OS::is_sandboxed() const {
+ return false;
+}
+
void OS::set_restart_on_exit(bool p_restart, const List<String> &p_restart_arguments) {
restart_on_exit = p_restart;
restart_commandline = p_restart_arguments;
diff --git a/core/os/os.h b/core/os/os.h
index f2787d6381..965dc1f912 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -295,6 +295,8 @@ public:
bool has_feature(const String &p_feature);
+ virtual bool is_sandboxed() const;
+
void set_has_server_feature_callback(HasServerFeatureCallback p_callback);
void set_restart_on_exit(bool p_restart, const List<String> &p_restart_arguments);
@@ -304,6 +306,7 @@ public:
virtual bool request_permission(const String &p_name) { return true; }
virtual bool request_permissions() { return true; }
virtual Vector<String> get_granted_permissions() const { return Vector<String>(); }
+ virtual void revoke_granted_permissions() {}
// For recording / measuring benchmark data. Only enabled with tools
void set_use_benchmark(bool p_use_benchmark);
diff --git a/core/string/print_string.cpp b/core/string/print_string.cpp
index 7b90710308..dcdde3c175 100644
--- a/core/string/print_string.cpp
+++ b/core/string/print_string.cpp
@@ -164,6 +164,8 @@ void __print_line_rich(String p_string) {
p_string_ansi = p_string_ansi.replace("[/fgcolor]", "\u001b[39;49m");
}
+ p_string_ansi += "\u001b[0m"; // Reset.
+
OS::get_singleton()->print_rich("%s\n", p_string_ansi.utf8().get_data());
_global_lock();
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 3ca2e5ccdf..02380c92bb 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -82,6 +82,15 @@ void Translation::_set_messages(const Dictionary &p_messages) {
void Translation::set_locale(const String &p_locale) {
locale = TranslationServer::get_singleton()->standardize_locale(p_locale);
+ if (Thread::is_main_thread()) {
+ _notify_translation_changed_if_applies();
+ } else {
+ // Avoid calling non-thread-safe functions here.
+ callable_mp(this, &Translation::_notify_translation_changed_if_applies).call_deferred();
+ }
+}
+
+void Translation::_notify_translation_changed_if_applies() {
if (OS::get_singleton()->get_main_loop() && TranslationServer::get_singleton()->get_loaded_locales().has(get_locale())) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
}
diff --git a/core/string/translation.h b/core/string/translation.h
index 01d239f81c..ca8b460312 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -47,6 +47,8 @@ class Translation : public Resource {
virtual Dictionary _get_messages() const;
virtual void _set_messages(const Dictionary &p_messages);
+ void _notify_translation_changed_if_applies();
+
protected:
static void _bind_methods();
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 49c7ead423..12e6423724 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -4281,12 +4281,13 @@ String String::pad_zeros(int p_digits) const {
begin++;
}
- if (begin >= end) {
+ int zeros_to_add = p_digits - (end - begin);
+
+ if (zeros_to_add <= 0) {
return s;
+ } else {
+ return s.insert(begin, String("0").repeat(zeros_to_add));
}
-
- int zeros_to_add = p_digits - (end - begin);
- return s.insert(begin, String("0").repeat(zeros_to_add));
}
String String::trim_prefix(const String &p_prefix) const {
diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h
index 4da73f1cfb..e1745110d7 100644
--- a/core/templates/hash_map.h
+++ b/core/templates/hash_map.h
@@ -353,6 +353,40 @@ public:
return true;
}
+ // Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration.
+ // p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key.
+ bool replace_key(const TKey &p_old_key, const TKey &p_new_key) {
+ if (p_old_key == p_new_key) {
+ return true;
+ }
+ uint32_t pos = 0;
+ ERR_FAIL_COND_V(_lookup_pos(p_new_key, pos), false);
+ ERR_FAIL_COND_V(!_lookup_pos(p_old_key, pos), false);
+ HashMapElement<TKey, TValue> *element = elements[pos];
+
+ // Delete the old entries in hashes and elements.
+ const uint32_t capacity = hash_table_size_primes[capacity_index];
+ const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
+ uint32_t next_pos = fastmod((pos + 1), capacity_inv, capacity);
+ while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) {
+ SWAP(hashes[next_pos], hashes[pos]);
+ SWAP(elements[next_pos], elements[pos]);
+ pos = next_pos;
+ next_pos = fastmod((pos + 1), capacity_inv, capacity);
+ }
+ hashes[pos] = EMPTY_HASH;
+ elements[pos] = nullptr;
+ // _insert_with_hash will increment this again.
+ num_elements--;
+
+ // Update the HashMapElement with the new key and reinsert it.
+ const_cast<TKey &>(element->data.key) = p_new_key;
+ uint32_t hash = _hash(p_new_key);
+ _insert_with_hash(hash, element);
+
+ return true;
+ }
+
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
void reserve(uint32_t p_new_capacity) {
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 5215142dd3..5a0ded6c01 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -454,17 +454,21 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
const int s = size();
- int begin = CLAMP(p_begin, -s, s);
+ if (s == 0 || (p_begin < -s && p_step < 0) || (p_begin >= s && p_step > 0)) {
+ return result;
+ }
+
+ int begin = CLAMP(p_begin, -s, s - 1);
if (begin < 0) {
begin += s;
}
- int end = CLAMP(p_end, -s, s);
+ int end = CLAMP(p_end, -s - 1, s);
if (end < 0) {
end += s;
}
- ERR_FAIL_COND_V_MSG(p_step > 0 && begin > end, result, "Slice is positive, but bounds is decreasing.");
- ERR_FAIL_COND_V_MSG(p_step < 0 && begin < end, result, "Slice is negative, but bounds is increasing.");
+ ERR_FAIL_COND_V_MSG(p_step > 0 && begin > end, result, "Slice step is positive, but bounds are decreasing.");
+ ERR_FAIL_COND_V_MSG(p_step < 0 && begin < end, result, "Slice step is negative, but bounds are increasing.");
int result_size = (end - begin) / p_step + (((end - begin) % p_step != 0) ? 1 : 0);
result.resize(result_size);
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
index 378d1ff618..e493e50467 100644
--- a/core/variant/callable_bind.cpp
+++ b/core/variant/callable_bind.cpp
@@ -144,6 +144,18 @@ void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Varia
callable.callp(args, p_argcount + binds.size(), r_return_value, r_call_error);
}
+Error CallableCustomBind::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
+ const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * (binds.size() + p_argcount));
+ for (int i = 0; i < p_argcount; i++) {
+ args[i] = (const Variant *)p_arguments[i];
+ }
+ for (int i = 0; i < binds.size(); i++) {
+ args[i + p_argcount] = (const Variant *)&binds[i];
+ }
+
+ return callable.rpcp(p_peer_id, args, p_argcount + binds.size(), r_call_error);
+}
+
CallableCustomBind::CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds) {
callable = p_callable;
binds = p_binds;
@@ -242,6 +254,16 @@ void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Var
callable.callp(p_arguments, p_argcount - argcount, r_return_value, r_call_error);
}
+Error CallableCustomUnbind::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
+ if (argcount > p_argcount) {
+ r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_call_error.argument = 0;
+ r_call_error.expected = argcount;
+ return ERR_UNCONFIGURED;
+ }
+ return callable.rpcp(p_peer_id, p_arguments, p_argcount - argcount, r_call_error);
+}
+
CallableCustomUnbind::CallableCustomUnbind(const Callable &p_callable, int p_argcount) {
callable = p_callable;
argcount = p_argcount;
diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h
index b51076ad0f..5798797a3d 100644
--- a/core/variant/callable_bind.h
+++ b/core/variant/callable_bind.h
@@ -51,6 +51,7 @@ public:
virtual StringName get_method() const override;
virtual ObjectID get_object() const override;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
+ virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
virtual const Callable *get_base_comparator() const override;
virtual int get_bound_arguments_count() const override;
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
@@ -78,6 +79,7 @@ public:
virtual StringName get_method() const override;
virtual ObjectID get_object() const override;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
+ virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
virtual const Callable *get_base_comparator() const override;
virtual int get_bound_arguments_count() const override;
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h
index ea811daabf..9199b12845 100644
--- a/core/variant/native_ptr.h
+++ b/core/variant/native_ptr.h
@@ -53,36 +53,46 @@ struct GDExtensionPtr {
operator Variant() const { return uint64_t(data); }
};
-#define GDVIRTUAL_NATIVE_PTR(m_type) \
- template <> \
- struct GDExtensionConstPtr<const m_type> { \
- const m_type *data = nullptr; \
- GDExtensionConstPtr() {} \
- GDExtensionConstPtr(const m_type *p_assign) { data = p_assign; } \
- static const char *get_name() { return "const " #m_type; } \
- operator const m_type *() const { return data; } \
- operator Variant() const { return uint64_t(data); } \
- }; \
- template <> \
- struct VariantCaster<GDExtensionConstPtr<const m_type>> { \
- static _FORCE_INLINE_ GDExtensionConstPtr<const m_type> cast(const Variant &p_variant) { \
- return GDExtensionConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \
- } \
- }; \
- template <> \
- struct GDExtensionPtr<m_type> { \
- m_type *data = nullptr; \
- GDExtensionPtr() {} \
- GDExtensionPtr(m_type *p_assign) { data = p_assign; } \
- static const char *get_name() { return #m_type; } \
- operator m_type *() const { return data; } \
- operator Variant() const { return uint64_t(data); } \
- }; \
- template <> \
- struct VariantCaster<GDExtensionPtr<m_type>> { \
- static _FORCE_INLINE_ GDExtensionPtr<m_type> cast(const Variant &p_variant) { \
- return GDExtensionPtr<m_type>((m_type *)p_variant.operator uint64_t()); \
- } \
+#define GDVIRTUAL_NATIVE_PTR(m_type) \
+ template <> \
+ struct GDExtensionConstPtr<const m_type> { \
+ const m_type *data = nullptr; \
+ GDExtensionConstPtr() {} \
+ GDExtensionConstPtr(const m_type *p_assign) { data = p_assign; } \
+ static const char *get_name() { return "const " #m_type; } \
+ operator const m_type *() const { return data; } \
+ operator Variant() const { return uint64_t(data); } \
+ }; \
+ template <> \
+ struct VariantCaster<GDExtensionConstPtr<const m_type>> { \
+ static _FORCE_INLINE_ GDExtensionConstPtr<const m_type> cast(const Variant &p_variant) { \
+ return GDExtensionConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \
+ } \
+ }; \
+ template <> \
+ struct VariantInternalAccessor<GDExtensionConstPtr<const m_type>> { \
+ static _FORCE_INLINE_ const GDExtensionConstPtr<const m_type> &get(const Variant *v) { return *reinterpret_cast<const GDExtensionConstPtr<const m_type> *>(VariantInternal::get_int(v)); } \
+ static _FORCE_INLINE_ void set(Variant *v, const GDExtensionConstPtr<const m_type> &p_value) { *VariantInternal::get_int(v) = uint64_t(p_value.data); } \
+ }; \
+ template <> \
+ struct GDExtensionPtr<m_type> { \
+ m_type *data = nullptr; \
+ GDExtensionPtr() {} \
+ GDExtensionPtr(m_type *p_assign) { data = p_assign; } \
+ static const char *get_name() { return #m_type; } \
+ operator m_type *() const { return data; } \
+ operator Variant() const { return uint64_t(data); } \
+ }; \
+ template <> \
+ struct VariantCaster<GDExtensionPtr<m_type>> { \
+ static _FORCE_INLINE_ GDExtensionPtr<m_type> cast(const Variant &p_variant) { \
+ return GDExtensionPtr<m_type>((m_type *)p_variant.operator uint64_t()); \
+ } \
+ }; \
+ template <> \
+ struct VariantInternalAccessor<GDExtensionPtr<m_type>> { \
+ static _FORCE_INLINE_ const GDExtensionPtr<m_type> &get(const Variant *v) { return *reinterpret_cast<const GDExtensionPtr<m_type> *>(VariantInternal::get_int(v)); } \
+ static _FORCE_INLINE_ void set(Variant *v, const GDExtensionPtr<m_type> &p_value) { *VariantInternal::get_int(v) = uint64_t(p_value.data); } \
};
template <class T>
diff --git a/doc/class.xsd b/doc/class.xsd
index 83880ed5f9..22821ac767 100644
--- a/doc/class.xsd
+++ b/doc/class.xsd
@@ -273,7 +273,6 @@
<xs:attribute type="xs:string" name="inherits" />
<xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
<xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
- <xs:attribute type="xs:float" name="version" />
</xs:complexType>
</xs:element>
</xs:schema>
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 0bdcfb79d0..9d597d8e23 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="@GlobalScope" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="@GlobalScope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Global scope constants and functions.
</brief_description>
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index 415eb9d682..0aa493361d 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AABB" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AABB" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D axis-aligned bounding box.
</brief_description>
diff --git a/doc/classes/AESContext.xml b/doc/classes/AESContext.xml
index 52158fcd3e..8c48edce86 100644
--- a/doc/classes/AESContext.xml
+++ b/doc/classes/AESContext.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AESContext" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AESContext" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides access to AES encryption/decryption of raw data.
</brief_description>
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index 8f6a6eeebc..f10e80e048 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AStar2D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AStar2D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An implementation of A* for finding the shortest path between two vertices on a connected graph in 2D space.
</brief_description>
diff --git a/doc/classes/AStar3D.xml b/doc/classes/AStar3D.xml
index 489f8e38be..d35835d73d 100644
--- a/doc/classes/AStar3D.xml
+++ b/doc/classes/AStar3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AStar3D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AStar3D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An implementation of A* for finding the shortest path between two vertices on a connected graph in 3D space.
</brief_description>
diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml
index 418a57dfa4..5d54af60ec 100644
--- a/doc/classes/AStarGrid2D.xml
+++ b/doc/classes/AStarGrid2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AStarGrid2D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AStarGrid2D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An implementation of A* for finding the shortest path between two points on a partial 2D grid.
</brief_description>
@@ -17,7 +17,7 @@
[/gdscript]
[csharp]
AStarGrid2D astarGrid = new AStarGrid2D();
- astarGrid.Size = new Vector2I(32, 32);
+ astarGrid.Region = new Rect2I(0, 0, 32, 32);
astarGrid.CellSize = new Vector2I(16, 16);
astarGrid.Update();
GD.Print(astarGrid.GetIdPath(Vector2I.Zero, new Vector2I(3, 4))); // prints (0, 0), (1, 1), (2, 2), (3, 3), (3, 4)
diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml
index 633657807b..202a84fb58 100644
--- a/doc/classes/AcceptDialog.xml
+++ b/doc/classes/AcceptDialog.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AcceptDialog" inherits="Window" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AcceptDialog" inherits="Window" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A base dialog used for user notification.
</brief_description>
diff --git a/doc/classes/AnimatableBody2D.xml b/doc/classes/AnimatableBody2D.xml
index 2a0f831fe6..b6723a9cfb 100644
--- a/doc/classes/AnimatableBody2D.xml
+++ b/doc/classes/AnimatableBody2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimatableBody2D" inherits="StaticBody2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimatableBody2D" inherits="StaticBody2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D physics body that can't be moved by external forces. When moved manually, it affects other bodies in its path.
</brief_description>
diff --git a/doc/classes/AnimatableBody3D.xml b/doc/classes/AnimatableBody3D.xml
index a8b88ab77b..1264a6ad03 100644
--- a/doc/classes/AnimatableBody3D.xml
+++ b/doc/classes/AnimatableBody3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimatableBody3D" inherits="StaticBody3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimatableBody3D" inherits="StaticBody3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D physics body that can't be moved by external forces. When moved manually, it affects other bodies in its path.
</brief_description>
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index 685913e115..d4f840cfa7 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimatedSprite2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimatedSprite2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Sprite node that contains multiple textures as frames to play for animation.
</brief_description>
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index cc007e5227..ff4bf97122 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimatedSprite3D" inherits="SpriteBase3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimatedSprite3D" inherits="SpriteBase3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
2D sprite node in 3D world, that can use multiple 2D textures for animation.
</brief_description>
diff --git a/doc/classes/AnimatedTexture.xml b/doc/classes/AnimatedTexture.xml
index 63c62e1beb..a5cacff987 100644
--- a/doc/classes/AnimatedTexture.xml
+++ b/doc/classes/AnimatedTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimatedTexture" inherits="Texture2D" is_deprecated="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimatedTexture" inherits="Texture2D" is_deprecated="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Proxy texture for simple frame-based animations.
</brief_description>
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index 3e94f3d0bd..d2b2c1fe47 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Animation" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Animation" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds data that can be used to animate anything in the engine.
</brief_description>
diff --git a/doc/classes/AnimationLibrary.xml b/doc/classes/AnimationLibrary.xml
index d5b3f63dc5..d457a858ab 100644
--- a/doc/classes/AnimationLibrary.xml
+++ b/doc/classes/AnimationLibrary.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationLibrary" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationLibrary" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Container for [Animation] resources.
</brief_description>
diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml
index a86ec396ee..a028d0bb4f 100644
--- a/doc/classes/AnimationNode.xml
+++ b/doc/classes/AnimationNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNode" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNode" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for [AnimationTree] nodes. Not related to scene nodes.
</brief_description>
diff --git a/doc/classes/AnimationNodeAdd2.xml b/doc/classes/AnimationNodeAdd2.xml
index 3aaf772716..af7e18bdde 100644
--- a/doc/classes/AnimationNodeAdd2.xml
+++ b/doc/classes/AnimationNodeAdd2.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeAdd2" inherits="AnimationNodeSync" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeAdd2" inherits="AnimationNodeSync" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Blends two animations additively inside of an [AnimationNodeBlendTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeAdd3.xml b/doc/classes/AnimationNodeAdd3.xml
index 7048c2329c..12f00849cc 100644
--- a/doc/classes/AnimationNodeAdd3.xml
+++ b/doc/classes/AnimationNodeAdd3.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeAdd3" inherits="AnimationNodeSync" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeAdd3" inherits="AnimationNodeSync" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Blends two of three animations additively inside of an [AnimationNodeBlendTree].
</brief_description>
<description>
- A resource to add to an [AnimationNodeBlendTree]. Blends two animations out of three additively out of three based on the amounmt value.
+ A resource to add to an [AnimationNodeBlendTree]. Blends two animations out of three additively out of three based on the amount value.
This animation node has three inputs:
- The base animation to add to
- A "-add" animation to blend with when the blend amount is negative
diff --git a/doc/classes/AnimationNodeAnimation.xml b/doc/classes/AnimationNodeAnimation.xml
index ffefa89e35..d965d31b03 100644
--- a/doc/classes/AnimationNodeAnimation.xml
+++ b/doc/classes/AnimationNodeAnimation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeAnimation" inherits="AnimationRootNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeAnimation" inherits="AnimationRootNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An input animation for an [AnimationNodeBlendTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeBlend2.xml b/doc/classes/AnimationNodeBlend2.xml
index db27a7d87d..61df0b26b3 100644
--- a/doc/classes/AnimationNodeBlend2.xml
+++ b/doc/classes/AnimationNodeBlend2.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeBlend2" inherits="AnimationNodeSync" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeBlend2" inherits="AnimationNodeSync" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Blends two animations linearly inside of an [AnimationNodeBlendTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeBlend3.xml b/doc/classes/AnimationNodeBlend3.xml
index b7a5403238..2efe628c17 100644
--- a/doc/classes/AnimationNodeBlend3.xml
+++ b/doc/classes/AnimationNodeBlend3.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeBlend3" inherits="AnimationNodeSync" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeBlend3" inherits="AnimationNodeSync" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Blends two of three animations linearly inside of an [AnimationNodeBlendTree].
</brief_description>
<description>
- A resource to add to an [AnimationNodeBlendTree]. Blends two animations out of three linearly out of three based on the amounmt value.
+ A resource to add to an [AnimationNodeBlendTree]. Blends two animations out of three linearly out of three based on the amount value.
This animation node has three inputs:
- The base animation to blend with
- A "-blend" animation to blend with when the blend amount is negative value
diff --git a/doc/classes/AnimationNodeBlendSpace1D.xml b/doc/classes/AnimationNodeBlendSpace1D.xml
index 02f0053380..c13a7784f7 100644
--- a/doc/classes/AnimationNodeBlendSpace1D.xml
+++ b/doc/classes/AnimationNodeBlendSpace1D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeBlendSpace1D" inherits="AnimationRootNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeBlendSpace1D" inherits="AnimationRootNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A set of [AnimationRootNode]s placed on a virtual axis, crossfading between the two adjacent ones. Used by [AnimationTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeBlendSpace2D.xml b/doc/classes/AnimationNodeBlendSpace2D.xml
index 46606f12b0..47933a1fd0 100644
--- a/doc/classes/AnimationNodeBlendSpace2D.xml
+++ b/doc/classes/AnimationNodeBlendSpace2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeBlendSpace2D" inherits="AnimationRootNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeBlendSpace2D" inherits="AnimationRootNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A set of [AnimationRootNode]s placed on 2D coordinates, crossfading between the three adjacent ones. Used by [AnimationTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeBlendTree.xml b/doc/classes/AnimationNodeBlendTree.xml
index 4b3bf4c806..e1f0fe96df 100644
--- a/doc/classes/AnimationNodeBlendTree.xml
+++ b/doc/classes/AnimationNodeBlendTree.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeBlendTree" inherits="AnimationRootNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeBlendTree" inherits="AnimationRootNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A sub-tree of many type [AnimationNode]s used for complex animations. Used by [AnimationTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeOneShot.xml b/doc/classes/AnimationNodeOneShot.xml
index 85f45ffad8..ac7cf70133 100644
--- a/doc/classes/AnimationNodeOneShot.xml
+++ b/doc/classes/AnimationNodeOneShot.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeOneShot" inherits="AnimationNodeSync" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeOneShot" inherits="AnimationNodeSync" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plays an animation once in an [AnimationNodeBlendTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeOutput.xml b/doc/classes/AnimationNodeOutput.xml
index 0a9210ce37..f957650294 100644
--- a/doc/classes/AnimationNodeOutput.xml
+++ b/doc/classes/AnimationNodeOutput.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeOutput" inherits="AnimationNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeOutput" inherits="AnimationNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
The animation output node of an [AnimationNodeBlendTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml
index b2b9166c38..0a1a7df2f4 100644
--- a/doc/classes/AnimationNodeStateMachine.xml
+++ b/doc/classes/AnimationNodeStateMachine.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeStateMachine" inherits="AnimationRootNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeStateMachine" inherits="AnimationRootNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A state machine with multiple [AnimationRootNode]s, used by [AnimationTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeStateMachinePlayback.xml b/doc/classes/AnimationNodeStateMachinePlayback.xml
index 85dea7a4c2..943e6ed7d9 100644
--- a/doc/classes/AnimationNodeStateMachinePlayback.xml
+++ b/doc/classes/AnimationNodeStateMachinePlayback.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeStateMachinePlayback" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeStateMachinePlayback" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides playback control for an [AnimationNodeStateMachine].
</brief_description>
diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml
index 7bb615c148..7b7797f594 100644
--- a/doc/classes/AnimationNodeStateMachineTransition.xml
+++ b/doc/classes/AnimationNodeStateMachineTransition.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeStateMachineTransition" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeStateMachineTransition" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A transition within an [AnimationNodeStateMachine] connecting two [AnimationRootNode]s.
</brief_description>
diff --git a/doc/classes/AnimationNodeSub2.xml b/doc/classes/AnimationNodeSub2.xml
index f913526a23..6aac3280be 100644
--- a/doc/classes/AnimationNodeSub2.xml
+++ b/doc/classes/AnimationNodeSub2.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeSub2" inherits="AnimationNodeSync" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeSub2" inherits="AnimationNodeSync" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Blends two animations subtractively inside of an [AnimationNodeBlendTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeSync.xml b/doc/classes/AnimationNodeSync.xml
index 38f4069c7b..e9e1519672 100644
--- a/doc/classes/AnimationNodeSync.xml
+++ b/doc/classes/AnimationNodeSync.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeSync" inherits="AnimationNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeSync" inherits="AnimationNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for [AnimationNode]s with more than two input ports that must be synchronized.
</brief_description>
diff --git a/doc/classes/AnimationNodeTimeScale.xml b/doc/classes/AnimationNodeTimeScale.xml
index 65795823b3..d7d4814506 100644
--- a/doc/classes/AnimationNodeTimeScale.xml
+++ b/doc/classes/AnimationNodeTimeScale.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeTimeScale" inherits="AnimationNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeTimeScale" inherits="AnimationNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A time-scaling animation node used in [AnimationTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeTimeSeek.xml b/doc/classes/AnimationNodeTimeSeek.xml
index 053e2e0bb2..d00b3fca3a 100644
--- a/doc/classes/AnimationNodeTimeSeek.xml
+++ b/doc/classes/AnimationNodeTimeSeek.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeTimeSeek" inherits="AnimationNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeTimeSeek" inherits="AnimationNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A time-seeking animation node used in [AnimationTree].
</brief_description>
diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml
index 0d97f128ab..3e1a0a28b5 100644
--- a/doc/classes/AnimationNodeTransition.xml
+++ b/doc/classes/AnimationNodeTransition.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeTransition" inherits="AnimationNodeSync" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeTransition" inherits="AnimationNodeSync" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A transition within an [AnimationTree] connecting two [AnimationNode]s.
</brief_description>
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index 743bbb1b61..b7f384d004 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationPlayer" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationPlayer" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node used for animation playback.
</brief_description>
diff --git a/doc/classes/AnimationRootNode.xml b/doc/classes/AnimationRootNode.xml
index 82d4c38ded..b24f2acd9f 100644
--- a/doc/classes/AnimationRootNode.xml
+++ b/doc/classes/AnimationRootNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationRootNode" inherits="AnimationNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationRootNode" inherits="AnimationNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for [AnimationNode]s that hold one or multiple composite animations. Usually used for [member AnimationTree.tree_root].
</brief_description>
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index 54efb1741d..88d2d8f593 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationTree" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationTree" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node used for advanced animation transitions in an [AnimationPlayer].
</brief_description>
diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml
index e973cd9aae..6fa8e4ae9f 100644
--- a/doc/classes/Area2D.xml
+++ b/doc/classes/Area2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Area2D" inherits="CollisionObject2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Area2D" inherits="CollisionObject2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A region of 2D space that detects other [CollisionObject2D]s entering or exiting it.
</brief_description>
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index 4d1c8000c4..89b3f843af 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Area3D" inherits="CollisionObject3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Area3D" inherits="CollisionObject3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A region of 3D space that detects other [CollisionObject3D]s entering or exiting it.
</brief_description>
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index bed9768603..999cc6fa29 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Array" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Array" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A built-in data structure that holds a sequence of elements.
</brief_description>
@@ -584,6 +584,7 @@
If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
If specified, [param step] is the relative index between source elements. It can be negative, then [param begin] must be higher than [param end]. For example, [code][0, 1, 2, 3, 4, 5].slice(5, 1, -2)[/code] returns [code][5, 3][/code].
If [param deep] is true, each element will be copied by value rather than by reference.
+ [b]Note:[/b] To include the first element when [param step] is negative, use [code]arr.slice(begin, -arr.size() - 1, step)[/code] (i.e. [code][0, 1, 2].slice(1, -4, -1)[/code] returns [code][1, 0][/code]).
</description>
</method>
<method name="sort">
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index 6d2b05e729..dde7153d5f 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ArrayMesh" inherits="Mesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ArrayMesh" inherits="Mesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
[Mesh] type that provides utility for constructing a surface from arrays.
</brief_description>
diff --git a/doc/classes/ArrayOccluder3D.xml b/doc/classes/ArrayOccluder3D.xml
index 0210ffbc96..0e73d01847 100644
--- a/doc/classes/ArrayOccluder3D.xml
+++ b/doc/classes/ArrayOccluder3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ArrayOccluder3D" inherits="Occluder3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ArrayOccluder3D" inherits="Occluder3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
3D polygon shape for use with occlusion culling in [OccluderInstance3D].
</brief_description>
diff --git a/doc/classes/AspectRatioContainer.xml b/doc/classes/AspectRatioContainer.xml
index 0f4f7687b9..b2cc60827b 100644
--- a/doc/classes/AspectRatioContainer.xml
+++ b/doc/classes/AspectRatioContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AspectRatioContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AspectRatioContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that preserves the proportions of its child controls.
</brief_description>
diff --git a/doc/classes/AtlasTexture.xml b/doc/classes/AtlasTexture.xml
index 64e8b684ea..cea8e13f4c 100644
--- a/doc/classes/AtlasTexture.xml
+++ b/doc/classes/AtlasTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AtlasTexture" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AtlasTexture" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A texture that crops out part of another Texture2D.
</brief_description>
diff --git a/doc/classes/AudioBusLayout.xml b/doc/classes/AudioBusLayout.xml
index 91d11b8a01..73c893e549 100644
--- a/doc/classes/AudioBusLayout.xml
+++ b/doc/classes/AudioBusLayout.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioBusLayout" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioBusLayout" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Stores information about the audio buses.
</brief_description>
diff --git a/doc/classes/AudioEffect.xml b/doc/classes/AudioEffect.xml
index 3240d860c4..f0e8b4f19e 100644
--- a/doc/classes/AudioEffect.xml
+++ b/doc/classes/AudioEffect.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffect" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffect" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Audio effect for audio.
</brief_description>
diff --git a/doc/classes/AudioEffectAmplify.xml b/doc/classes/AudioEffectAmplify.xml
index e3f263b5a7..940231967b 100644
--- a/doc/classes/AudioEffectAmplify.xml
+++ b/doc/classes/AudioEffectAmplify.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectAmplify" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectAmplify" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds an amplifying audio effect to an audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectBandLimitFilter.xml b/doc/classes/AudioEffectBandLimitFilter.xml
index 40c920cdb2..c8667818ba 100644
--- a/doc/classes/AudioEffectBandLimitFilter.xml
+++ b/doc/classes/AudioEffectBandLimitFilter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectBandLimitFilter" inherits="AudioEffectFilter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectBandLimitFilter" inherits="AudioEffectFilter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a band limit filter to the audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectBandPassFilter.xml b/doc/classes/AudioEffectBandPassFilter.xml
index dca4777d4e..64bff53467 100644
--- a/doc/classes/AudioEffectBandPassFilter.xml
+++ b/doc/classes/AudioEffectBandPassFilter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectBandPassFilter" inherits="AudioEffectFilter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectBandPassFilter" inherits="AudioEffectFilter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a band pass filter to the audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectCapture.xml b/doc/classes/AudioEffectCapture.xml
index b5705d3d4c..275e5ab0b6 100644
--- a/doc/classes/AudioEffectCapture.xml
+++ b/doc/classes/AudioEffectCapture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectCapture" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectCapture" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Captures audio from an audio bus in real-time.
</brief_description>
diff --git a/doc/classes/AudioEffectChorus.xml b/doc/classes/AudioEffectChorus.xml
index 584160352b..f0c1d7c111 100644
--- a/doc/classes/AudioEffectChorus.xml
+++ b/doc/classes/AudioEffectChorus.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectChorus" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectChorus" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a chorus audio effect.
</brief_description>
diff --git a/doc/classes/AudioEffectCompressor.xml b/doc/classes/AudioEffectCompressor.xml
index 0e713db5bf..f73bd02894 100644
--- a/doc/classes/AudioEffectCompressor.xml
+++ b/doc/classes/AudioEffectCompressor.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectCompressor" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectCompressor" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a compressor audio effect to an audio bus.
Reduces sounds that exceed a certain threshold level, smooths out the dynamics and increases the overall volume.
diff --git a/doc/classes/AudioEffectDelay.xml b/doc/classes/AudioEffectDelay.xml
index 0764584042..fa255e3201 100644
--- a/doc/classes/AudioEffectDelay.xml
+++ b/doc/classes/AudioEffectDelay.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectDelay" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectDelay" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a delay audio effect to an audio bus. Plays input signal back after a period of time.
Two tap delay and feedback options.
diff --git a/doc/classes/AudioEffectDistortion.xml b/doc/classes/AudioEffectDistortion.xml
index ad4baa9778..f8c6804772 100644
--- a/doc/classes/AudioEffectDistortion.xml
+++ b/doc/classes/AudioEffectDistortion.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectDistortion" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectDistortion" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a distortion audio effect to an Audio bus.
Modifies the sound to make it distorted.
diff --git a/doc/classes/AudioEffectEQ.xml b/doc/classes/AudioEffectEQ.xml
index 4b674dd6bf..fb06ee2a54 100644
--- a/doc/classes/AudioEffectEQ.xml
+++ b/doc/classes/AudioEffectEQ.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectEQ" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectEQ" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for audio equalizers. Gives you control over frequencies.
Use it to create a custom equalizer if [AudioEffectEQ6], [AudioEffectEQ10] or [AudioEffectEQ21] don't fit your needs.
diff --git a/doc/classes/AudioEffectEQ10.xml b/doc/classes/AudioEffectEQ10.xml
index 66035379b2..b236ba7b02 100644
--- a/doc/classes/AudioEffectEQ10.xml
+++ b/doc/classes/AudioEffectEQ10.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectEQ10" inherits="AudioEffectEQ" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectEQ10" inherits="AudioEffectEQ" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a 10-band equalizer audio effect to an Audio bus. Gives you control over frequencies from 31 Hz to 16000 Hz.
Each frequency can be modulated between -60/+24 dB.
diff --git a/doc/classes/AudioEffectEQ21.xml b/doc/classes/AudioEffectEQ21.xml
index 27d5936bf1..41ceed1707 100644
--- a/doc/classes/AudioEffectEQ21.xml
+++ b/doc/classes/AudioEffectEQ21.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectEQ21" inherits="AudioEffectEQ" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectEQ21" inherits="AudioEffectEQ" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a 21-band equalizer audio effect to an Audio bus. Gives you control over frequencies from 22 Hz to 22000 Hz.
Each frequency can be modulated between -60/+24 dB.
diff --git a/doc/classes/AudioEffectEQ6.xml b/doc/classes/AudioEffectEQ6.xml
index 84340f993c..6e4a16ddf2 100644
--- a/doc/classes/AudioEffectEQ6.xml
+++ b/doc/classes/AudioEffectEQ6.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectEQ6" inherits="AudioEffectEQ" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectEQ6" inherits="AudioEffectEQ" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a 6-band equalizer audio effect to an audio bus. Gives you control over frequencies from 32 Hz to 10000 Hz.
Each frequency can be modulated between -60/+24 dB.
diff --git a/doc/classes/AudioEffectFilter.xml b/doc/classes/AudioEffectFilter.xml
index 981b9a61c2..e5c1f4ccf4 100644
--- a/doc/classes/AudioEffectFilter.xml
+++ b/doc/classes/AudioEffectFilter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectFilter" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectFilter" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a filter to the audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectHighPassFilter.xml b/doc/classes/AudioEffectHighPassFilter.xml
index b3146dd574..285b4c74a3 100644
--- a/doc/classes/AudioEffectHighPassFilter.xml
+++ b/doc/classes/AudioEffectHighPassFilter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectHighPassFilter" inherits="AudioEffectFilter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectHighPassFilter" inherits="AudioEffectFilter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a high-pass filter to the audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectHighShelfFilter.xml b/doc/classes/AudioEffectHighShelfFilter.xml
index fccc64d646..4645bf953c 100644
--- a/doc/classes/AudioEffectHighShelfFilter.xml
+++ b/doc/classes/AudioEffectHighShelfFilter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectHighShelfFilter" inherits="AudioEffectFilter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectHighShelfFilter" inherits="AudioEffectFilter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a high-shelf filter to the audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectInstance.xml b/doc/classes/AudioEffectInstance.xml
index d16b727ab5..3e868ae9da 100644
--- a/doc/classes/AudioEffectInstance.xml
+++ b/doc/classes/AudioEffectInstance.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectInstance" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectInstance" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/AudioEffectLimiter.xml b/doc/classes/AudioEffectLimiter.xml
index e2d222e1b6..57861d0485 100644
--- a/doc/classes/AudioEffectLimiter.xml
+++ b/doc/classes/AudioEffectLimiter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectLimiter" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectLimiter" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a soft-clip limiter audio effect to an Audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectLowPassFilter.xml b/doc/classes/AudioEffectLowPassFilter.xml
index 4ee6801659..eab5a04c15 100644
--- a/doc/classes/AudioEffectLowPassFilter.xml
+++ b/doc/classes/AudioEffectLowPassFilter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectLowPassFilter" inherits="AudioEffectFilter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectLowPassFilter" inherits="AudioEffectFilter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a low-pass filter to the audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectLowShelfFilter.xml b/doc/classes/AudioEffectLowShelfFilter.xml
index 35ccbd3bb0..1afc9ce310 100644
--- a/doc/classes/AudioEffectLowShelfFilter.xml
+++ b/doc/classes/AudioEffectLowShelfFilter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectLowShelfFilter" inherits="AudioEffectFilter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectLowShelfFilter" inherits="AudioEffectFilter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a low-shelf filter to the audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectNotchFilter.xml b/doc/classes/AudioEffectNotchFilter.xml
index 620ef9585d..de8edb34f2 100644
--- a/doc/classes/AudioEffectNotchFilter.xml
+++ b/doc/classes/AudioEffectNotchFilter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectNotchFilter" inherits="AudioEffectFilter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectNotchFilter" inherits="AudioEffectFilter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a notch filter to the Audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectPanner.xml b/doc/classes/AudioEffectPanner.xml
index 874bf6e172..22286dbfb1 100644
--- a/doc/classes/AudioEffectPanner.xml
+++ b/doc/classes/AudioEffectPanner.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectPanner" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectPanner" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a panner audio effect to an audio bus. Pans sound left or right.
</brief_description>
diff --git a/doc/classes/AudioEffectPhaser.xml b/doc/classes/AudioEffectPhaser.xml
index e7551d63e5..2057202cac 100644
--- a/doc/classes/AudioEffectPhaser.xml
+++ b/doc/classes/AudioEffectPhaser.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectPhaser" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectPhaser" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a phaser audio effect to an audio bus.
Combines the original signal with a copy that is slightly out of phase with the original.
diff --git a/doc/classes/AudioEffectPitchShift.xml b/doc/classes/AudioEffectPitchShift.xml
index e9cf868ca3..ec60e6a75a 100644
--- a/doc/classes/AudioEffectPitchShift.xml
+++ b/doc/classes/AudioEffectPitchShift.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectPitchShift" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectPitchShift" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a pitch-shifting audio effect to an audio bus.
Raises or lowers the pitch of original sound.
diff --git a/doc/classes/AudioEffectRecord.xml b/doc/classes/AudioEffectRecord.xml
index 80ad4b31c4..e07d66fa7b 100644
--- a/doc/classes/AudioEffectRecord.xml
+++ b/doc/classes/AudioEffectRecord.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectRecord" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectRecord" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Audio effect used for recording the sound from an audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectReverb.xml b/doc/classes/AudioEffectReverb.xml
index 5661ebc67c..2c055f3825 100644
--- a/doc/classes/AudioEffectReverb.xml
+++ b/doc/classes/AudioEffectReverb.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectReverb" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectReverb" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Adds a reverberation audio effect to an Audio bus.
</brief_description>
diff --git a/doc/classes/AudioEffectSpectrumAnalyzer.xml b/doc/classes/AudioEffectSpectrumAnalyzer.xml
index 9533cc81d9..eb70396433 100644
--- a/doc/classes/AudioEffectSpectrumAnalyzer.xml
+++ b/doc/classes/AudioEffectSpectrumAnalyzer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectSpectrumAnalyzer" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectSpectrumAnalyzer" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Audio effect that can be used for real-time audio visualizations.
</brief_description>
diff --git a/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml b/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml
index 39928e7613..e8c6394073 100644
--- a/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml
+++ b/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectSpectrumAnalyzerInstance" inherits="AudioEffectInstance" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectSpectrumAnalyzerInstance" inherits="AudioEffectInstance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/AudioEffectStereoEnhance.xml b/doc/classes/AudioEffectStereoEnhance.xml
index 3bfb7b902b..f009bec5bb 100644
--- a/doc/classes/AudioEffectStereoEnhance.xml
+++ b/doc/classes/AudioEffectStereoEnhance.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectStereoEnhance" inherits="AudioEffect" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioEffectStereoEnhance" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An audio effect that can be used to adjust the intensity of stereo panning.
</brief_description>
diff --git a/doc/classes/AudioListener2D.xml b/doc/classes/AudioListener2D.xml
index 804c258d4c..8328e82dbd 100644
--- a/doc/classes/AudioListener2D.xml
+++ b/doc/classes/AudioListener2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioListener2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioListener2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Overrides the location sounds are heard from.
</brief_description>
diff --git a/doc/classes/AudioListener3D.xml b/doc/classes/AudioListener3D.xml
index 75a5aa6062..a5fe0153c4 100644
--- a/doc/classes/AudioListener3D.xml
+++ b/doc/classes/AudioListener3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioListener3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioListener3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Overrides the location sounds are heard from.
</brief_description>
diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml
index d13511ee1c..20a87aea7b 100644
--- a/doc/classes/AudioServer.xml
+++ b/doc/classes/AudioServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioServer" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioServer" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Server interface for low-level audio access.
</brief_description>
diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml
index b2d6032063..12e09b235f 100644
--- a/doc/classes/AudioStream.xml
+++ b/doc/classes/AudioStream.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStream" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStream" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for audio streams.
</brief_description>
diff --git a/doc/classes/AudioStreamGenerator.xml b/doc/classes/AudioStreamGenerator.xml
index 7718cb78ea..6949a5d82b 100644
--- a/doc/classes/AudioStreamGenerator.xml
+++ b/doc/classes/AudioStreamGenerator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamGenerator" inherits="AudioStream" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamGenerator" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An audio stream with utilities for procedural sound generation.
</brief_description>
diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml
index f4c230c1eb..185b89d760 100644
--- a/doc/classes/AudioStreamGeneratorPlayback.xml
+++ b/doc/classes/AudioStreamGeneratorPlayback.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamGeneratorPlayback" inherits="AudioStreamPlaybackResampled" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamGeneratorPlayback" inherits="AudioStreamPlaybackResampled" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plays back audio generated using [AudioStreamGenerator].
</brief_description>
diff --git a/doc/classes/AudioStreamMicrophone.xml b/doc/classes/AudioStreamMicrophone.xml
index 0c740745a8..189f9b95e2 100644
--- a/doc/classes/AudioStreamMicrophone.xml
+++ b/doc/classes/AudioStreamMicrophone.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamMicrophone" inherits="AudioStream" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamMicrophone" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plays real-time audio input data.
</brief_description>
diff --git a/doc/classes/AudioStreamPlayback.xml b/doc/classes/AudioStreamPlayback.xml
index fced312c5b..7692690b5e 100644
--- a/doc/classes/AudioStreamPlayback.xml
+++ b/doc/classes/AudioStreamPlayback.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPlayback" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamPlayback" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Meta class for playing back audio.
</brief_description>
diff --git a/doc/classes/AudioStreamPlaybackPolyphonic.xml b/doc/classes/AudioStreamPlaybackPolyphonic.xml
index 0143a38401..106f2a3dbb 100644
--- a/doc/classes/AudioStreamPlaybackPolyphonic.xml
+++ b/doc/classes/AudioStreamPlaybackPolyphonic.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPlaybackPolyphonic" inherits="AudioStreamPlayback" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamPlaybackPolyphonic" inherits="AudioStreamPlayback" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Playback instance for [AudioStreamPolyphonic].
</brief_description>
diff --git a/doc/classes/AudioStreamPlaybackResampled.xml b/doc/classes/AudioStreamPlaybackResampled.xml
index 53bb4ca635..4173ee4bb4 100644
--- a/doc/classes/AudioStreamPlaybackResampled.xml
+++ b/doc/classes/AudioStreamPlaybackResampled.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPlaybackResampled" inherits="AudioStreamPlayback" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamPlaybackResampled" inherits="AudioStreamPlayback" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml
index 8ac2cc8b18..c48c7f4300 100644
--- a/doc/classes/AudioStreamPlayer.xml
+++ b/doc/classes/AudioStreamPlayer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPlayer" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamPlayer" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plays back audio non-positionally.
</brief_description>
diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml
index 7fd8006c24..7c59089708 100644
--- a/doc/classes/AudioStreamPlayer2D.xml
+++ b/doc/classes/AudioStreamPlayer2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPlayer2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamPlayer2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plays positional sound in 2D space.
</brief_description>
diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml
index 4a0e261c3a..f4c9adcaec 100644
--- a/doc/classes/AudioStreamPlayer3D.xml
+++ b/doc/classes/AudioStreamPlayer3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPlayer3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamPlayer3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plays positional sound in 3D space.
</brief_description>
@@ -85,7 +85,7 @@
Attenuation factor used if listener is outside of [member emission_angle_degrees] and [member emission_angle_enabled] is set, in decibels.
</member>
<member name="max_db" type="float" setter="set_max_db" getter="get_max_db" default="3.0">
- Sets the absolute maximum of the soundlevel, in decibels.
+ Sets the absolute maximum of the sound level, in decibels.
</member>
<member name="max_distance" type="float" setter="set_max_distance" getter="get_max_distance" default="0.0">
The distance past which the sound can no longer be heard at all. Only has an effect if set to a value greater than [code]0.0[/code]. [member max_distance] works in tandem with [member unit_size]. However, unlike [member unit_size] whose behavior depends on the [member attenuation_model], [member max_distance] always works in a linear fashion. This can be used to prevent the [AudioStreamPlayer3D] from requiring audio mixing when the listener is far away, which saves CPU resources.
diff --git a/doc/classes/AudioStreamPolyphonic.xml b/doc/classes/AudioStreamPolyphonic.xml
index 1febc3ad63..49c6aebaa5 100644
--- a/doc/classes/AudioStreamPolyphonic.xml
+++ b/doc/classes/AudioStreamPolyphonic.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPolyphonic" inherits="AudioStream" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamPolyphonic" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
AudioStream that lets the user play custom streams at any time from code, simultaneously using a single player.
</brief_description>
diff --git a/doc/classes/AudioStreamRandomizer.xml b/doc/classes/AudioStreamRandomizer.xml
index 5a2cacb0f3..384c316000 100644
--- a/doc/classes/AudioStreamRandomizer.xml
+++ b/doc/classes/AudioStreamRandomizer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamRandomizer" inherits="AudioStream" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamRandomizer" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Wraps a pool of audio streams with pitch and volume shifting.
</brief_description>
diff --git a/doc/classes/AudioStreamWAV.xml b/doc/classes/AudioStreamWAV.xml
index 65251e953b..c3df946b4b 100644
--- a/doc/classes/AudioStreamWAV.xml
+++ b/doc/classes/AudioStreamWAV.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamWAV" inherits="AudioStream" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AudioStreamWAV" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Stores audio data loaded from WAV files.
</brief_description>
diff --git a/doc/classes/BackBufferCopy.xml b/doc/classes/BackBufferCopy.xml
index aa5a644d6a..a671b85c83 100644
--- a/doc/classes/BackBufferCopy.xml
+++ b/doc/classes/BackBufferCopy.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BackBufferCopy" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BackBufferCopy" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Copies a region of the screen (or the whole screen) to a buffer so it can be accessed in your shader scripts using the screen texture (i.e. a uniform sampler with ``hint_screen_texture``).
</brief_description>
diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml
index cc95c97e68..b18ee95a43 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BaseButton" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BaseButton" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for GUI buttons.
</brief_description>
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index f5e14e29bf..949dcc24d0 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BaseMaterial3D" inherits="Material" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BaseMaterial3D" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Default 3D rendering material.
</brief_description>
@@ -269,7 +269,7 @@
Specifies the channel of the [member metallic_texture] in which the metallic information is stored. This is useful when you store the information for multiple effects in a single texture. For example if you stored metallic in the red channel, roughness in the blue, and ambient occlusion in the green you could reduce the number of textures you use.
</member>
<member name="msdf_outline_size" type="float" setter="set_msdf_outline_size" getter="get_msdf_outline_size" default="0.0">
- The width of the shape outine.
+ The width of the shape outline.
</member>
<member name="msdf_pixel_range" type="float" setter="set_msdf_pixel_range" getter="get_msdf_pixel_range" default="4.0">
The width of the range around the shape between the minimum and maximum representable signed distance.
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index f84d14a5a6..2034f4a8ff 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Basis" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Basis" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3×3 matrix for representing 3D rotation and scale.
</brief_description>
diff --git a/doc/classes/BitMap.xml b/doc/classes/BitMap.xml
index 7e00fbd317..fa454a1b0d 100644
--- a/doc/classes/BitMap.xml
+++ b/doc/classes/BitMap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BitMap" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BitMap" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Boolean matrix.
</brief_description>
diff --git a/doc/classes/Bone2D.xml b/doc/classes/Bone2D.xml
index 93bdd9d527..605f217eff 100644
--- a/doc/classes/Bone2D.xml
+++ b/doc/classes/Bone2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Bone2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Bone2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A joint used with [Skeleton2D] to control and animate other nodes.
</brief_description>
diff --git a/doc/classes/BoneAttachment3D.xml b/doc/classes/BoneAttachment3D.xml
index 83f70fc331..111e58e981 100644
--- a/doc/classes/BoneAttachment3D.xml
+++ b/doc/classes/BoneAttachment3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BoneAttachment3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BoneAttachment3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
А node that dynamically copies or overrides the 3D transform of a bone in its parent [Skeleton3D].
</brief_description>
@@ -39,7 +39,7 @@
<return type="void" />
<param index="0" name="use_external_skeleton" type="bool" />
<description>
- Sets whether the BoneAttachment3D node will use an extenral [Skeleton3D] node rather than attenpting to use its parent node as the [Skeleton3D]. When set to [code]true[/code], the BoneAttachment3D node will use the external [Skeleton3D] node set in [method set_external_skeleton].
+ Sets whether the BoneAttachment3D node will use an external [Skeleton3D] node rather than attempting to use its parent node as the [Skeleton3D]. When set to [code]true[/code], the BoneAttachment3D node will use the external [Skeleton3D] node set in [method set_external_skeleton].
</description>
</method>
</methods>
diff --git a/doc/classes/BoneMap.xml b/doc/classes/BoneMap.xml
index 032e2420ca..447d3406c0 100644
--- a/doc/classes/BoneMap.xml
+++ b/doc/classes/BoneMap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BoneMap" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BoneMap" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Describes a mapping of bone names for retargeting [Skeleton3D] into common names defined by a [SkeletonProfile].
</brief_description>
diff --git a/doc/classes/BoxContainer.xml b/doc/classes/BoxContainer.xml
index 1716fc83fb..926bd8f0bd 100644
--- a/doc/classes/BoxContainer.xml
+++ b/doc/classes/BoxContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BoxContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BoxContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that arranges its child controls horizontally or vertically.
</brief_description>
diff --git a/doc/classes/BoxMesh.xml b/doc/classes/BoxMesh.xml
index 4cf3783a79..7df874ccf4 100644
--- a/doc/classes/BoxMesh.xml
+++ b/doc/classes/BoxMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BoxMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BoxMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Generate an axis-aligned box [PrimitiveMesh].
</brief_description>
diff --git a/doc/classes/BoxOccluder3D.xml b/doc/classes/BoxOccluder3D.xml
index ab35af2244..094a696936 100644
--- a/doc/classes/BoxOccluder3D.xml
+++ b/doc/classes/BoxOccluder3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BoxOccluder3D" inherits="Occluder3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BoxOccluder3D" inherits="Occluder3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Cuboid shape for use with occlusion culling in [OccluderInstance3D].
</brief_description>
diff --git a/doc/classes/BoxShape3D.xml b/doc/classes/BoxShape3D.xml
index 1886e8f29a..5190e6e759 100644
--- a/doc/classes/BoxShape3D.xml
+++ b/doc/classes/BoxShape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BoxShape3D" inherits="Shape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="BoxShape3D" inherits="Shape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D box shape used for physics collision.
</brief_description>
diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml
index e5d57d3f18..6faefcbe0d 100644
--- a/doc/classes/Button.xml
+++ b/doc/classes/Button.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Button" inherits="BaseButton" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Button" inherits="BaseButton" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A themed button that can contain text and an icon.
</brief_description>
diff --git a/doc/classes/ButtonGroup.xml b/doc/classes/ButtonGroup.xml
index bb32319a31..618136c2a7 100644
--- a/doc/classes/ButtonGroup.xml
+++ b/doc/classes/ButtonGroup.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ButtonGroup" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ButtonGroup" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A group of buttons that doesn't allow more than one button to be pressed at a time.
</brief_description>
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index 73d859eacd..eaacdd590d 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CPUParticles2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CPUParticles2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
CPU-based 2D particle emitter.
</brief_description>
@@ -169,7 +169,7 @@
The sphere's radius if [member emission_shape] is set to [constant EMISSION_SHAPE_SPHERE].
</member>
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
- If [code]true[/code], particles are being emitted.
+ If [code]true[/code], particles are being emitted. [member emitting] can be used to start and stop particles from emitting. However, if [member one_shot] is [code]true[/code] setting [member emitting] to [code]true[/code] will not restart the emission cycle until after all active particles finish processing. You can use the [signal finished] signal to be notified once all active particles finish processing.
</member>
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
@@ -285,6 +285,13 @@
Particle texture. If [code]null[/code], particles will be squares.
</member>
</members>
+ <signals>
+ <signal name="finished">
+ <description>
+ Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
Particles are drawn in the order emitted.
diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml
index f02b7578f8..f03c463049 100644
--- a/doc/classes/CPUParticles3D.xml
+++ b/doc/classes/CPUParticles3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CPUParticles3D" inherits="GeometryInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CPUParticles3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
CPU-based 3D particle emitter.
</brief_description>
@@ -183,7 +183,7 @@
The sphere's radius if [enum EmissionShape] is set to [constant EMISSION_SHAPE_SPHERE].
</member>
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
- If [code]true[/code], particles are being emitted.
+ If [code]true[/code], particles are being emitted. [member emitting] can be used to start and stop particles from emitting. However, if [member one_shot] is [code]true[/code] setting [member emitting] to [code]true[/code] will not restart the emission cycle until after all active particles finish processing. You can use the [signal finished] signal to be notified once all active particles finish processing.
</member>
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
@@ -309,6 +309,13 @@
Minimum tangent acceleration.
</member>
</members>
+ <signals>
+ <signal name="finished">
+ <description>
+ Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
Particles are drawn in the order emitted.
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index be6669110c..c7b2d6df94 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Callable" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Callable" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A built-in type representing a method or a standalone function.
</brief_description>
diff --git a/doc/classes/CallbackTweener.xml b/doc/classes/CallbackTweener.xml
index f69ccec947..64b47183be 100644
--- a/doc/classes/CallbackTweener.xml
+++ b/doc/classes/CallbackTweener.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CallbackTweener" inherits="Tweener" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CallbackTweener" inherits="Tweener" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Calls the specified method after optional delay.
</brief_description>
diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml
index ce2c1cc37e..6319bfb3d1 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Camera2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Camera2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Camera node for 2D scenes.
</brief_description>
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index b0406c77a1..83f1ffa08e 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Camera3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Camera3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Camera node, displays from a point of view.
</brief_description>
@@ -17,6 +17,12 @@
If this is the current camera, remove it from being current. If [param enable_next] is [code]true[/code], request to make the next camera current, if any.
</description>
</method>
+ <method name="get_camera_projection" qualifiers="const">
+ <return type="Projection" />
+ <description>
+ Returns the projection matrix that this camera uses to render to its associated viewport. The camera must be part of the scene tree to function.
+ </description>
+ </method>
<method name="get_camera_rid" qualifiers="const">
<return type="RID" />
<description>
diff --git a/doc/classes/CameraAttributes.xml b/doc/classes/CameraAttributes.xml
index 9333916e52..1b1365eed4 100644
--- a/doc/classes/CameraAttributes.xml
+++ b/doc/classes/CameraAttributes.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CameraAttributes" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CameraAttributes" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Parent class for camera settings.
</brief_description>
diff --git a/doc/classes/CameraAttributesPhysical.xml b/doc/classes/CameraAttributesPhysical.xml
index 8cab882f24..c11a057b1d 100644
--- a/doc/classes/CameraAttributesPhysical.xml
+++ b/doc/classes/CameraAttributesPhysical.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CameraAttributesPhysical" inherits="CameraAttributes" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CameraAttributesPhysical" inherits="CameraAttributes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Physically-based camera settings.
</brief_description>
diff --git a/doc/classes/CameraAttributesPractical.xml b/doc/classes/CameraAttributesPractical.xml
index 623abe81ed..8a5956cc87 100644
--- a/doc/classes/CameraAttributesPractical.xml
+++ b/doc/classes/CameraAttributesPractical.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CameraAttributesPractical" inherits="CameraAttributes" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CameraAttributesPractical" inherits="CameraAttributes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Camera settings in an easy to use format.
</brief_description>
diff --git a/doc/classes/CameraFeed.xml b/doc/classes/CameraFeed.xml
index 37b47c6baf..974f6d4a33 100644
--- a/doc/classes/CameraFeed.xml
+++ b/doc/classes/CameraFeed.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CameraFeed" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CameraFeed" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A camera feed gives you access to a single physical camera attached to your device.
</brief_description>
diff --git a/doc/classes/CameraServer.xml b/doc/classes/CameraServer.xml
index dadc2d6550..983bd6cd91 100644
--- a/doc/classes/CameraServer.xml
+++ b/doc/classes/CameraServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CameraServer" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CameraServer" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Server keeping track of different cameras accessible in Godot.
</brief_description>
diff --git a/doc/classes/CameraTexture.xml b/doc/classes/CameraTexture.xml
index a4594b7db9..faaf9b55fa 100644
--- a/doc/classes/CameraTexture.xml
+++ b/doc/classes/CameraTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CameraTexture" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CameraTexture" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture provided by a [CameraFeed].
</brief_description>
diff --git a/doc/classes/CanvasGroup.xml b/doc/classes/CanvasGroup.xml
index 6258ee4ffb..2792e593e3 100644
--- a/doc/classes/CanvasGroup.xml
+++ b/doc/classes/CanvasGroup.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CanvasGroup" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CanvasGroup" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Merges several 2D nodes into a single draw operation.
</brief_description>
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index ba280ab0fa..33f6a02c52 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CanvasItem" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CanvasItem" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for everything in 2D space.
</brief_description>
diff --git a/doc/classes/CanvasItemMaterial.xml b/doc/classes/CanvasItemMaterial.xml
index 500e3fb719..3ba122d7ac 100644
--- a/doc/classes/CanvasItemMaterial.xml
+++ b/doc/classes/CanvasItemMaterial.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CanvasItemMaterial" inherits="Material" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CanvasItemMaterial" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A material for [CanvasItem]s.
</brief_description>
diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml
index e85ab6c21f..2b155d869d 100644
--- a/doc/classes/CanvasLayer.xml
+++ b/doc/classes/CanvasLayer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CanvasLayer" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CanvasLayer" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node used for independent rendering of objects within a 2D scene.
</brief_description>
diff --git a/doc/classes/CanvasModulate.xml b/doc/classes/CanvasModulate.xml
index ecebabb1c5..214b3959c7 100644
--- a/doc/classes/CanvasModulate.xml
+++ b/doc/classes/CanvasModulate.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CanvasModulate" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CanvasModulate" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node that applies a color tint to a canvas.
</brief_description>
diff --git a/doc/classes/CanvasTexture.xml b/doc/classes/CanvasTexture.xml
index d1f32ef921..df3f8e8125 100644
--- a/doc/classes/CanvasTexture.xml
+++ b/doc/classes/CanvasTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CanvasTexture" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CanvasTexture" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture with optional normal and specular maps for use in 2D rendering.
</brief_description>
diff --git a/doc/classes/CapsuleMesh.xml b/doc/classes/CapsuleMesh.xml
index d0ddad8105..62e92e1900 100644
--- a/doc/classes/CapsuleMesh.xml
+++ b/doc/classes/CapsuleMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CapsuleMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CapsuleMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Class representing a capsule-shaped [PrimitiveMesh].
</brief_description>
diff --git a/doc/classes/CapsuleShape2D.xml b/doc/classes/CapsuleShape2D.xml
index ebc64aaedf..52ea7af292 100644
--- a/doc/classes/CapsuleShape2D.xml
+++ b/doc/classes/CapsuleShape2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CapsuleShape2D" inherits="Shape2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CapsuleShape2D" inherits="Shape2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D capsule shape used for physics collision.
</brief_description>
diff --git a/doc/classes/CapsuleShape3D.xml b/doc/classes/CapsuleShape3D.xml
index 6662e20f3a..2c8c2cef9e 100644
--- a/doc/classes/CapsuleShape3D.xml
+++ b/doc/classes/CapsuleShape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CapsuleShape3D" inherits="Shape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CapsuleShape3D" inherits="Shape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D capsule shape used for physics collision.
</brief_description>
diff --git a/doc/classes/CenterContainer.xml b/doc/classes/CenterContainer.xml
index c5481d5beb..cf4207b86d 100644
--- a/doc/classes/CenterContainer.xml
+++ b/doc/classes/CenterContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CenterContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CenterContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that keeps child controls in its center.
</brief_description>
diff --git a/doc/classes/CharFXTransform.xml b/doc/classes/CharFXTransform.xml
index c146a4c9e9..ad41eceff4 100644
--- a/doc/classes/CharFXTransform.xml
+++ b/doc/classes/CharFXTransform.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CharFXTransform" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CharFXTransform" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Controls how an individual character will be displayed in a [RichTextEffect].
</brief_description>
diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml
index ddd2521823..7b22fe2e93 100644
--- a/doc/classes/CharacterBody2D.xml
+++ b/doc/classes/CharacterBody2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CharacterBody2D" inherits="PhysicsBody2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CharacterBody2D" inherits="PhysicsBody2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D physics body specialized for characters moved by script.
</brief_description>
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
index 0be6f8b705..b4f68cb1aa 100644
--- a/doc/classes/CharacterBody3D.xml
+++ b/doc/classes/CharacterBody3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CharacterBody3D" inherits="PhysicsBody3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CharacterBody3D" inherits="PhysicsBody3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D physics body specialized for characters moved by script.
</brief_description>
diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml
index b5d7c8d898..fb733a95b8 100644
--- a/doc/classes/CheckBox.xml
+++ b/doc/classes/CheckBox.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CheckBox" inherits="Button" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CheckBox" inherits="Button" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A button that represents a binary choice.
</brief_description>
diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml
index 3f9af48dc9..0fffe7f621 100644
--- a/doc/classes/CheckButton.xml
+++ b/doc/classes/CheckButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CheckButton" inherits="Button" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CheckButton" inherits="Button" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A button that represents a binary choice.
</brief_description>
diff --git a/doc/classes/CircleShape2D.xml b/doc/classes/CircleShape2D.xml
index f4dd2dcb27..3d0864b08a 100644
--- a/doc/classes/CircleShape2D.xml
+++ b/doc/classes/CircleShape2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CircleShape2D" inherits="Shape2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CircleShape2D" inherits="Shape2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D circle shape used for physics collision.
</brief_description>
diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml
index 69eee5057d..d24181c3d3 100644
--- a/doc/classes/ClassDB.xml
+++ b/doc/classes/ClassDB.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ClassDB" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ClassDB" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A class information repository.
</brief_description>
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index 7686fd9384..0e829127f2 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CodeEdit" inherits="TextEdit" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CodeEdit" inherits="TextEdit" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A multiline text editor designed for editing code.
</brief_description>
@@ -248,12 +248,20 @@
Returns the full text with char [code]0xFFFF[/code] at the caret location.
</description>
</method>
- <method name="get_text_for_symbol_lookup">
+ <method name="get_text_for_symbol_lookup" qualifiers="const">
<return type="String" />
<description>
Returns the full text with char [code]0xFFFF[/code] at the cursor location.
</description>
</method>
+ <method name="get_text_with_cursor_char" qualifiers="const">
+ <return type="String" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="column" type="int" />
+ <description>
+ Returns the full text with char [code]0xFFFF[/code] at the specified location.
+ </description>
+ </method>
<method name="has_auto_brace_completion_close_key" qualifiers="const">
<return type="bool" />
<param index="0" name="close_key" type="String" />
@@ -435,7 +443,7 @@
<return type="void" />
<param index="0" name="force" type="bool" />
<description>
- Submits all completion options added with [method add_code_completion_option]. Will try to force the autoccomplete menu to popup, if [param force] is [code]true[/code].
+ Submits all completion options added with [method add_code_completion_option]. Will try to force the autocomplete menu to popup, if [param force] is [code]true[/code].
[b]Note:[/b] This will replace all current candidates.
</description>
</method>
diff --git a/doc/classes/CodeHighlighter.xml b/doc/classes/CodeHighlighter.xml
index 11b00557e9..3005ffcdca 100644
--- a/doc/classes/CodeHighlighter.xml
+++ b/doc/classes/CodeHighlighter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CodeHighlighter" inherits="SyntaxHighlighter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CodeHighlighter" inherits="SyntaxHighlighter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A syntax highlighter intended for code.
</brief_description>
diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index e645d6fb74..07bc53575c 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CollisionObject2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CollisionObject2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for 2D physics objects.
</brief_description>
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index 4903784abc..b45a5d8c56 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CollisionObject3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CollisionObject3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for 3D physics objects.
</brief_description>
diff --git a/doc/classes/CollisionPolygon2D.xml b/doc/classes/CollisionPolygon2D.xml
index 4ad88d49bc..d6f3b7cb5d 100644
--- a/doc/classes/CollisionPolygon2D.xml
+++ b/doc/classes/CollisionPolygon2D.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CollisionPolygon2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CollisionPolygon2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node that provides a polygon shape to a [CollisionObject2D] parent.
</brief_description>
<description>
A node that provides a thickened polygon shape (a prism) to a [CollisionObject2D] parent and allows to edit it. The polygon can be concave or convex. This can give a detection shape to an [Area2D] or turn [PhysicsBody2D] into a solid object.
- [b]Warning:[/b] A non-uniformly scaled [CollisionShape3D] will likely not behave as expected. Make sure to keep its scale the same on all axes and adjust its shape resource instead.
+ [b]Warning:[/b] A non-uniformly scaled [CollisionShape2D] will likely not behave as expected. Make sure to keep its scale the same on all axes and adjust its shape resource instead.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CollisionPolygon3D.xml b/doc/classes/CollisionPolygon3D.xml
index 382471d0f0..0a3a3cfd26 100644
--- a/doc/classes/CollisionPolygon3D.xml
+++ b/doc/classes/CollisionPolygon3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CollisionPolygon3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CollisionPolygon3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node that provides a thickened polygon shape (a prism) to a [CollisionObject3D] parent.
</brief_description>
diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml
index d14686a251..f3143e1f5c 100644
--- a/doc/classes/CollisionShape2D.xml
+++ b/doc/classes/CollisionShape2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CollisionShape2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CollisionShape2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node that provides a [Shape2D] to a [CollisionObject2D] parent.
</brief_description>
diff --git a/doc/classes/CollisionShape3D.xml b/doc/classes/CollisionShape3D.xml
index b5e63b0135..4e32545f27 100644
--- a/doc/classes/CollisionShape3D.xml
+++ b/doc/classes/CollisionShape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CollisionShape3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CollisionShape3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node that provides a [Shape3D] to a [CollisionObject3D] parent.
</brief_description>
@@ -20,11 +20,11 @@
Sets the collision shape's shape to the addition of all its convexed [MeshInstance3D] siblings geometry.
</description>
</method>
- <method name="resource_changed">
+ <method name="resource_changed" is_deprecated="true">
<return type="void" />
<param index="0" name="resource" type="Resource" />
<description>
- If this method exists within a script it will be called whenever the shape resource has been modified.
+ [i]Obsoleted.[/i] Use [signal Resource.changed] instead.
</description>
</method>
</methods>
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 26b3e68e24..292207e8bb 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Color" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Color" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A color represented in RGBA format.
</brief_description>
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index fbeae42932..2f01e791a2 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ColorPicker" inherits="VBoxContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ColorPicker" inherits="VBoxContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A widget that provides an interface for selecting or modifying a color.
</brief_description>
diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml
index a725d1a3ee..32ec27868a 100644
--- a/doc/classes/ColorPickerButton.xml
+++ b/doc/classes/ColorPickerButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ColorPickerButton" inherits="Button" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ColorPickerButton" inherits="Button" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A button that brings up a [ColorPicker] when pressed.
</brief_description>
diff --git a/doc/classes/ColorRect.xml b/doc/classes/ColorRect.xml
index e179ab07bb..5bc97e6f46 100644
--- a/doc/classes/ColorRect.xml
+++ b/doc/classes/ColorRect.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ColorRect" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ColorRect" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control that displays a solid color rectangle.
</brief_description>
diff --git a/doc/classes/CompressedCubemap.xml b/doc/classes/CompressedCubemap.xml
index f98dfc61a3..e72d727d7d 100644
--- a/doc/classes/CompressedCubemap.xml
+++ b/doc/classes/CompressedCubemap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CompressedCubemap" inherits="CompressedTextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CompressedCubemap" inherits="CompressedTextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
6-sided texture typically used in 3D rendering, optionally compressed.
</brief_description>
diff --git a/doc/classes/CompressedCubemapArray.xml b/doc/classes/CompressedCubemapArray.xml
index 75e9b3d513..f5829e4e3e 100644
--- a/doc/classes/CompressedCubemapArray.xml
+++ b/doc/classes/CompressedCubemapArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CompressedCubemapArray" inherits="CompressedTextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CompressedCubemapArray" inherits="CompressedTextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Array of 6-sided textures typically used in 3D rendering, optionally compressed.
</brief_description>
diff --git a/doc/classes/CompressedTexture2D.xml b/doc/classes/CompressedTexture2D.xml
index 9fde9ebeea..cc4c4c8182 100644
--- a/doc/classes/CompressedTexture2D.xml
+++ b/doc/classes/CompressedTexture2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CompressedTexture2D" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CompressedTexture2D" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture with 2 dimensions, optionally compressed.
</brief_description>
diff --git a/doc/classes/CompressedTexture2DArray.xml b/doc/classes/CompressedTexture2DArray.xml
index 71888bf824..ab0684fa06 100644
--- a/doc/classes/CompressedTexture2DArray.xml
+++ b/doc/classes/CompressedTexture2DArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CompressedTexture2DArray" inherits="CompressedTextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CompressedTexture2DArray" inherits="CompressedTextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Array of 2-dimensional textures, optionally compressed.
</brief_description>
diff --git a/doc/classes/CompressedTexture3D.xml b/doc/classes/CompressedTexture3D.xml
index 2143a50c5c..797fbc9da5 100644
--- a/doc/classes/CompressedTexture3D.xml
+++ b/doc/classes/CompressedTexture3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CompressedTexture3D" inherits="Texture3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CompressedTexture3D" inherits="Texture3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture with 3 dimensions, optionally compressed.
</brief_description>
diff --git a/doc/classes/CompressedTextureLayered.xml b/doc/classes/CompressedTextureLayered.xml
index da34180c93..e661055f82 100644
--- a/doc/classes/CompressedTextureLayered.xml
+++ b/doc/classes/CompressedTextureLayered.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CompressedTextureLayered" inherits="TextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CompressedTextureLayered" inherits="TextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for texture arrays that can optionally be compressed.
</brief_description>
diff --git a/doc/classes/ConcavePolygonShape2D.xml b/doc/classes/ConcavePolygonShape2D.xml
index 817c2891d9..3d366cecc6 100644
--- a/doc/classes/ConcavePolygonShape2D.xml
+++ b/doc/classes/ConcavePolygonShape2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConcavePolygonShape2D" inherits="Shape2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ConcavePolygonShape2D" inherits="Shape2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D polyline shape used for physics collision.
</brief_description>
diff --git a/doc/classes/ConcavePolygonShape3D.xml b/doc/classes/ConcavePolygonShape3D.xml
index a9ac34c04a..c0d0f43010 100644
--- a/doc/classes/ConcavePolygonShape3D.xml
+++ b/doc/classes/ConcavePolygonShape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConcavePolygonShape3D" inherits="Shape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ConcavePolygonShape3D" inherits="Shape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D trimesh shape used for physics collision.
</brief_description>
diff --git a/doc/classes/ConeTwistJoint3D.xml b/doc/classes/ConeTwistJoint3D.xml
index da67ac6df3..632b512497 100644
--- a/doc/classes/ConeTwistJoint3D.xml
+++ b/doc/classes/ConeTwistJoint3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConeTwistJoint3D" inherits="Joint3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ConeTwistJoint3D" inherits="Joint3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics joint that connects two 3D physics bodies in a way that simulates a ball-and-socket joint.
</brief_description>
diff --git a/doc/classes/ConfigFile.xml b/doc/classes/ConfigFile.xml
index b4eaab6464..04e4164415 100644
--- a/doc/classes/ConfigFile.xml
+++ b/doc/classes/ConfigFile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConfigFile" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ConfigFile" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Helper class to handle INI-style files.
</brief_description>
diff --git a/doc/classes/ConfirmationDialog.xml b/doc/classes/ConfirmationDialog.xml
index 631e107448..8fa5dac7bf 100644
--- a/doc/classes/ConfirmationDialog.xml
+++ b/doc/classes/ConfirmationDialog.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConfirmationDialog" inherits="AcceptDialog" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ConfirmationDialog" inherits="AcceptDialog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A dialog used for confirmation of actions.
</brief_description>
diff --git a/doc/classes/Container.xml b/doc/classes/Container.xml
index 6d7101ea1b..6ac02e2d08 100644
--- a/doc/classes/Container.xml
+++ b/doc/classes/Container.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Container" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Container" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for all GUI containers.
</brief_description>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index e20651b1ee..54c38f2db9 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Control" inherits="CanvasItem" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Control" inherits="CanvasItem" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for all GUI controls. Adapts its position and size based on its parent control.
</brief_description>
@@ -1299,13 +1299,13 @@
Tells the parent [Container] to align the node with its end, either the bottom or the right edge. It is mutually exclusive with [constant SIZE_FILL] and other shrink size flags, but can be used with [constant SIZE_EXPAND] in some containers. Use with [member size_flags_horizontal] and [member size_flags_vertical].
</constant>
<constant name="MOUSE_FILTER_STOP" value="0" enum="MouseFilter">
- The control will receive mouse button input events through [method _gui_input] if clicked on. And the control will receive the [signal mouse_entered] and [signal mouse_exited] signals. These events are automatically marked as handled, and they will not propagate further to other controls. This also results in blocking signals in other controls.
+ The control will receive mouse movement input events and mouse button input events if clicked on through [method _gui_input]. And the control will receive the [signal mouse_entered] and [signal mouse_exited] signals. These events are automatically marked as handled, and they will not propagate further to other controls. This also results in blocking signals in other controls.
</constant>
<constant name="MOUSE_FILTER_PASS" value="1" enum="MouseFilter">
- The control will receive mouse button input events through [method _gui_input] if clicked on. And the control will receive the [signal mouse_entered] and [signal mouse_exited] signals. If this control does not handle the event, the parent control (if any) will be considered, and so on until there is no more parent control to potentially handle it. This also allows signals to fire in other controls. If no control handled it, the event will be passed to [method Node._unhandled_input] for further processing.
+ The control will receive mouse movement input events and mouse button input events if clicked on through [method _gui_input]. And the control will receive the [signal mouse_entered] and [signal mouse_exited] signals. If this control does not handle the event, the parent control (if any) will be considered, and so on until there is no more parent control to potentially handle it. This also allows signals to fire in other controls. If no control handled it, the event will be passed to [method Node._shortcut_input] for further processing.
</constant>
<constant name="MOUSE_FILTER_IGNORE" value="2" enum="MouseFilter">
- The control will not receive mouse button input events through [method _gui_input]. The control will also not receive the [signal mouse_entered] nor [signal mouse_exited] signals. This will not block other controls from receiving these events or firing the signals. Ignored events will not be handled automatically.
+ The control will not receive mouse movement input events and mouse button input events if clicked on through [method _gui_input]. The control will also not receive the [signal mouse_entered] nor [signal mouse_exited] signals. This will not block other controls from receiving these events or firing the signals. Ignored events will not be handled automatically.
</constant>
<constant name="GROW_DIRECTION_BEGIN" value="0" enum="GrowDirection">
The control will grow to the left or top to make up if its minimum size is changed to be greater than its current size on the respective axis.
diff --git a/doc/classes/ConvexPolygonShape2D.xml b/doc/classes/ConvexPolygonShape2D.xml
index d131df3d27..4f86f3830b 100644
--- a/doc/classes/ConvexPolygonShape2D.xml
+++ b/doc/classes/ConvexPolygonShape2D.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConvexPolygonShape2D" inherits="Shape2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ConvexPolygonShape2D" inherits="Shape2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D convex polygon shape used for physics collision.
</brief_description>
<description>
A 2D convex polygon shape, intended for use in physics. Used internally in [CollisionPolygon2D] when it's in [code]BUILD_SOLIDS[/code] mode.
[ConvexPolygonShape2D] is [i]solid[/i], which means it detects collisions from objects that are fully inside it, unlike [ConcavePolygonShape2D] which is hollow. This makes it more suitable for both detection and physics.
- [b]Convex decomposition:[/b] A concave polygon can be split up into several convex polygons. This allows dynamic physics bodies to have complex concave collisions (at a performance cost) and can be achieved by using several [ConvexPolygonShape3D] nodes or by using the [CollisionPolygon2D] node in [code]BUILD_SOLIDS[/code] mode. To generate a collision polygon from a sprite, select the [Sprite2D] node, go to the [b]Sprite2D[/b] menu that appears above the viewport, and choose [b]Create Polygon2D Sibling[/b].
+ [b]Convex decomposition:[/b] A concave polygon can be split up into several convex polygons. This allows dynamic physics bodies to have complex concave collisions (at a performance cost) and can be achieved by using several [ConvexPolygonShape2D] nodes or by using the [CollisionPolygon2D] node in [code]BUILD_SOLIDS[/code] mode. To generate a collision polygon from a sprite, select the [Sprite2D] node, go to the [b]Sprite2D[/b] menu that appears above the viewport, and choose [b]Create Polygon2D Sibling[/b].
[b]Performance:[/b] [ConvexPolygonShape2D] is faster to check collisions against compared to [ConcavePolygonShape2D], but it is slower than primitive collision shapes such as [CircleShape2D] and [RectangleShape2D]. Its use should generally be limited to medium-sized objects that cannot have their collision accurately represented by primitive shapes.
</description>
<tutorials>
diff --git a/doc/classes/ConvexPolygonShape3D.xml b/doc/classes/ConvexPolygonShape3D.xml
index 126cd2b983..280cadde78 100644
--- a/doc/classes/ConvexPolygonShape3D.xml
+++ b/doc/classes/ConvexPolygonShape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConvexPolygonShape3D" inherits="Shape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ConvexPolygonShape3D" inherits="Shape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D convex polyhedron shape used for physics collision.
</brief_description>
diff --git a/doc/classes/Crypto.xml b/doc/classes/Crypto.xml
index ba410035af..59d19b03f4 100644
--- a/doc/classes/Crypto.xml
+++ b/doc/classes/Crypto.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Crypto" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Crypto" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides access to advanced cryptographic functionalities.
</brief_description>
diff --git a/doc/classes/CryptoKey.xml b/doc/classes/CryptoKey.xml
index 31e4cf1936..32d5d361ba 100644
--- a/doc/classes/CryptoKey.xml
+++ b/doc/classes/CryptoKey.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CryptoKey" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CryptoKey" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A cryptographic key (RSA).
</brief_description>
diff --git a/doc/classes/Cubemap.xml b/doc/classes/Cubemap.xml
index 2dc77ac8f8..0d3b52ddfc 100644
--- a/doc/classes/Cubemap.xml
+++ b/doc/classes/Cubemap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Cubemap" inherits="ImageTextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Cubemap" inherits="ImageTextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
6-sided texture typically used in 3D rendering.
</brief_description>
diff --git a/doc/classes/CubemapArray.xml b/doc/classes/CubemapArray.xml
index 66a7e2ef1f..ee4ec239f3 100644
--- a/doc/classes/CubemapArray.xml
+++ b/doc/classes/CubemapArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CubemapArray" inherits="ImageTextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CubemapArray" inherits="ImageTextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A single composite texture resource which consists of multiple [Cubemap]s.
</brief_description>
diff --git a/doc/classes/Curve.xml b/doc/classes/Curve.xml
index 52f79ecc9d..8f5dc4e945 100644
--- a/doc/classes/Curve.xml
+++ b/doc/classes/Curve.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Curve" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Curve" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A mathematic curve.
</brief_description>
diff --git a/doc/classes/Curve2D.xml b/doc/classes/Curve2D.xml
index 59cf96b0e7..197d03f0d8 100644
--- a/doc/classes/Curve2D.xml
+++ b/doc/classes/Curve2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Curve2D" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Curve2D" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Describes a Bézier curve in 2D space.
</brief_description>
diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml
index 4d1f5a7180..06b6409e09 100644
--- a/doc/classes/Curve3D.xml
+++ b/doc/classes/Curve3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Curve3D" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Curve3D" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Describes a Bézier curve in 3D space.
</brief_description>
diff --git a/doc/classes/CurveTexture.xml b/doc/classes/CurveTexture.xml
index 7d530e45cf..4767c18d5a 100644
--- a/doc/classes/CurveTexture.xml
+++ b/doc/classes/CurveTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CurveTexture" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CurveTexture" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A texture that shows a curve.
</brief_description>
diff --git a/doc/classes/CurveXYZTexture.xml b/doc/classes/CurveXYZTexture.xml
index b50a37c7cc..e0ab17a35c 100644
--- a/doc/classes/CurveXYZTexture.xml
+++ b/doc/classes/CurveXYZTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CurveXYZTexture" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CurveXYZTexture" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A texture that shows 3 different curves (stored on the red, green and blue color channels).
</brief_description>
diff --git a/doc/classes/CylinderMesh.xml b/doc/classes/CylinderMesh.xml
index d1761325ac..34c192e4db 100644
--- a/doc/classes/CylinderMesh.xml
+++ b/doc/classes/CylinderMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CylinderMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CylinderMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Class representing a cylindrical [PrimitiveMesh].
</brief_description>
diff --git a/doc/classes/CylinderShape3D.xml b/doc/classes/CylinderShape3D.xml
index 1492e09591..8bec199ab6 100644
--- a/doc/classes/CylinderShape3D.xml
+++ b/doc/classes/CylinderShape3D.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CylinderShape3D" inherits="Shape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="CylinderShape3D" inherits="Shape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D cylinder shape used for physics collision.
</brief_description>
<description>
- A 2D capsule shape, intended for use in physics. Usually used to provide a shape for a [CollisionShape3D].
+ A 3D cylinder shape, intended for use in physics. Usually used to provide a shape for a [CollisionShape3D].
[b]Note:[/b] There are several known bugs with cylinder collision shapes. Using [CapsuleShape3D] or [BoxShape3D] instead is recommended.
- [b]Performance:[/b] [CylinderShape3D] is fast to check collisions against, but it is slower than [CapsuleShape3D], [BoxShape3D], and [CylinderShape3D].
+ [b]Performance:[/b] [CylinderShape3D] is fast to check collisions against, but it is slower than [CapsuleShape3D], [BoxShape3D], and [SphereShape3D].
</description>
<tutorials>
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
diff --git a/doc/classes/DTLSServer.xml b/doc/classes/DTLSServer.xml
index da452de946..f4c75a731d 100644
--- a/doc/classes/DTLSServer.xml
+++ b/doc/classes/DTLSServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="DTLSServer" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="DTLSServer" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Helper class to implement a DTLS server.
</brief_description>
diff --git a/doc/classes/DampedSpringJoint2D.xml b/doc/classes/DampedSpringJoint2D.xml
index 11a6e5bd30..c47a7d9303 100644
--- a/doc/classes/DampedSpringJoint2D.xml
+++ b/doc/classes/DampedSpringJoint2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="DampedSpringJoint2D" inherits="Joint2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="DampedSpringJoint2D" inherits="Joint2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics joint that connects two 2D physics bodies with a spring-like force.
</brief_description>
diff --git a/doc/classes/Decal.xml b/doc/classes/Decal.xml
index ace1d026d4..b89db8dc9e 100644
--- a/doc/classes/Decal.xml
+++ b/doc/classes/Decal.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Decal" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Decal" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Node that projects a texture onto a [MeshInstance3D].
</brief_description>
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index 515a54b27d..b39c5c9699 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Dictionary" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Dictionary" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A built-in data structure that holds key-value pairs.
</brief_description>
@@ -261,7 +261,7 @@
[/csharp]
[/codeblocks]
[b]Note:[/b] Dictionaries with the same entries but in a different order will not have the same hash.
- [b]Note:[/b] Dictionaries with equal hash values are [i]not[/i] guaranteed to be the same, because of hash collisions. On the countrary, dictionaries with different hash values are guaranteed to be different.
+ [b]Note:[/b] Dictionaries with equal hash values are [i]not[/i] guaranteed to be the same, because of hash collisions. On the contrary, dictionaries with different hash values are guaranteed to be different.
</description>
</method>
<method name="is_empty" qualifiers="const">
diff --git a/doc/classes/DirAccess.xml b/doc/classes/DirAccess.xml
index c98db3bc26..a987f4b5b4 100644
--- a/doc/classes/DirAccess.xml
+++ b/doc/classes/DirAccess.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="DirAccess" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="DirAccess" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides methods for managing directories and their content.
</brief_description>
diff --git a/doc/classes/DirectionalLight2D.xml b/doc/classes/DirectionalLight2D.xml
index f1419d0c7e..02909c95fa 100644
--- a/doc/classes/DirectionalLight2D.xml
+++ b/doc/classes/DirectionalLight2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="DirectionalLight2D" inherits="Light2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="DirectionalLight2D" inherits="Light2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Directional 2D light from a distance.
</brief_description>
diff --git a/doc/classes/DirectionalLight3D.xml b/doc/classes/DirectionalLight3D.xml
index 0da4343c26..1dbacd5ef7 100644
--- a/doc/classes/DirectionalLight3D.xml
+++ b/doc/classes/DirectionalLight3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="DirectionalLight3D" inherits="Light3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="DirectionalLight3D" inherits="Light3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Directional light from a distance, as from the Sun.
</brief_description>
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index f0e60d95ae..465855cc92 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="DisplayServer" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="DisplayServer" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A server interface for low-level window management.
</brief_description>
@@ -16,6 +16,12 @@
Returns the user's clipboard as a string if possible.
</description>
</method>
+ <method name="clipboard_get_image" qualifiers="const">
+ <return type="Image" />
+ <description>
+ Returns the user's clipboard as an image if possible.
+ </description>
+ </method>
<method name="clipboard_get_primary" qualifiers="const">
<return type="String" />
<description>
@@ -26,7 +32,13 @@
<method name="clipboard_has" qualifiers="const">
<return type="bool" />
<description>
- Returns [code]true[/code] if there is content on the user's clipboard.
+ Returns [code]true[/code] if there is a text content on the user's clipboard.
+ </description>
+ </method>
+ <method name="clipboard_has_image" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if there is an image content on the user's clipboard.
</description>
</method>
<method name="clipboard_set">
@@ -96,6 +108,24 @@
[b]Note:[/b] This method is implemented only on Windows.
</description>
</method>
+ <method name="file_dialog_show">
+ <return type="int" enum="Error" />
+ <param index="0" name="title" type="String" />
+ <param index="1" name="current_directory" type="String" />
+ <param index="2" name="filename" type="String" />
+ <param index="3" name="show_hidden" type="bool" />
+ <param index="4" name="mode" type="int" enum="DisplayServer.FileDialogMode" />
+ <param index="5" name="filters" type="PackedStringArray" />
+ <param index="6" name="callback" type="Callable" />
+ <description>
+ Displays OS native dialog for selecting files or directories in the file system.
+ Callbacks have the following arguments: [code]bool status, PackedStringArray selected_paths[/code].
+ [b]Note:[/b] This method is implemented if the display server has the [code]FEATURE_NATIVE_DIALOG[/code] feature.
+ [b]Note:[/b] This method is implemented on Windows and macOS.
+ [b]Note:[/b] On macOS, native file dialogs have no title.
+ [b]Note:[/b] On macOS, sandboxed apps will save security-scoped bookmarks to retain access to the opened folders across multiple sessions. Use [method OS.get_granted_permissions] to get a list of saved bookmarks.
+ </description>
+ </method>
<method name="force_process_and_drop_events">
<return type="void" />
<description>
@@ -757,7 +787,7 @@
<method name="is_touchscreen_available" qualifiers="const">
<return type="bool" />
<description>
- Returns [code]true[/code] if touch events are available (Android or iOS), the capability is detected on the Webplatform or if [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse] is [code]true[/code].
+ Returns [code]true[/code] if touch events are available (Android or iOS), the capability is detected on the Web platform or if [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse] is [code]true[/code].
</description>
</method>
<method name="keyboard_get_current_layout" qualifiers="const">
@@ -775,6 +805,14 @@
[b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows.
</description>
</method>
+ <method name="keyboard_get_label_from_physical" qualifiers="const">
+ <return type="int" enum="Key" />
+ <param index="0" name="keycode" type="int" enum="Key" />
+ <description>
+ Converts a physical (US QWERTY) [param keycode] to localized label printed on the key in the active keyboard layout.
+ [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows.
+ </description>
+ </method>
<method name="keyboard_get_layout_count" qualifiers="const">
<return type="int" />
<description>
@@ -1721,6 +1759,21 @@
<constant name="CURSOR_MAX" value="17" enum="CursorShape">
Represents the size of the [enum CursorShape] enum.
</constant>
+ <constant name="FILE_DIALOG_MODE_OPEN_FILE" value="0" enum="FileDialogMode">
+ The native file dialog allows selecting one, and only one file.
+ </constant>
+ <constant name="FILE_DIALOG_MODE_OPEN_FILES" value="1" enum="FileDialogMode">
+ The native file dialog allows selecting multiple files.
+ </constant>
+ <constant name="FILE_DIALOG_MODE_OPEN_DIR" value="2" enum="FileDialogMode">
+ The native file dialog only allows selecting a directory, disallowing the selection of any file.
+ </constant>
+ <constant name="FILE_DIALOG_MODE_OPEN_ANY" value="3" enum="FileDialogMode">
+ The native file dialog allows selecting one file or directory.
+ </constant>
+ <constant name="FILE_DIALOG_MODE_SAVE_FILE" value="4" enum="FileDialogMode">
+ The native file dialog will warn when a file exists.
+ </constant>
<constant name="WINDOW_MODE_WINDOWED" value="0" enum="WindowMode">
Windowed mode, i.e. [Window] doesn't occupy the whole screen (unless set to the size of the screen).
</constant>
diff --git a/doc/classes/EditorCommandPalette.xml b/doc/classes/EditorCommandPalette.xml
index 81f4a28017..df8bec8002 100644
--- a/doc/classes/EditorCommandPalette.xml
+++ b/doc/classes/EditorCommandPalette.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorCommandPalette" inherits="ConfirmationDialog" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorCommandPalette" inherits="ConfirmationDialog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Godot editor's command palette.
</brief_description>
diff --git a/doc/classes/EditorDebuggerPlugin.xml b/doc/classes/EditorDebuggerPlugin.xml
index 34aaff0036..6f6b4f69e4 100644
--- a/doc/classes/EditorDebuggerPlugin.xml
+++ b/doc/classes/EditorDebuggerPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorDebuggerPlugin" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorDebuggerPlugin" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A base class to implement debugger plugins.
</brief_description>
@@ -81,7 +81,7 @@
<return type="Array" />
<description>
Returns an array of [EditorDebuggerSession] currently available to this debugger plugin.
- Note: Not sessions in the array may be inactive, check their state via [method EditorDebuggerSession.is_active]
+ [b]Note:[/b] Not sessions in the array may be inactive, check their state via [method EditorDebuggerSession.is_active]
</description>
</method>
</methods>
diff --git a/doc/classes/EditorDebuggerSession.xml b/doc/classes/EditorDebuggerSession.xml
index 641d59a15a..c6c632be01 100644
--- a/doc/classes/EditorDebuggerSession.xml
+++ b/doc/classes/EditorDebuggerSession.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorDebuggerSession" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorDebuggerSession" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A class to interact with the editor debugger.
</brief_description>
diff --git a/doc/classes/EditorExportPlatform.xml b/doc/classes/EditorExportPlatform.xml
index bd15e6158e..48f3d46398 100644
--- a/doc/classes/EditorExportPlatform.xml
+++ b/doc/classes/EditorExportPlatform.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlatform" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorExportPlatform" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Identifies a supported export platform, and internally provides the functionality of exporting to that platform.
</brief_description>
diff --git a/doc/classes/EditorExportPlatformPC.xml b/doc/classes/EditorExportPlatformPC.xml
index 44df4f1884..3c2a27deab 100644
--- a/doc/classes/EditorExportPlatformPC.xml
+++ b/doc/classes/EditorExportPlatformPC.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlatformPC" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorExportPlatformPC" inherits="EditorExportPlatform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for the desktop platform exporter (Windows and Linux/BSD).
</brief_description>
diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml
index a5b42bb892..75641a4486 100644
--- a/doc/classes/EditorExportPlugin.xml
+++ b/doc/classes/EditorExportPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlugin" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorExportPlugin" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A script that is executed when exporting the project.
</brief_description>
@@ -8,6 +8,7 @@
To use [EditorExportPlugin], register it using the [method EditorPlugin.add_export_plugin] method first.
</description>
<tutorials>
+ <link title="Export Android plugins">$DOCS_URL/tutorials/platform/android/android_plugin.html</link>
</tutorials>
<methods>
<method name="_begin_customize_resources" qualifiers="virtual const">
@@ -84,6 +85,64 @@
Calling [method skip] inside this callback will make the file not included in the export.
</description>
</method>
+ <method name="_get_android_dependencies" qualifiers="virtual const">
+ <return type="PackedStringArray" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <param index="1" name="debug" type="bool" />
+ <description>
+ Virtual method to be overridden by the user. This is called to retrieve the set of Android dependencies provided by this plugin. Each returned Android dependency should have the format of an Android remote binary dependency: [code]org.godot.example:my-plugin:0.0.0[/code]
+ For more information see [url=https://developer.android.com/build/dependencies?agpversion=4.1#dependency-types]Android documentation on dependencies[/url].
+ [b]Note:[/b] Only supported on Android and requires [member EditorExportPlatformAndroid.gradle_build/use_gradle_build] to be enabled.
+ </description>
+ </method>
+ <method name="_get_android_dependencies_maven_repos" qualifiers="virtual const">
+ <return type="PackedStringArray" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <param index="1" name="debug" type="bool" />
+ <description>
+ Virtual method to be overridden by the user. This is called to retrieve the URLs of Maven repositories for the set of Android dependencies provided by this plugin.
+ For more information see [url=https://docs.gradle.org/current/userguide/dependency_management.html#sec:maven_repo]Gradle documentation on dependency management[/url].
+ [b]Note:[/b] Google's Maven repo and the Maven Central repo are already included by default.
+ [b]Note:[/b] Only supported on Android and requires [member EditorExportPlatformAndroid.gradle_build/use_gradle_build] to be enabled.
+ </description>
+ </method>
+ <method name="_get_android_libraries" qualifiers="virtual const">
+ <return type="PackedStringArray" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <param index="1" name="debug" type="bool" />
+ <description>
+ Virtual method to be overridden by the user. This is called to retrieve the local paths of the Android libraries archive (AAR) files provided by this plugin.
+ [b]Note:[/b] Relative paths **must** be relative to Godot's [code]res://addons/[/code] directory. For example, an AAR file located under [code]res://addons/hello_world_plugin/HelloWorld.release.aar[/code] can be returned as an absolute path using [code]res://addons/hello_world_plugin/HelloWorld.release.aar[/code] or a relative path using [code]hello_world_plugin/HelloWorld.release.aar[/code].
+ [b]Note:[/b] Only supported on Android and requires [member EditorExportPlatformAndroid.gradle_build/use_gradle_build] to be enabled.
+ </description>
+ </method>
+ <method name="_get_android_manifest_activity_element_contents" qualifiers="virtual const">
+ <return type="String" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <param index="1" name="debug" type="bool" />
+ <description>
+ Virtual method to be overridden by the user. This is used at export time to update the contents of the [code]activity[/code] element in the generated Android manifest.
+ [b]Note:[/b] Only supported on Android and requires [member EditorExportPlatformAndroid.gradle_build/use_gradle_build] to be enabled.
+ </description>
+ </method>
+ <method name="_get_android_manifest_application_element_contents" qualifiers="virtual const">
+ <return type="String" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <param index="1" name="debug" type="bool" />
+ <description>
+ Virtual method to be overridden by the user. This is used at export time to update the contents of the [code]application[/code] element in the generated Android manifest.
+ [b]Note:[/b] Only supported on Android and requires [member EditorExportPlatformAndroid.gradle_build/use_gradle_build] to be enabled.
+ </description>
+ </method>
+ <method name="_get_android_manifest_element_contents" qualifiers="virtual const">
+ <return type="String" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <param index="1" name="debug" type="bool" />
+ <description>
+ Virtual method to be overridden by the user. This is used at export time to update the contents of the [code]manifest[/code] element in the generated Android manifest.
+ [b]Note:[/b] Only supported on Android and requires [member EditorExportPlatformAndroid.gradle_build/use_gradle_build] to be enabled.
+ </description>
+ </method>
<method name="_get_customization_configuration_hash" qualifiers="virtual const">
<return type="int" />
<description>
@@ -99,6 +158,15 @@
Return a [PackedStringArray] of additional features this preset, for the given [param platform], should have.
</description>
</method>
+ <method name="_get_export_option_warning" qualifiers="virtual const">
+ <return type="String" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <param index="1" name="option" type="String" />
+ <description>
+ Check the requirements for the given [param option] and return a non-empty warning string if they are not met.
+ [b]Note:[/b] Use [method get_option] to check the value of the export options.
+ </description>
+ </method>
<method name="_get_export_options" qualifiers="virtual const">
<return type="Dictionary[]" />
<param index="0" name="platform" type="EditorExportPlatform" />
@@ -124,13 +192,21 @@
Return [code]true[/code], if the result of [method _get_export_options] has changed and the export options of preset corresponding to [param platform] should be updated.
</description>
</method>
+ <method name="_supports_platform" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <description>
+ Return [code]true[/code] if the plugin supports the given [param platform].
+ </description>
+ </method>
<method name="add_file">
<return type="void" />
<param index="0" name="path" type="String" />
<param index="1" name="file" type="PackedByteArray" />
<param index="2" name="remap" type="bool" />
<description>
- Adds a custom file to be exported. [param path] is the virtual path that can be used to load the file, [param file] is the binary data of the file. If [param remap] is [code]true[/code], file will not be exported, but instead remapped to the given [param path].
+ Adds a custom file to be exported. [param path] is the virtual path that can be used to load the file, [param file] is the binary data of the file.
+ When called inside [method _export_file] and [param remap] is [code]true[/code], the current file will not be exported, but instead remapped to this custom file. [param remap] is ignored when called in other places.
</description>
</method>
<method name="add_ios_bundle_file">
diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml
index 3a2349f8ec..3aa1e63aac 100644
--- a/doc/classes/EditorFeatureProfile.xml
+++ b/doc/classes/EditorFeatureProfile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorFeatureProfile" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorFeatureProfile" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An editor feature profile which can be used to disable specific features.
</brief_description>
@@ -51,6 +51,7 @@
<param index="0" name="path" type="String" />
<description>
Loads an editor feature profile from a file. The file must follow the JSON format obtained by using the feature profile manager's [b]Export[/b] button or the [method save_to_file] method.
+ [b]Note:[/b] Feature profiles created via the user interface are loaded from the [code]feature_profiles[/code] directory, as a file with the [code].profile[/code] extension. The editor configuration folder can be found by using [method EditorPaths.get_config_dir].
</description>
</method>
<method name="save_to_file">
@@ -58,6 +59,7 @@
<param index="0" name="path" type="String" />
<description>
Saves the editor feature profile to a file in JSON format. It can then be imported using the feature profile manager's [b]Import[/b] button or the [method load_from_file] method.
+ [b]Note:[/b] Feature profiles created via the user interface are saved in the [code]feature_profiles[/code] directory, as a file with the [code].profile[/code] extension. The editor configuration folder can be found by using [method EditorPaths.get_config_dir].
</description>
</method>
<method name="set_disable_class">
diff --git a/doc/classes/EditorFileDialog.xml b/doc/classes/EditorFileDialog.xml
index 1585b28be0..42cb420e74 100644
--- a/doc/classes/EditorFileDialog.xml
+++ b/doc/classes/EditorFileDialog.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorFileDialog" inherits="ConfirmationDialog" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorFileDialog" inherits="ConfirmationDialog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modified version of [FileDialog] used by the editor.
</brief_description>
diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml
index 48f1a13490..08b40c7800 100644
--- a/doc/classes/EditorFileSystem.xml
+++ b/doc/classes/EditorFileSystem.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorFileSystem" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorFileSystem" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Resource filesystem, as the editor sees it.
</brief_description>
diff --git a/doc/classes/EditorFileSystemDirectory.xml b/doc/classes/EditorFileSystemDirectory.xml
index b95e714cb7..e271b3156e 100644
--- a/doc/classes/EditorFileSystemDirectory.xml
+++ b/doc/classes/EditorFileSystemDirectory.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorFileSystemDirectory" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorFileSystemDirectory" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A directory for the resource filesystem.
</brief_description>
diff --git a/doc/classes/EditorFileSystemImportFormatSupportQuery.xml b/doc/classes/EditorFileSystemImportFormatSupportQuery.xml
index 1108997c4f..b1a810fe6e 100644
--- a/doc/classes/EditorFileSystemImportFormatSupportQuery.xml
+++ b/doc/classes/EditorFileSystemImportFormatSupportQuery.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorFileSystemImportFormatSupportQuery" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorFileSystemImportFormatSupportQuery" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Used to query and configure import format support.
</brief_description>
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index e3bd78dacf..d1361c4f0d 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorImportPlugin" inherits="ResourceImporter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorImportPlugin" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Registers a custom resource importer in the editor. Use the class to parse any file and import it as a new resource type.
</brief_description>
diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml
index 377a3b5a6a..d55c1847e4 100644
--- a/doc/classes/EditorInspector.xml
+++ b/doc/classes/EditorInspector.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorInspector" inherits="ScrollContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorInspector" inherits="ScrollContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control used to edit properties of an object.
</brief_description>
diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml
index 340e22c46a..efa881591c 100644
--- a/doc/classes/EditorInspectorPlugin.xml
+++ b/doc/classes/EditorInspectorPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorInspectorPlugin" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorInspectorPlugin" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plugin for adding custom property editors on the inspector.
</brief_description>
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index effce40b12..cabd9c0da6 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorInterface" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorInterface" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Godot editor's interface.
</brief_description>
@@ -54,6 +54,14 @@
Returns the current directory being viewed in the [FileSystemDock]. If a file is selected, its base directory will be returned using [method String.get_base_dir] instead.
</description>
</method>
+ <method name="get_current_feature_profile" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the name of the currently activated feature profile. If the default profile is currently active, an empty string is returned instead.
+ In order to get a reference to the [EditorFeatureProfile], you must load the feature profile using [method EditorFeatureProfile.load_from_file].
+ [b]Note:[/b] Feature profiles created via the user interface are loaded from the [code]feature_profiles[/code] directory, as a file with the [code].profile[/code] extension. The editor configuration folder can be found by using [method EditorPaths.get_config_dir].
+ </description>
+ </method>
<method name="get_current_path" qualifiers="const">
<return type="String" />
<description>
@@ -262,10 +270,16 @@
Restarts the editor. This closes the editor and then opens the same project. If [param save] is [code]true[/code], the project will be saved before restarting.
</description>
</method>
+ <method name="save_all_scenes">
+ <return type="void" />
+ <description>
+ Saves all opened scenes in the editor.
+ </description>
+ </method>
<method name="save_scene">
<return type="int" enum="Error" />
<description>
- Saves the scene. Returns either [constant OK] or [constant ERR_CANT_CREATE].
+ Saves the currently active scene. Returns either [constant OK] or [constant ERR_CANT_CREATE].
</description>
</method>
<method name="save_scene_as">
@@ -273,7 +287,7 @@
<param index="0" name="path" type="String" />
<param index="1" name="with_preview" type="bool" default="true" />
<description>
- Saves the scene as a file at [param path].
+ Saves the currently active scene as a file at [param path].
</description>
</method>
<method name="select_file">
@@ -283,6 +297,15 @@
Selects the file, with the path provided by [param file], in the FileSystem dock.
</description>
</method>
+ <method name="set_current_feature_profile">
+ <return type="void" />
+ <param index="0" name="profile_name" type="String" />
+ <description>
+ Selects and activates the specified feature profile with the given [param profile_name]. Set [param profile_name] to an empty string to reset to the default feature profile.
+ A feature profile can be created programmatically using the [EditorFeatureProfile] class.
+ [b]Note:[/b] The feature profile that gets activated must be located in the [code]feature_profiles[/code] directory, as a file with the [code].profile[/code] extension. If a profile could not be found, an error occurs. The editor configuration folder can be found by using [method EditorPaths.get_config_dir].
+ </description>
+ </method>
<method name="set_main_screen_editor">
<return type="void" />
<param index="0" name="name" type="String" />
diff --git a/doc/classes/EditorNode3DGizmo.xml b/doc/classes/EditorNode3DGizmo.xml
index ad915c8237..371651c31d 100644
--- a/doc/classes/EditorNode3DGizmo.xml
+++ b/doc/classes/EditorNode3DGizmo.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorNode3DGizmo" inherits="Node3DGizmo" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorNode3DGizmo" inherits="Node3DGizmo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Gizmo for editing Node3D objects.
</brief_description>
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
index 55d1a38c3e..3e90c54647 100644
--- a/doc/classes/EditorNode3DGizmoPlugin.xml
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorNode3DGizmoPlugin" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorNode3DGizmoPlugin" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A class used by the editor to define Node3D gizmo types.
</brief_description>
diff --git a/doc/classes/EditorPaths.xml b/doc/classes/EditorPaths.xml
index c4b9eda24c..94ddb37658 100644
--- a/doc/classes/EditorPaths.xml
+++ b/doc/classes/EditorPaths.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorPaths" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorPaths" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Editor-only singleton that returns paths to various OS-specific data folders and files.
</brief_description>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 1f3f028bbe..ffb4df25d3 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorPlugin" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorPlugin" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Used by the editor to extend its functionality.
</brief_description>
@@ -280,6 +280,34 @@
[/codeblock]
</description>
</method>
+ <method name="_get_unsaved_status" qualifiers="virtual const">
+ <return type="String" />
+ <param index="0" name="for_scene" type="String" />
+ <description>
+ Override this method to provide a custom message that lists unsaved changes. The editor will call this method when exiting or when closing a scene, and display the returned string in a confirmation dialog. Return empty string if the plugin has no unsaved changes.
+ When closing a scene, [param for_scene] is the path to the scene being closed. You can use it to handle built-in resources in that scene.
+ If the user confirms saving, [method _save_external_data] will be called, before closing the editor.
+ [codeblock]
+ func _get_unsaved_status(for_scene):
+ if not unsaved:
+ return ""
+
+ if for_scene.is_empty():
+ return "Save changes in MyCustomPlugin before closing?"
+ else:
+ return "Scene %s has changes from MyCustomPlugin. Save before closing?" % for_scene.get_file()
+
+ func _save_external_data():
+ unsaved = false
+ [/codeblock]
+ If the plugin has no scene-specific changes, you can ignore the calls when closing scenes:
+ [codeblock]
+ func _get_unsaved_status(for_scene):
+ if not for_scene.is_empty():
+ return ""
+ [/codeblock]
+ </description>
+ </method>
<method name="_get_window_layout" qualifiers="virtual">
<return type="void" />
<param index="0" name="configuration" type="ConfigFile" />
@@ -298,6 +326,7 @@
<param index="0" name="object" type="Object" />
<description>
Implement this function if your plugin edits a specific type of object (Resource or Node). If you return [code]true[/code], then you will get the functions [method _edit] and [method _make_visible] called when the editor requests them. If you have declared the methods [method _forward_canvas_gui_input] and [method _forward_3d_gui_input] these will be called too.
+ [b]Note:[/b] Each plugin should handle only one type of objects at a time. If a plugin handes more types of objects and they are edited at the same time, it will result in errors.
</description>
</method>
<method name="_has_main_screen" qualifiers="virtual const">
@@ -541,6 +570,12 @@
Returns the [PopupMenu] under [b]Scene &gt; Export As...[/b].
</description>
</method>
+ <method name="get_plugin_version" qualifiers="const">
+ <return type="String" />
+ <description>
+ Provide the version of the plugin declared in the [code]plugin.cfg[/code] config file.
+ </description>
+ </method>
<method name="get_script_create_dialog">
<return type="ScriptCreateDialog" />
<description>
diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml
index 3e9d98f67a..4fd288f16d 100644
--- a/doc/classes/EditorProperty.xml
+++ b/doc/classes/EditorProperty.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorProperty" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorProperty" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Custom control for editing properties that can be added to the [EditorInspector].
</brief_description>
diff --git a/doc/classes/EditorResourceConversionPlugin.xml b/doc/classes/EditorResourceConversionPlugin.xml
index c84f8e4ec5..b0c2071442 100644
--- a/doc/classes/EditorResourceConversionPlugin.xml
+++ b/doc/classes/EditorResourceConversionPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorResourceConversionPlugin" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorResourceConversionPlugin" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plugin for adding custom converters from one resource format to another in the editor resource picker context menu; for example, converting a [StandardMaterial3D] to a [ShaderMaterial].
</brief_description>
diff --git a/doc/classes/EditorResourcePicker.xml b/doc/classes/EditorResourcePicker.xml
index 3daa84a2da..f139502e18 100644
--- a/doc/classes/EditorResourcePicker.xml
+++ b/doc/classes/EditorResourcePicker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorResourcePicker" inherits="HBoxContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorResourcePicker" inherits="HBoxContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Godot editor's control for selecting [Resource] type properties.
</brief_description>
diff --git a/doc/classes/EditorResourcePreview.xml b/doc/classes/EditorResourcePreview.xml
index b85629912e..d8c5855932 100644
--- a/doc/classes/EditorResourcePreview.xml
+++ b/doc/classes/EditorResourcePreview.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorResourcePreview" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorResourcePreview" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node used to generate previews of resources or files.
</brief_description>
diff --git a/doc/classes/EditorResourcePreviewGenerator.xml b/doc/classes/EditorResourcePreviewGenerator.xml
index e69c6489df..e504bf7980 100644
--- a/doc/classes/EditorResourcePreviewGenerator.xml
+++ b/doc/classes/EditorResourcePreviewGenerator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorResourcePreviewGenerator" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorResourcePreviewGenerator" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Custom generator of previews.
</brief_description>
diff --git a/doc/classes/EditorResourceTooltipPlugin.xml b/doc/classes/EditorResourceTooltipPlugin.xml
index f6ce99b878..69c5f30f25 100644
--- a/doc/classes/EditorResourceTooltipPlugin.xml
+++ b/doc/classes/EditorResourceTooltipPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorResourceTooltipPlugin" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorResourceTooltipPlugin" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A plugin that advanced tooltip for its handled resource type.
</brief_description>
diff --git a/doc/classes/EditorSceneFormatImporter.xml b/doc/classes/EditorSceneFormatImporter.xml
index 64dd26dc74..b507273117 100644
--- a/doc/classes/EditorSceneFormatImporter.xml
+++ b/doc/classes/EditorSceneFormatImporter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneFormatImporter" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorSceneFormatImporter" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Imports scenes from third-parties' 3D files.
</brief_description>
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index b36dd6fddd..e98edef44c 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorScenePostImport" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorScenePostImport" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Post-processes scenes after import.
</brief_description>
diff --git a/doc/classes/EditorScenePostImportPlugin.xml b/doc/classes/EditorScenePostImportPlugin.xml
index 5b1214e0d7..5c1c898c9d 100644
--- a/doc/classes/EditorScenePostImportPlugin.xml
+++ b/doc/classes/EditorScenePostImportPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorScenePostImportPlugin" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorScenePostImportPlugin" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plugin to control and modifying the process of importing a scene.
</brief_description>
diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml
index d77d11857b..01e6b9a52e 100644
--- a/doc/classes/EditorScript.xml
+++ b/doc/classes/EditorScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorScript" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorScript" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base script that can be used to add extension functions to the editor.
</brief_description>
diff --git a/doc/classes/EditorScriptPicker.xml b/doc/classes/EditorScriptPicker.xml
index c8ca41c2ce..31a1c50379 100644
--- a/doc/classes/EditorScriptPicker.xml
+++ b/doc/classes/EditorScriptPicker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorScriptPicker" inherits="EditorResourcePicker" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorScriptPicker" inherits="EditorResourcePicker" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Godot editor's control for selecting the [code]script[/code] property of a [Node].
</brief_description>
diff --git a/doc/classes/EditorSelection.xml b/doc/classes/EditorSelection.xml
index da609bcc3f..09aae04d04 100644
--- a/doc/classes/EditorSelection.xml
+++ b/doc/classes/EditorSelection.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSelection" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorSelection" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Manages the SceneTree selection in the editor.
</brief_description>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index c674482725..85efe4362e 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSettings" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorSettings" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Object that holds the project-independent editor settings.
</brief_description>
@@ -232,14 +232,16 @@
<member name="editors/2d/bone_outline_color" type="Color" setter="" getter="">
The outline color to use for non-selected bones in the 2D skeleton editor. See also [member editors/2d/bone_selected_color].
</member>
- <member name="editors/2d/bone_outline_size" type="int" setter="" getter="">
+ <member name="editors/2d/bone_outline_size" type="float" setter="" getter="">
The outline size in the 2D skeleton editor (in pixels). See also [member editors/2d/bone_width].
+ [b]Note:[/b] Changes to this value only apply after modifying a [Bone2D] node in any way, or closing and reopening the scene.
</member>
<member name="editors/2d/bone_selected_color" type="Color" setter="" getter="">
The color to use for selected bones in the 2D skeleton editor. See also [member editors/2d/bone_outline_color].
</member>
- <member name="editors/2d/bone_width" type="int" setter="" getter="">
+ <member name="editors/2d/bone_width" type="float" setter="" getter="">
The bone width in the 2D skeleton editor (in pixels). See also [member editors/2d/bone_outline_size].
+ [b]Note:[/b] Changes to this value only apply after modifying a [Bone2D] node in any way, or closing and reopening the scene.
</member>
<member name="editors/2d/grid_color" type="Color" setter="" getter="">
The grid color to use in the 2D editor.
@@ -250,6 +252,9 @@
<member name="editors/2d/smart_snapping_line_color" type="Color" setter="" getter="">
The color to use when drawing smart snapping lines in the 2D editor. The smart snapping lines will automatically display when moving 2D nodes if smart snapping is enabled in the Snapping Options menu at the top of the 2D editor viewport.
</member>
+ <member name="editors/2d/use_integer_zoom_by_default" type="bool" setter="" getter="">
+ If [code]true[/code], the 2D editor will snap to integer zoom values while not holding the [kbd]Alt[/kbd] key and powers of two while holding it. If [code]false[/code], this behavior is swapped.
+ </member>
<member name="editors/2d/viewport_border_color" type="Color" setter="" getter="">
The color of the viewport border in the 2D editor. This border represents the viewport's size at the base resolution defined in the Project Settings. Objects placed outside this border will not be visible unless a [Camera2D] node is used, or unless the window is resized and the stretch mode is set to [code]disabled[/code].
</member>
@@ -384,9 +389,6 @@
<member name="editors/animation/autorename_animation_tracks" type="bool" setter="" getter="">
If [code]true[/code], automatically updates animation tracks' target paths when renaming or reparenting nodes in the Scene tree dock.
</member>
- <member name="editors/animation/confirm_insert_track" type="bool" setter="" getter="">
- If [code]true[/code], display a confirmation dialog when adding a new track to an animation by pressing the "key" icon next to a property.
- </member>
<member name="editors/animation/default_create_bezier_tracks" type="bool" setter="" getter="">
If [code]true[/code], create a Bezier track instead of a standard track when pressing the "key" icon next to a property. Bezier tracks provide more control over animation curves, but are more difficult to adjust quickly.
</member>
@@ -837,6 +839,9 @@
<member name="text_editor/completion/code_complete_delay" type="float" setter="" getter="">
The delay in seconds after which autocompletion suggestions should be displayed when the user stops typing.
</member>
+ <member name="text_editor/completion/code_complete_enabled" type="bool" setter="" getter="">
+ If [code]true[/code], code completion will be triggered automatically after [member text_editor/completion/code_complete_delay]. If [code]false[/code], you can still trigger completion manually by pressing [kbd]Ctrl + Space[/kbd] ([kbd]Cmd + Space[/kbd] on macOS).
+ </member>
<member name="text_editor/completion/complete_file_paths" type="bool" setter="" getter="">
If [code]true[/code], provides autocompletion suggestions for file paths in methods such as [code]load()[/code] and [code]preload()[/code].
</member>
diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml
index 045a1796dd..6e5ccb4dd0 100644
--- a/doc/classes/EditorSpinSlider.xml
+++ b/doc/classes/EditorSpinSlider.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSpinSlider" inherits="Range" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorSpinSlider" inherits="Range" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Godot editor's control for editing numeric values.
</brief_description>
diff --git a/doc/classes/EditorSyntaxHighlighter.xml b/doc/classes/EditorSyntaxHighlighter.xml
index 3d8ba0118e..3bc845352f 100644
--- a/doc/classes/EditorSyntaxHighlighter.xml
+++ b/doc/classes/EditorSyntaxHighlighter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSyntaxHighlighter" inherits="SyntaxHighlighter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorSyntaxHighlighter" inherits="SyntaxHighlighter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for [SyntaxHighlighter] used by the [ScriptEditor].
</brief_description>
diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml
index c32ebba520..a47a41594e 100644
--- a/doc/classes/EditorTranslationParserPlugin.xml
+++ b/doc/classes/EditorTranslationParserPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorTranslationParserPlugin" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorTranslationParserPlugin" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Plugin for adding custom parsers to extract strings that are to be translated from custom files (.csv, .json etc.).
</brief_description>
diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml
index 553e36bd42..26580bbf06 100644
--- a/doc/classes/EditorUndoRedoManager.xml
+++ b/doc/classes/EditorUndoRedoManager.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorUndoRedoManager" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorUndoRedoManager" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Manages undo history of scenes opened in the editor.
</brief_description>
diff --git a/doc/classes/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml
index 031d2a50c3..baf69f2c6d 100644
--- a/doc/classes/EditorVCSInterface.xml
+++ b/doc/classes/EditorVCSInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorVCSInterface" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorVCSInterface" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Version Control System (VCS) interface, which reads and writes to the local VCS in use.
</brief_description>
@@ -240,7 +240,7 @@
<return type="void" />
<param index="0" name="msg" type="String" />
<description>
- Pops up an error message in the edior which is shown as coming from the underlying VCS. Use this to show VCS specific error messages.
+ Pops up an error message in the editor which is shown as coming from the underlying VCS. Use this to show VCS specific error messages.
</description>
</method>
</methods>
diff --git a/doc/classes/EncodedObjectAsID.xml b/doc/classes/EncodedObjectAsID.xml
index 5b4e718e16..c930e6f579 100644
--- a/doc/classes/EncodedObjectAsID.xml
+++ b/doc/classes/EncodedObjectAsID.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EncodedObjectAsID" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EncodedObjectAsID" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds a reference to an [Object]'s instance ID.
</brief_description>
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index c695c3348e..207cd0bccc 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Engine" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Engine" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides access to engine properties.
</brief_description>
@@ -12,20 +12,20 @@
<method name="get_architecture_name" qualifiers="const">
<return type="String" />
<description>
- Returns the name of the CPU architecture the Godot binary was built for. Possible return values are [code]x86_64[/code], [code]x86_32[/code], [code]arm64[/code], [code]armv7[/code], [code]rv64[/code], [code]riscv[/code], [code]ppc64[/code], [code]ppc[/code], [code]wasm64[/code] and [code]wasm32[/code].
+ Returns the name of the CPU architecture the Godot binary was built for. Possible return values are [code]x86_64[/code], [code]x86_32[/code], [code]arm64[/code], [code]arm32[/code], [code]rv64[/code], [code]riscv[/code], [code]ppc64[/code], [code]ppc[/code], [code]wasm64[/code] and [code]wasm32[/code].
To detect whether the current CPU architecture is 64-bit, you can use the fact that all 64-bit architecture names have [code]64[/code] in their name:
[codeblocks]
[gdscript]
if "64" in Engine.get_architecture_name():
- print("Running on 64-bit CPU.")
+ print("Running a 64-bit build of Godot.")
else:
- print("Running on 32-bit CPU.")
+ print("Running a 32-bit build of Godot.")
[/gdscript]
[csharp]
if (Engine.GetArchitectureName().Contains("64"))
- GD.Print("Running on 64-bit CPU.");
+ GD.Print("Running a 64-bit build of Godot.");
else
- GD.Print("Running on 32-bit CPU.");
+ GD.Print("Running a 32-bit build of Godot.");
[/csharp]
[/codeblocks]
[b]Note:[/b] [method get_architecture_name] does [i]not[/i] return the name of the host CPU architecture. For example, if running an x86_32 Godot binary on a x86_64 system, the returned value will be [code]x86_32[/code].
diff --git a/doc/classes/EngineDebugger.xml b/doc/classes/EngineDebugger.xml
index 45317be394..29ac04f097 100644
--- a/doc/classes/EngineDebugger.xml
+++ b/doc/classes/EngineDebugger.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EngineDebugger" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EngineDebugger" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exposes the internal debugger.
</brief_description>
diff --git a/doc/classes/EngineProfiler.xml b/doc/classes/EngineProfiler.xml
index 9726391e90..a974a3af6a 100644
--- a/doc/classes/EngineProfiler.xml
+++ b/doc/classes/EngineProfiler.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EngineProfiler" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EngineProfiler" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for creating custom profilers.
</brief_description>
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index f09ea463c5..e2f76480a0 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Environment" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Environment" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Resource for environment nodes (like [WorldEnvironment]) that define multiple rendering options.
</brief_description>
diff --git a/doc/classes/Expression.xml b/doc/classes/Expression.xml
index ff04440a04..02ff4e1c2d 100644
--- a/doc/classes/Expression.xml
+++ b/doc/classes/Expression.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Expression" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Expression" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A class that stores an expression you can execute.
</brief_description>
diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml
index 261e039cb0..5c1f6775a1 100644
--- a/doc/classes/FileAccess.xml
+++ b/doc/classes/FileAccess.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="FileAccess" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="FileAccess" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides methods for file reading and writing operations.
</brief_description>
diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml
index fe448d381a..75856e91d8 100644
--- a/doc/classes/FileDialog.xml
+++ b/doc/classes/FileDialog.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="FileDialog" inherits="ConfirmationDialog" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="FileDialog" inherits="ConfirmationDialog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A dialog for selecting files or directories in the filesystem.
</brief_description>
@@ -83,6 +83,10 @@
If [code]true[/code], the dialog will show hidden files.
</member>
<member name="title" type="String" setter="set_title" getter="get_title" overrides="Window" default="&quot;Save a File&quot;" />
+ <member name="use_native_dialog" type="bool" setter="set_use_native_dialog" getter="get_use_native_dialog" default="false">
+ If [code]true[/code], [member access] is set to [constant ACCESS_FILESYSTEM], and it is supported by the current [DisplayServer], OS native dialog will be used instead of custom one.
+ [b]Note:[/b] On macOS, sandboxed apps always use native dialogs to access host filesystem.
+ </member>
</members>
<signals>
<signal name="dir_selected">
diff --git a/doc/classes/FileSystemDock.xml b/doc/classes/FileSystemDock.xml
index 512fa431f9..9028dd4b9f 100644
--- a/doc/classes/FileSystemDock.xml
+++ b/doc/classes/FileSystemDock.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="FileSystemDock" inherits="VBoxContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="FileSystemDock" inherits="VBoxContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Godot editor's dock for managing files in the project.
</brief_description>
diff --git a/doc/classes/FlowContainer.xml b/doc/classes/FlowContainer.xml
index 9636a0fbc7..14e84b40e6 100644
--- a/doc/classes/FlowContainer.xml
+++ b/doc/classes/FlowContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="FlowContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="FlowContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that arranges its child controls horizontally or vertically and wraps them around at the borders.
</brief_description>
diff --git a/doc/classes/FogMaterial.xml b/doc/classes/FogMaterial.xml
index 674bc53f62..13366f1813 100644
--- a/doc/classes/FogMaterial.xml
+++ b/doc/classes/FogMaterial.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="FogMaterial" inherits="Material" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="FogMaterial" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
[Material] used with a [FogVolume] to draw things with the volumetric fog effect.
</brief_description>
diff --git a/doc/classes/FogVolume.xml b/doc/classes/FogVolume.xml
index 8904fe6782..66aeb580c2 100644
--- a/doc/classes/FogVolume.xml
+++ b/doc/classes/FogVolume.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="FogVolume" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="FogVolume" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node used to add local fog with the volumetric fog effect.
</brief_description>
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index 5d34e38b13..461e96def4 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Font" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Font" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for fonts and font variations.
</brief_description>
diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml
index 7f438435bd..ba4761e900 100644
--- a/doc/classes/FontFile.xml
+++ b/doc/classes/FontFile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="FontFile" inherits="Font" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="FontFile" inherits="Font" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds font source data and prerendered glyph cache, imported from a dynamic or a bitmap font.
</brief_description>
@@ -134,7 +134,7 @@
<return type="int" />
<param index="0" name="cache_index" type="int" />
<description>
- Recturns an active face index in the TrueType / OpenType collection.
+ Returns an active face index in the TrueType / OpenType collection.
</description>
</method>
<method name="get_glyph_advance" qualifiers="const">
diff --git a/doc/classes/FontVariation.xml b/doc/classes/FontVariation.xml
index ede341e71f..eb72b4020c 100644
--- a/doc/classes/FontVariation.xml
+++ b/doc/classes/FontVariation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="FontVariation" inherits="Font" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="FontVariation" inherits="Font" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A variation of a font with additional settings.
</brief_description>
diff --git a/doc/classes/GDExtension.xml b/doc/classes/GDExtension.xml
index 573c88c7c1..ee55c89131 100644
--- a/doc/classes/GDExtension.xml
+++ b/doc/classes/GDExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDExtension" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GDExtension" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/GDExtensionManager.xml b/doc/classes/GDExtensionManager.xml
index 6519fbd8b9..94501b0662 100644
--- a/doc/classes/GDExtensionManager.xml
+++ b/doc/classes/GDExtensionManager.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDExtensionManager" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GDExtensionManager" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index d59ece4ab6..2928215c3e 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticles2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticles2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
2D particle emitter.
</brief_description>
@@ -18,6 +18,7 @@
<return type="Rect2" />
<description>
Returns a rectangle containing the positions of all existing particles.
+ [b]Note:[/b] When using threaded rendering this method synchronizes the rendering thread. Calling it often may have a negative impact on performance.
</description>
</method>
<method name="emit_particle">
@@ -49,7 +50,7 @@
Particle draw order. Uses [enum DrawOrder] values.
</member>
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
- If [code]true[/code], particles are being emitted.
+ If [code]true[/code], particles are being emitted. [member emitting] can be used to start and stop particles from emitting. However, if [member one_shot] is [code]true[/code] setting [member emitting] to [code]true[/code] will not restart the emission cycle until after all active particles finish processing. You can use the [signal finished] signal to be notified once all active particles finish processing.
</member>
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
@@ -108,6 +109,14 @@
Grow the rect if particles suddenly appear/disappear when the node enters/exits the screen. The [Rect2] can be grown via code or with the [b]Particles → Generate Visibility Rect[/b] editor tool.
</member>
</members>
+ <signals>
+ <signal name="finished">
+ <description>
+ Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
+ [b]Note:[/b] Due to the particles being computed on the GPU there might be a delay before the signal gets emitted.
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
Particles are drawn in the order emitted.
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index f03c8f7d41..4c0b2d12ed 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticles3D" inherits="GeometryInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticles3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
3D particle emitter.
</brief_description>
@@ -78,7 +78,7 @@
<member name="draw_skin" type="Skin" setter="set_skin" getter="get_skin">
</member>
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
- If [code]true[/code], particles are being emitted.
+ If [code]true[/code], particles are being emitted. [member emitting] can be used to start and stop particles from emitting. However, if [member one_shot] is [code]true[/code] setting [member emitting] to [code]true[/code] will not restart the emission cycle until after all active particles finish processing. You can use the [signal finished] signal to be notified once all active particles finish processing.
</member>
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
Time ratio between each emission. If [code]0[/code], particles are emitted continuously. If [code]1[/code], all particles are emitted simultaneously.
@@ -130,6 +130,14 @@
Grow the box if particles suddenly appear/disappear when the node enters/exits the screen. The [AABB] can be grown via code or with the [b]Particles → Generate AABB[/b] editor tool.
</member>
</members>
+ <signals>
+ <signal name="finished">
+ <description>
+ Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
+ [b]Note:[/b] Due to the particles being computed on the GPU there might be a delay before the signal gets emitted.
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
Particles are drawn in the order emitted.
diff --git a/doc/classes/GPUParticlesAttractor3D.xml b/doc/classes/GPUParticlesAttractor3D.xml
index 753637f075..b3ed3b4701 100644
--- a/doc/classes/GPUParticlesAttractor3D.xml
+++ b/doc/classes/GPUParticlesAttractor3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticlesAttractor3D" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticlesAttractor3D" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract class for 3D particle attractors affecting [GPUParticles3D] nodes.
</brief_description>
diff --git a/doc/classes/GPUParticlesAttractorBox3D.xml b/doc/classes/GPUParticlesAttractorBox3D.xml
index 8f6372a43f..d43efc73bf 100644
--- a/doc/classes/GPUParticlesAttractorBox3D.xml
+++ b/doc/classes/GPUParticlesAttractorBox3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticlesAttractorBox3D" inherits="GPUParticlesAttractor3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticlesAttractorBox3D" inherits="GPUParticlesAttractor3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Box-shaped 3D particle attractor affecting [GPUParticles3D] nodes.
</brief_description>
diff --git a/doc/classes/GPUParticlesAttractorSphere3D.xml b/doc/classes/GPUParticlesAttractorSphere3D.xml
index fef626fd9c..05c1e60d9a 100644
--- a/doc/classes/GPUParticlesAttractorSphere3D.xml
+++ b/doc/classes/GPUParticlesAttractorSphere3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticlesAttractorSphere3D" inherits="GPUParticlesAttractor3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticlesAttractorSphere3D" inherits="GPUParticlesAttractor3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Ellipse-shaped 3D particle attractor affecting [GPUParticles3D] nodes.
</brief_description>
diff --git a/doc/classes/GPUParticlesAttractorVectorField3D.xml b/doc/classes/GPUParticlesAttractorVectorField3D.xml
index f069ecafbe..ef9a11e57c 100644
--- a/doc/classes/GPUParticlesAttractorVectorField3D.xml
+++ b/doc/classes/GPUParticlesAttractorVectorField3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticlesAttractorVectorField3D" inherits="GPUParticlesAttractor3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticlesAttractorVectorField3D" inherits="GPUParticlesAttractor3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Box-shaped 3D particle attractor with strength varying within the box, affecting [GPUParticles3D] nodes.
</brief_description>
diff --git a/doc/classes/GPUParticlesCollision3D.xml b/doc/classes/GPUParticlesCollision3D.xml
index ae79ffb8a8..9471a7caf2 100644
--- a/doc/classes/GPUParticlesCollision3D.xml
+++ b/doc/classes/GPUParticlesCollision3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticlesCollision3D" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticlesCollision3D" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract class for 3D particle collision shapes affecting [GPUParticles3D] nodes.
</brief_description>
diff --git a/doc/classes/GPUParticlesCollisionBox3D.xml b/doc/classes/GPUParticlesCollisionBox3D.xml
index c6b623ff8e..4bb947a82d 100644
--- a/doc/classes/GPUParticlesCollisionBox3D.xml
+++ b/doc/classes/GPUParticlesCollisionBox3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticlesCollisionBox3D" inherits="GPUParticlesCollision3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticlesCollisionBox3D" inherits="GPUParticlesCollision3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Box-shaped 3D particle collision shape affecting [GPUParticles3D] nodes.
</brief_description>
diff --git a/doc/classes/GPUParticlesCollisionHeightField3D.xml b/doc/classes/GPUParticlesCollisionHeightField3D.xml
index 4c55aa225c..58219aa0b3 100644
--- a/doc/classes/GPUParticlesCollisionHeightField3D.xml
+++ b/doc/classes/GPUParticlesCollisionHeightField3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticlesCollisionHeightField3D" inherits="GPUParticlesCollision3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticlesCollisionHeightField3D" inherits="GPUParticlesCollision3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Real-time heightmap-shaped 3D particle attractor affecting [GPUParticles3D] nodes.
</brief_description>
diff --git a/doc/classes/GPUParticlesCollisionSDF3D.xml b/doc/classes/GPUParticlesCollisionSDF3D.xml
index 170504c1c9..b61be49619 100644
--- a/doc/classes/GPUParticlesCollisionSDF3D.xml
+++ b/doc/classes/GPUParticlesCollisionSDF3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticlesCollisionSDF3D" inherits="GPUParticlesCollision3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticlesCollisionSDF3D" inherits="GPUParticlesCollision3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Baked signed distance field 3D particle attractor affecting [GPUParticles3D] nodes.
</brief_description>
diff --git a/doc/classes/GPUParticlesCollisionSphere3D.xml b/doc/classes/GPUParticlesCollisionSphere3D.xml
index 42ebff451f..cade0eaeef 100644
--- a/doc/classes/GPUParticlesCollisionSphere3D.xml
+++ b/doc/classes/GPUParticlesCollisionSphere3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GPUParticlesCollisionSphere3D" inherits="GPUParticlesCollision3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GPUParticlesCollisionSphere3D" inherits="GPUParticlesCollision3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Sphere-shaped 3D particle collision shape affecting [GPUParticles3D] nodes.
</brief_description>
diff --git a/doc/classes/Generic6DOFJoint3D.xml b/doc/classes/Generic6DOFJoint3D.xml
index aac9a82467..2482defd0b 100644
--- a/doc/classes/Generic6DOFJoint3D.xml
+++ b/doc/classes/Generic6DOFJoint3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Generic6DOFJoint3D" inherits="Joint3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Generic6DOFJoint3D" inherits="Joint3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics joint that allows for complex movement and rotation between two 3D physics bodies.
</brief_description>
diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml
index 1db7142855..dfcf299fe6 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Geometry2D" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Geometry2D" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides methods for some common 2D geometric operations.
</brief_description>
diff --git a/doc/classes/Geometry3D.xml b/doc/classes/Geometry3D.xml
index 2f068b9fa5..014ebd2248 100644
--- a/doc/classes/Geometry3D.xml
+++ b/doc/classes/Geometry3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Geometry3D" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Geometry3D" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides methods for some common 3D geometric operations.
</brief_description>
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index edf2f9e18a..d728ab4f6c 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GeometryInstance3D" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GeometryInstance3D" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base node for geometry-based visual instances.
</brief_description>
diff --git a/doc/classes/Gradient.xml b/doc/classes/Gradient.xml
index f76ccb49ac..f2b894d612 100644
--- a/doc/classes/Gradient.xml
+++ b/doc/classes/Gradient.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Gradient" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Gradient" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A color interpolator resource which can be used to generate colors between user-defined color points.
</brief_description>
@@ -79,6 +79,7 @@
<members>
<member name="colors" type="PackedColorArray" setter="set_colors" getter="get_colors" default="PackedColorArray(0, 0, 0, 1, 1, 1, 1, 1)">
Gradient's colors returned as a [PackedColorArray].
+ [b]Note:[/b] This property returns a copy, modifying the return value does not update the gradient. To update the gradient use [method set_color] method (for updating colors individually) or assign to this property directly (for bulk-updating all colors at once).
</member>
<member name="interpolation_color_space" type="int" setter="set_interpolation_color_space" getter="get_interpolation_color_space" enum="Gradient.ColorSpace" default="0">
The color space used to interpolate between points of the gradient. It does not affect the returned colors, which will always be in sRGB space. See [enum ColorSpace] for available modes.
@@ -89,6 +90,7 @@
</member>
<member name="offsets" type="PackedFloat32Array" setter="set_offsets" getter="get_offsets" default="PackedFloat32Array(0, 1)">
Gradient's offsets returned as a [PackedFloat32Array].
+ [b]Note:[/b] This property returns a copy, modifying the return value does not update the gradient. To update the gradient use [method set_offset] method (for updating offsets individually) or assign to this property directly (for bulk-updating all offsets at once).
</member>
</members>
<constants>
diff --git a/doc/classes/GradientTexture1D.xml b/doc/classes/GradientTexture1D.xml
index ed0b15c536..7207de57fd 100644
--- a/doc/classes/GradientTexture1D.xml
+++ b/doc/classes/GradientTexture1D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GradientTexture1D" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GradientTexture1D" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Gradient-filled texture.
</brief_description>
diff --git a/doc/classes/GradientTexture2D.xml b/doc/classes/GradientTexture2D.xml
index 9522de3528..63e511173a 100644
--- a/doc/classes/GradientTexture2D.xml
+++ b/doc/classes/GradientTexture2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GradientTexture2D" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GradientTexture2D" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Gradient-filled 2D texture.
</brief_description>
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index 19ee396de1..0aea0c5727 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GraphEdit" inherits="Control" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GraphEdit" inherits="Control" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An editor for graph-like structures, using [GraphNode]s.
</brief_description>
@@ -157,7 +157,7 @@
Returns an Array containing the list of connections. A connection consists in a structure of the form [code]{ from_port: 0, from: "GraphNode name 0", to_port: 1, to: "GraphNode name 1" }[/code].
</description>
</method>
- <method name="get_zoom_hbox">
+ <method name="get_menu_hbox">
<return type="HBoxContainer" />
<description>
Gets the [HBoxContainer] that contains the zooming and grid snap controls in the top left of the graph. You can use this method to reposition the toolbar or to add your own custom controls to it.
@@ -255,16 +255,19 @@
<member name="right_disconnects" type="bool" setter="set_right_disconnects" getter="is_right_disconnects_enabled" default="false">
If [code]true[/code], enables disconnection of existing connections in the GraphEdit by dragging the right end.
</member>
- <member name="scroll_offset" type="Vector2" setter="set_scroll_ofs" getter="get_scroll_ofs" default="Vector2(0, 0)">
+ <member name="scroll_offset" type="Vector2" setter="set_scroll_offset" getter="get_scroll_offset" default="Vector2(0, 0)">
The scroll offset.
</member>
+ <member name="show_grid" type="bool" setter="set_show_grid" getter="is_showing_grid" default="true">
+ If [code]true[/code], the grid is visible.
+ </member>
<member name="show_zoom_label" type="bool" setter="set_show_zoom_label" getter="is_showing_zoom_label" default="false">
If [code]true[/code], makes a label with the current zoom level visible. The zoom value is displayed in percents.
</member>
- <member name="snap_distance" type="int" setter="set_snap" getter="get_snap" default="20">
- The snapping distance in pixels.
+ <member name="snapping_distance" type="int" setter="set_snapping_distance" getter="get_snapping_distance" default="20">
+ The snapping distance in pixels, also determines the grid line distance.
</member>
- <member name="use_snap" type="bool" setter="set_use_snap" getter="is_using_snap" default="true">
+ <member name="snapping_enabled" type="bool" setter="set_snapping_enabled" getter="is_snapping_enabled" default="true">
If [code]true[/code], enables snapping.
</member>
<member name="zoom" type="float" setter="set_zoom" getter="get_zoom" default="1.0">
@@ -412,23 +415,28 @@
<theme_item name="port_hotzone_outer_extent" data_type="constant" type="int" default="26">
The horizontal range within which a port can be grabbed (outer side).
</theme_item>
+ <theme_item name="grid_toggle" data_type="icon" type="Texture2D">
+ The icon for the grid toggle button.
+ </theme_item>
<theme_item name="layout" data_type="icon" type="Texture2D">
+ The icon for the layout button for auto-arranging the graph.
</theme_item>
- <theme_item name="minimap" data_type="icon" type="Texture2D">
+ <theme_item name="minimap_toggle" data_type="icon" type="Texture2D">
+ The icon for the minimap toggle button.
</theme_item>
- <theme_item name="minus" data_type="icon" type="Texture2D">
- The icon for the zoom out button.
+ <theme_item name="snapping_toggle" data_type="icon" type="Texture2D">
+ The icon for the snapping toggle button.
</theme_item>
- <theme_item name="more" data_type="icon" type="Texture2D">
+ <theme_item name="zoom_in" data_type="icon" type="Texture2D">
The icon for the zoom in button.
</theme_item>
- <theme_item name="reset" data_type="icon" type="Texture2D">
- The icon for the zoom reset button.
+ <theme_item name="zoom_out" data_type="icon" type="Texture2D">
+ The icon for the zoom out button.
</theme_item>
- <theme_item name="snap" data_type="icon" type="Texture2D">
- The icon for the snap toggle button.
+ <theme_item name="zoom_reset" data_type="icon" type="Texture2D">
+ The icon for the zoom reset button.
</theme_item>
- <theme_item name="bg" data_type="style" type="StyleBox">
+ <theme_item name="panel" data_type="style" type="StyleBox">
The background drawn under the grid.
</theme_item>
</theme_items>
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index 5b3e377cbb..d160141842 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GraphNode" inherits="Container" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GraphNode" inherits="Container" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container with connection ports, representing a node in a [GraphEdit].
</brief_description>
@@ -236,9 +236,6 @@
</method>
</methods>
<members>
- <member name="comment" type="bool" setter="set_comment" getter="is_comment" default="false">
- If [code]true[/code], the GraphNode is a comment node.
- </member>
<member name="draggable" type="bool" setter="set_draggable" getter="is_draggable" default="true">
If [code]true[/code], the user can drag the GraphNode.
</member>
@@ -373,12 +370,6 @@
<theme_item name="breakpoint" data_type="style" type="StyleBox">
The background used when [member overlay] is set to [constant OVERLAY_BREAKPOINT].
</theme_item>
- <theme_item name="comment" data_type="style" type="StyleBox">
- The [StyleBox] used when [member comment] is enabled.
- </theme_item>
- <theme_item name="comment_focus" data_type="style" type="StyleBox">
- The [StyleBox] used when [member comment] is enabled and the [GraphNode] is focused.
- </theme_item>
<theme_item name="frame" data_type="style" type="StyleBox">
The default background for [GraphNode].
</theme_item>
diff --git a/doc/classes/GridContainer.xml b/doc/classes/GridContainer.xml
index 8446f5ca60..cd96bd49d9 100644
--- a/doc/classes/GridContainer.xml
+++ b/doc/classes/GridContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GridContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GridContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that arranges its child controls in a grid layout.
</brief_description>
diff --git a/doc/classes/GrooveJoint2D.xml b/doc/classes/GrooveJoint2D.xml
index abb3f86ed8..a9c4f19c65 100644
--- a/doc/classes/GrooveJoint2D.xml
+++ b/doc/classes/GrooveJoint2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GrooveJoint2D" inherits="Joint2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="GrooveJoint2D" inherits="Joint2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics joint that restricts the movement of two 2D physics bodies to a fixed axis.
</brief_description>
diff --git a/doc/classes/HBoxContainer.xml b/doc/classes/HBoxContainer.xml
index 5217b0e4e2..331c1d23ad 100644
--- a/doc/classes/HBoxContainer.xml
+++ b/doc/classes/HBoxContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HBoxContainer" inherits="BoxContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HBoxContainer" inherits="BoxContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that arranges its child controls horizontally.
</brief_description>
diff --git a/doc/classes/HFlowContainer.xml b/doc/classes/HFlowContainer.xml
index c0c99cb11f..44d1af37cf 100644
--- a/doc/classes/HFlowContainer.xml
+++ b/doc/classes/HFlowContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HFlowContainer" inherits="FlowContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HFlowContainer" inherits="FlowContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that arranges its child controls horizontally and wraps them around at the borders.
</brief_description>
diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml
index ed80488e04..5f707adbea 100644
--- a/doc/classes/HMACContext.xml
+++ b/doc/classes/HMACContext.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HMACContext" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HMACContext" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Used to create an HMAC for a message using a key.
</brief_description>
diff --git a/doc/classes/HScrollBar.xml b/doc/classes/HScrollBar.xml
index 320a6f608e..307d244a40 100644
--- a/doc/classes/HScrollBar.xml
+++ b/doc/classes/HScrollBar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HScrollBar" inherits="ScrollBar" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HScrollBar" inherits="ScrollBar" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A horizontal scrollbar that goes from left (min) to right (max).
</brief_description>
diff --git a/doc/classes/HSeparator.xml b/doc/classes/HSeparator.xml
index 492145679c..c749eaa10e 100644
--- a/doc/classes/HSeparator.xml
+++ b/doc/classes/HSeparator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HSeparator" inherits="Separator" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HSeparator" inherits="Separator" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A horizontal line used for separating other controls.
</brief_description>
diff --git a/doc/classes/HSlider.xml b/doc/classes/HSlider.xml
index 14060721af..352ab3773e 100644
--- a/doc/classes/HSlider.xml
+++ b/doc/classes/HSlider.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HSlider" inherits="Slider" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HSlider" inherits="Slider" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A horizontal slider that goes from left (min) to right (max).
</brief_description>
diff --git a/doc/classes/HSplitContainer.xml b/doc/classes/HSplitContainer.xml
index 86661867d7..7cc6d94af3 100644
--- a/doc/classes/HSplitContainer.xml
+++ b/doc/classes/HSplitContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HSplitContainer" inherits="SplitContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HSplitContainer" inherits="SplitContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that splits two child controls horizontally and provides a grabber for adjusting the split ratio.
</brief_description>
diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml
index 39cebf773b..f0385a7814 100644
--- a/doc/classes/HTTPClient.xml
+++ b/doc/classes/HTTPClient.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HTTPClient" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HTTPClient" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Low-level hyper-text transfer protocol client.
</brief_description>
@@ -41,6 +41,7 @@
<description>
Returns the response's body length.
[b]Note:[/b] Some Web servers may not send a body length. In this case, the value returned will be [code]-1[/code]. If using chunked transfer encoding, the body length will also be [code]-1[/code].
+ [b]Note:[/b] This function always returns [code]-1[/code] on the Web platform due to browsers limitations.
</description>
</method>
<method name="get_response_code" qualifiers="const">
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index 877dc9df1f..961e9f216f 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HTTPRequest" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HTTPRequest" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node with the ability to send HTTP(S) requests.
</brief_description>
diff --git a/doc/classes/HashingContext.xml b/doc/classes/HashingContext.xml
index e5af3ad4b4..86d69bc2f7 100644
--- a/doc/classes/HashingContext.xml
+++ b/doc/classes/HashingContext.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HashingContext" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HashingContext" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides functionality for computing cryptographic hashes chunk by chunk.
</brief_description>
diff --git a/doc/classes/HeightMapShape3D.xml b/doc/classes/HeightMapShape3D.xml
index e490fc1d71..ff120fa557 100644
--- a/doc/classes/HeightMapShape3D.xml
+++ b/doc/classes/HeightMapShape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HeightMapShape3D" inherits="Shape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HeightMapShape3D" inherits="Shape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D height map shape used for physics collision.
</brief_description>
diff --git a/doc/classes/HingeJoint3D.xml b/doc/classes/HingeJoint3D.xml
index bd123217a7..d150c79b78 100644
--- a/doc/classes/HingeJoint3D.xml
+++ b/doc/classes/HingeJoint3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HingeJoint3D" inherits="Joint3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="HingeJoint3D" inherits="Joint3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics joint that restricts the rotation of a 3D physics body around an axis relative to another physics body.
</brief_description>
diff --git a/doc/classes/IP.xml b/doc/classes/IP.xml
index 407cc353d7..9fe3362e0f 100644
--- a/doc/classes/IP.xml
+++ b/doc/classes/IP.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="IP" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="IP" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Internet protocol (IP) support functions such as DNS resolution.
</brief_description>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index 130f848a73..81954dd7de 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Image" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Image" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Image datatype.
</brief_description>
@@ -333,6 +333,25 @@
Loads an image from the binary contents of a PNG file.
</description>
</method>
+ <method name="load_svg_from_buffer">
+ <return type="int" enum="Error" />
+ <param index="0" name="buffer" type="PackedByteArray" />
+ <param index="1" name="scale" type="float" default="1.0" />
+ <description>
+ Loads an image from the UTF-8 binary contents of an [b]uncompressed[/b] SVG file ([b].svg[/b]).
+ [b]Note:[/b] Beware when using compressed SVG files (like [b].svgz[/b]), they need to be [code]decompressed[/code] before loading.
+ [b]Note:[/b] This method is only available in engine builds with the SVG module enabled. By default, the SVG module is enabled, but it can be disabled at build-time using the [code]module_svg_enabled=no[/code] SCons option.
+ </description>
+ </method>
+ <method name="load_svg_from_string">
+ <return type="int" enum="Error" />
+ <param index="0" name="svg_str" type="String" />
+ <param index="1" name="scale" type="float" default="1.0" />
+ <description>
+ Loads an image from the string contents of a SVG file ([b].svg[/b]).
+ [b]Note:[/b] This method is only available in engine builds with the SVG module enabled. By default, the SVG module is enabled, but it can be disabled at build-time using the [code]module_svg_enabled=no[/code] SCons option.
+ </description>
+ </method>
<method name="load_tga_from_buffer">
<return type="int" enum="Error" />
<param index="0" name="buffer" type="PackedByteArray" />
@@ -660,13 +679,13 @@
<constant name="FORMAT_DXT5_RA_AS_RG" value="34" enum="Format">
</constant>
<constant name="FORMAT_ASTC_4x4" value="35" enum="Format">
- [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texutre Compression[/url]. This implements the 4x4 (high quality) mode.
+ [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texture Compression[/url]. This implements the 4x4 (high quality) mode.
</constant>
<constant name="FORMAT_ASTC_4x4_HDR" value="36" enum="Format">
Same format as [constant FORMAT_ASTC_4x4], but with the hint to let the GPU know it is used for HDR.
</constant>
<constant name="FORMAT_ASTC_8x8" value="37" enum="Format">
- [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texutre Compression[/url]. This implements the 8x8 (low quality) mode.
+ [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texture Compression[/url]. This implements the 8x8 (low quality) mode.
</constant>
<constant name="FORMAT_ASTC_8x8_HDR" value="38" enum="Format">
Same format as [constant FORMAT_ASTC_8x8], but with the hint to let the GPU know it is used for HDR.
diff --git a/doc/classes/ImageFormatLoader.xml b/doc/classes/ImageFormatLoader.xml
index a7ed12033f..a2276675bb 100644
--- a/doc/classes/ImageFormatLoader.xml
+++ b/doc/classes/ImageFormatLoader.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ImageFormatLoader" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ImageFormatLoader" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class to add support for specific image formats.
</brief_description>
diff --git a/doc/classes/ImageFormatLoaderExtension.xml b/doc/classes/ImageFormatLoaderExtension.xml
index be695de629..a755669518 100644
--- a/doc/classes/ImageFormatLoaderExtension.xml
+++ b/doc/classes/ImageFormatLoaderExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ImageFormatLoaderExtension" inherits="ImageFormatLoader" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ImageFormatLoaderExtension" inherits="ImageFormatLoader" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for creating [ImageFormatLoader] extensions (adding support for extra image formats).
</brief_description>
diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml
index 82303efbc0..3ac13dded1 100644
--- a/doc/classes/ImageTexture.xml
+++ b/doc/classes/ImageTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ImageTexture" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ImageTexture" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Texture2D] based on an [Image].
</brief_description>
diff --git a/doc/classes/ImageTexture3D.xml b/doc/classes/ImageTexture3D.xml
index 4396039ab2..a36271d67b 100644
--- a/doc/classes/ImageTexture3D.xml
+++ b/doc/classes/ImageTexture3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ImageTexture3D" inherits="Texture3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ImageTexture3D" inherits="Texture3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture with 3 dimensions.
</brief_description>
diff --git a/doc/classes/ImageTextureLayered.xml b/doc/classes/ImageTextureLayered.xml
index 215ff6ac5d..545c9289d1 100644
--- a/doc/classes/ImageTextureLayered.xml
+++ b/doc/classes/ImageTextureLayered.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ImageTextureLayered" inherits="TextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ImageTextureLayered" inherits="TextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for texture types which contain the data of multiple [ImageTexture]s. Each image is of the same size and format.
</brief_description>
diff --git a/doc/classes/ImmediateMesh.xml b/doc/classes/ImmediateMesh.xml
index 25eaa078f8..bde11a850e 100644
--- a/doc/classes/ImmediateMesh.xml
+++ b/doc/classes/ImmediateMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ImmediateMesh" inherits="Mesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ImmediateMesh" inherits="Mesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Mesh optimized for creating geometry manually.
</brief_description>
diff --git a/doc/classes/ImporterMesh.xml b/doc/classes/ImporterMesh.xml
index c800ec1b97..657d5659f8 100644
--- a/doc/classes/ImporterMesh.xml
+++ b/doc/classes/ImporterMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ImporterMesh" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ImporterMesh" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Resource] that contains vertex array-based geometry during the import process.
</brief_description>
diff --git a/doc/classes/ImporterMeshInstance3D.xml b/doc/classes/ImporterMeshInstance3D.xml
index eccfb0f3da..87b3635454 100644
--- a/doc/classes/ImporterMeshInstance3D.xml
+++ b/doc/classes/ImporterMeshInstance3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ImporterMeshInstance3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ImporterMeshInstance3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index cea8e66e52..c2a20827d2 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Input" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Input" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton for handling inputs.
</brief_description>
@@ -343,6 +343,15 @@
[b]Note:[/b] This value can be immediately overwritten by the hardware sensor value on Android and iOS.
</description>
</method>
+ <method name="should_ignore_device" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="vendor_id" type="int" />
+ <param index="1" name="product_id" type="int" />
+ <description>
+ Queries whether an input device should be ignored or not. Devices can be ignored by setting the environment variable [code]SDL_GAMECONTROLLER_IGNORE_DEVICES[/code]. Read the [url=https://wiki.libsdl.org/SDL2]SDL documentation[/url] for more information.
+ [b]Note:[/b] Some 3rd party tools can contribute to the list of ignored devices. For example, [i]SteamInput[/i] creates virtual devices from physical devices for remapping purposes. To avoid handling the same input device twice, the original device is added to the ignore list.
+ </description>
+ </method>
<method name="start_joy_vibration">
<return type="void" />
<param index="0" name="device" type="int" />
diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml
index f389cd9add..391d060fc3 100644
--- a/doc/classes/InputEvent.xml
+++ b/doc/classes/InputEvent.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEvent" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEvent" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for input events.
</brief_description>
diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml
index 5a684763c0..1fe4cfcd79 100644
--- a/doc/classes/InputEventAction.xml
+++ b/doc/classes/InputEventAction.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventAction" inherits="InputEvent" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventAction" inherits="InputEvent" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An input event type for actions.
</brief_description>
diff --git a/doc/classes/InputEventFromWindow.xml b/doc/classes/InputEventFromWindow.xml
index 58204ef3fb..df2a7c4fc2 100644
--- a/doc/classes/InputEventFromWindow.xml
+++ b/doc/classes/InputEventFromWindow.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventFromWindow" inherits="InputEvent" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventFromWindow" inherits="InputEvent" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for [Viewport]-based input events.
</brief_description>
diff --git a/doc/classes/InputEventGesture.xml b/doc/classes/InputEventGesture.xml
index 5979d5fbea..2cf133911b 100644
--- a/doc/classes/InputEventGesture.xml
+++ b/doc/classes/InputEventGesture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventGesture" inherits="InputEventWithModifiers" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventGesture" inherits="InputEventWithModifiers" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for touch gestures.
</brief_description>
diff --git a/doc/classes/InputEventJoypadButton.xml b/doc/classes/InputEventJoypadButton.xml
index 095cc1c363..4a1ecb962c 100644
--- a/doc/classes/InputEventJoypadButton.xml
+++ b/doc/classes/InputEventJoypadButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventJoypadButton" inherits="InputEvent" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventJoypadButton" inherits="InputEvent" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a gamepad button being pressed or released.
</brief_description>
diff --git a/doc/classes/InputEventJoypadMotion.xml b/doc/classes/InputEventJoypadMotion.xml
index 6254860bc4..f6b9692d38 100644
--- a/doc/classes/InputEventJoypadMotion.xml
+++ b/doc/classes/InputEventJoypadMotion.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventJoypadMotion" inherits="InputEvent" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventJoypadMotion" inherits="InputEvent" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents axis motions (such as joystick or analog triggers) from a gamepad.
</brief_description>
diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml
index 06e1c737db..5c4dc8e65d 100644
--- a/doc/classes/InputEventKey.xml
+++ b/doc/classes/InputEventKey.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventKey" inherits="InputEventWithModifiers" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventKey" inherits="InputEventWithModifiers" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a key on a keyboard being pressed or released.
</brief_description>
diff --git a/doc/classes/InputEventMIDI.xml b/doc/classes/InputEventMIDI.xml
index 078edf1d34..d685fdfa41 100644
--- a/doc/classes/InputEventMIDI.xml
+++ b/doc/classes/InputEventMIDI.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventMIDI" inherits="InputEvent" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventMIDI" inherits="InputEvent" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents an input event from a MIDI device, such as a piano.
</brief_description>
diff --git a/doc/classes/InputEventMagnifyGesture.xml b/doc/classes/InputEventMagnifyGesture.xml
index cae975bc79..bf92155139 100644
--- a/doc/classes/InputEventMagnifyGesture.xml
+++ b/doc/classes/InputEventMagnifyGesture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventMagnifyGesture" inherits="InputEventGesture" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventMagnifyGesture" inherits="InputEventGesture" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a magnifying touch gesture.
</brief_description>
diff --git a/doc/classes/InputEventMouse.xml b/doc/classes/InputEventMouse.xml
index 061438dd9a..b6f77b4f0c 100644
--- a/doc/classes/InputEventMouse.xml
+++ b/doc/classes/InputEventMouse.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventMouse" inherits="InputEventWithModifiers" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventMouse" inherits="InputEventWithModifiers" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base input event type for mouse events.
</brief_description>
diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml
index 2ec00191b6..57137e4bef 100644
--- a/doc/classes/InputEventMouseButton.xml
+++ b/doc/classes/InputEventMouseButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventMouseButton" inherits="InputEventMouse" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventMouseButton" inherits="InputEventMouse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a mouse button being pressed or released.
</brief_description>
diff --git a/doc/classes/InputEventMouseMotion.xml b/doc/classes/InputEventMouseMotion.xml
index 84751d4999..33a50d9daf 100644
--- a/doc/classes/InputEventMouseMotion.xml
+++ b/doc/classes/InputEventMouseMotion.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventMouseMotion" inherits="InputEventMouse" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventMouseMotion" inherits="InputEventMouse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a mouse or a pen movement.
</brief_description>
diff --git a/doc/classes/InputEventPanGesture.xml b/doc/classes/InputEventPanGesture.xml
index 71ef37a472..9966550c1a 100644
--- a/doc/classes/InputEventPanGesture.xml
+++ b/doc/classes/InputEventPanGesture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventPanGesture" inherits="InputEventGesture" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventPanGesture" inherits="InputEventGesture" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a panning touch gesture.
</brief_description>
diff --git a/doc/classes/InputEventScreenDrag.xml b/doc/classes/InputEventScreenDrag.xml
index 0e0ed53cba..07c0a87180 100644
--- a/doc/classes/InputEventScreenDrag.xml
+++ b/doc/classes/InputEventScreenDrag.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventScreenDrag" inherits="InputEventFromWindow" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventScreenDrag" inherits="InputEventFromWindow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a screen drag event.
</brief_description>
diff --git a/doc/classes/InputEventScreenTouch.xml b/doc/classes/InputEventScreenTouch.xml
index a9264f3953..9ed6fc191c 100644
--- a/doc/classes/InputEventScreenTouch.xml
+++ b/doc/classes/InputEventScreenTouch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventScreenTouch" inherits="InputEventFromWindow" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventScreenTouch" inherits="InputEventFromWindow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a screen touch event.
</brief_description>
diff --git a/doc/classes/InputEventShortcut.xml b/doc/classes/InputEventShortcut.xml
index 4141888d2c..3c698fd4fb 100644
--- a/doc/classes/InputEventShortcut.xml
+++ b/doc/classes/InputEventShortcut.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventShortcut" inherits="InputEvent" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventShortcut" inherits="InputEvent" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a triggered keyboard [Shortcut].
</brief_description>
diff --git a/doc/classes/InputEventWithModifiers.xml b/doc/classes/InputEventWithModifiers.xml
index 9de6469dfb..8bb3850dc2 100644
--- a/doc/classes/InputEventWithModifiers.xml
+++ b/doc/classes/InputEventWithModifiers.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventWithModifiers" inherits="InputEventFromWindow" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputEventWithModifiers" inherits="InputEventFromWindow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for input events affected by modifier keys like [kbd]Shift[/kbd] and [kbd]Alt[/kbd].
</brief_description>
diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml
index e08ba3f640..ff04040826 100644
--- a/doc/classes/InputMap.xml
+++ b/doc/classes/InputMap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputMap" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InputMap" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton that manages all [InputEventAction]s.
</brief_description>
diff --git a/doc/classes/InstancePlaceholder.xml b/doc/classes/InstancePlaceholder.xml
index 84494863e2..abd1428bac 100644
--- a/doc/classes/InstancePlaceholder.xml
+++ b/doc/classes/InstancePlaceholder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InstancePlaceholder" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="InstancePlaceholder" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Placeholder for the root [Node] of a [PackedScene].
</brief_description>
diff --git a/doc/classes/IntervalTweener.xml b/doc/classes/IntervalTweener.xml
index 24379dfdc8..13f48c65d5 100644
--- a/doc/classes/IntervalTweener.xml
+++ b/doc/classes/IntervalTweener.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="IntervalTweener" inherits="Tweener" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="IntervalTweener" inherits="Tweener" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Creates an idle interval in a [Tween] animation.
</brief_description>
diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml
index 5b5cd6618b..f6ad422234 100644
--- a/doc/classes/ItemList.xml
+++ b/doc/classes/ItemList.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ItemList" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ItemList" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A vertical list of selectable items with one or multiple columns.
</brief_description>
diff --git a/doc/classes/JNISingleton.xml b/doc/classes/JNISingleton.xml
index e5742ecc3b..041b8600b0 100644
--- a/doc/classes/JNISingleton.xml
+++ b/doc/classes/JNISingleton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JNISingleton" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="JNISingleton" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Singleton that connects the engine with Android plugins to interface with native Android code.
</brief_description>
diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml
index c630d2c1af..b73ca4a1a6 100644
--- a/doc/classes/JSON.xml
+++ b/doc/classes/JSON.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JSON" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="JSON" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Helper class for creating and parsing JSON data.
</brief_description>
diff --git a/doc/classes/JSONRPC.xml b/doc/classes/JSONRPC.xml
index 50cead321c..348688f7f8 100644
--- a/doc/classes/JSONRPC.xml
+++ b/doc/classes/JSONRPC.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JSONRPC" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="JSONRPC" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A helper to handle dictionaries which look like JSONRPC documents.
</brief_description>
diff --git a/doc/classes/JavaClass.xml b/doc/classes/JavaClass.xml
index 33037fc11a..541f23013d 100644
--- a/doc/classes/JavaClass.xml
+++ b/doc/classes/JavaClass.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JavaClass" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="JavaClass" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/JavaClassWrapper.xml b/doc/classes/JavaClassWrapper.xml
index 487e059f1e..e197b1e97e 100644
--- a/doc/classes/JavaClassWrapper.xml
+++ b/doc/classes/JavaClassWrapper.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JavaClassWrapper" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="JavaClassWrapper" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/JavaScriptBridge.xml b/doc/classes/JavaScriptBridge.xml
index 2b2480e413..6ce5801864 100644
--- a/doc/classes/JavaScriptBridge.xml
+++ b/doc/classes/JavaScriptBridge.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JavaScriptBridge" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="JavaScriptBridge" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Singleton that connects the engine with the browser's JavaScript context in Web export.
</brief_description>
diff --git a/doc/classes/JavaScriptObject.xml b/doc/classes/JavaScriptObject.xml
index af3af4367c..73a06c4719 100644
--- a/doc/classes/JavaScriptObject.xml
+++ b/doc/classes/JavaScriptObject.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JavaScriptObject" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="JavaScriptObject" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A wrapper class for web native JavaScript objects.
</brief_description>
diff --git a/doc/classes/Joint2D.xml b/doc/classes/Joint2D.xml
index 57a36535c5..6a43180561 100644
--- a/doc/classes/Joint2D.xml
+++ b/doc/classes/Joint2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Joint2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Joint2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for all 2D physics joints.
</brief_description>
diff --git a/doc/classes/Joint3D.xml b/doc/classes/Joint3D.xml
index e8f07ccf72..d848bdc0cd 100644
--- a/doc/classes/Joint3D.xml
+++ b/doc/classes/Joint3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Joint3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Joint3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for all 3D physics joints.
</brief_description>
diff --git a/doc/classes/KinematicCollision2D.xml b/doc/classes/KinematicCollision2D.xml
index 127e2fb2ce..ab805bf4b3 100644
--- a/doc/classes/KinematicCollision2D.xml
+++ b/doc/classes/KinematicCollision2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="KinematicCollision2D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="KinematicCollision2D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds collision data from the movement of a [PhysicsBody2D].
</brief_description>
diff --git a/doc/classes/KinematicCollision3D.xml b/doc/classes/KinematicCollision3D.xml
index 41e6e01822..2e319676c9 100644
--- a/doc/classes/KinematicCollision3D.xml
+++ b/doc/classes/KinematicCollision3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="KinematicCollision3D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="KinematicCollision3D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds collision data from the movement of a [PhysicsBody3D].
</brief_description>
diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml
index d54f209244..d0aa89b2e7 100644
--- a/doc/classes/Label.xml
+++ b/doc/classes/Label.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Label" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Label" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control for displaying plain text.
</brief_description>
diff --git a/doc/classes/Label3D.xml b/doc/classes/Label3D.xml
index 79e96d0d45..abd0e179af 100644
--- a/doc/classes/Label3D.xml
+++ b/doc/classes/Label3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Label3D" inherits="GeometryInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Label3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node for displaying plain text in 3D space.
</brief_description>
diff --git a/doc/classes/LabelSettings.xml b/doc/classes/LabelSettings.xml
index 2ea9332e9c..8cdb30c303 100644
--- a/doc/classes/LabelSettings.xml
+++ b/doc/classes/LabelSettings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LabelSettings" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="LabelSettings" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides common settings to customize the text in a [Label].
</brief_description>
diff --git a/doc/classes/Light2D.xml b/doc/classes/Light2D.xml
index 7d361c3536..9e0cf664de 100644
--- a/doc/classes/Light2D.xml
+++ b/doc/classes/Light2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Light2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Light2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Casts light in a 2D environment.
</brief_description>
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index 26b97edc25..ca9f821acf 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Light3D" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Light3D" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides a base class for different kinds of light nodes.
</brief_description>
diff --git a/doc/classes/LightOccluder2D.xml b/doc/classes/LightOccluder2D.xml
index 392f1d2062..533e87bce9 100644
--- a/doc/classes/LightOccluder2D.xml
+++ b/doc/classes/LightOccluder2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LightOccluder2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="LightOccluder2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Occludes light cast by a Light2D, casting shadows.
</brief_description>
diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml
index 55c6ef5eb5..6a6a72b329 100644
--- a/doc/classes/LightmapGI.xml
+++ b/doc/classes/LightmapGI.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LightmapGI" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="LightmapGI" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Computes and stores baked lightmaps for fast global illumination.
</brief_description>
diff --git a/doc/classes/LightmapGIData.xml b/doc/classes/LightmapGIData.xml
index 0d0ee679fb..09c4383829 100644
--- a/doc/classes/LightmapGIData.xml
+++ b/doc/classes/LightmapGIData.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LightmapGIData" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="LightmapGIData" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Contains baked lightmap and dynamic object probe data for [LightmapGI].
</brief_description>
diff --git a/doc/classes/LightmapProbe.xml b/doc/classes/LightmapProbe.xml
index bf90f4b2da..48584e50fd 100644
--- a/doc/classes/LightmapProbe.xml
+++ b/doc/classes/LightmapProbe.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LightmapProbe" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="LightmapProbe" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a single manually placed probe for dynamic object lighting with [LightmapGI].
</brief_description>
diff --git a/doc/classes/Lightmapper.xml b/doc/classes/Lightmapper.xml
index 05eaa5e08c..1febd39829 100644
--- a/doc/classes/Lightmapper.xml
+++ b/doc/classes/Lightmapper.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Lightmapper" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Lightmapper" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract class extended by lightmappers, for use in [LightmapGI].
</brief_description>
diff --git a/doc/classes/LightmapperRD.xml b/doc/classes/LightmapperRD.xml
index 2d103154dc..8fe42ad9cd 100644
--- a/doc/classes/LightmapperRD.xml
+++ b/doc/classes/LightmapperRD.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LightmapperRD" inherits="Lightmapper" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="LightmapperRD" inherits="Lightmapper" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
The built-in GPU-based lightmapper for use with [LightmapGI].
</brief_description>
diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml
index f376e44a97..c055603bcd 100644
--- a/doc/classes/Line2D.xml
+++ b/doc/classes/Line2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Line2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Line2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D line.
</brief_description>
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index d098956c4e..cea0adbe0f 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LineEdit" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="LineEdit" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An input field for single-line text.
</brief_description>
diff --git a/doc/classes/LinkButton.xml b/doc/classes/LinkButton.xml
index 5918adf5e0..010760cae0 100644
--- a/doc/classes/LinkButton.xml
+++ b/doc/classes/LinkButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LinkButton" inherits="BaseButton" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="LinkButton" inherits="BaseButton" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A button that represents a link.
</brief_description>
diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml
index f009f554b5..4c6c9d3524 100644
--- a/doc/classes/MainLoop.xml
+++ b/doc/classes/MainLoop.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MainLoop" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MainLoop" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for the game's main loop.
</brief_description>
diff --git a/doc/classes/MarginContainer.xml b/doc/classes/MarginContainer.xml
index 9ba4517e0e..1a6621d354 100644
--- a/doc/classes/MarginContainer.xml
+++ b/doc/classes/MarginContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MarginContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MarginContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that keeps a margin around its child controls.
</brief_description>
diff --git a/doc/classes/Marker2D.xml b/doc/classes/Marker2D.xml
index 16342669c8..d6239484f5 100644
--- a/doc/classes/Marker2D.xml
+++ b/doc/classes/Marker2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Marker2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Marker2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Generic 2D position hint for editing.
</brief_description>
diff --git a/doc/classes/Marker3D.xml b/doc/classes/Marker3D.xml
index e2a0839920..1728f7e566 100644
--- a/doc/classes/Marker3D.xml
+++ b/doc/classes/Marker3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Marker3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Marker3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Generic 3D position hint for editing.
</brief_description>
diff --git a/doc/classes/Marshalls.xml b/doc/classes/Marshalls.xml
index 0471027c18..5dc77fe1de 100644
--- a/doc/classes/Marshalls.xml
+++ b/doc/classes/Marshalls.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Marshalls" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Marshalls" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Data transformation (marshaling) and encoding helpers.
</brief_description>
diff --git a/doc/classes/Material.xml b/doc/classes/Material.xml
index 8b566ffa20..505a1465bb 100644
--- a/doc/classes/Material.xml
+++ b/doc/classes/Material.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Material" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Material" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base [Resource] for coloring and shading geometry.
</brief_description>
diff --git a/doc/classes/MenuBar.xml b/doc/classes/MenuBar.xml
index f3fbcfff7b..7d1b73278e 100644
--- a/doc/classes/MenuBar.xml
+++ b/doc/classes/MenuBar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MenuBar" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MenuBar" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A horizontal menu bar that creates a [MenuButton] for each [PopupMenu] child.
</brief_description>
diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml
index 4f62660bb9..8af233427c 100644
--- a/doc/classes/MenuButton.xml
+++ b/doc/classes/MenuButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MenuButton" inherits="Button" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MenuButton" inherits="Button" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A button that brings up a [PopupMenu] when clicked.
</brief_description>
diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml
index 4b9fa7bca9..6c4242b92d 100644
--- a/doc/classes/Mesh.xml
+++ b/doc/classes/Mesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Mesh" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Mesh" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Resource] that contains vertex array-based geometry.
</brief_description>
diff --git a/doc/classes/MeshConvexDecompositionSettings.xml b/doc/classes/MeshConvexDecompositionSettings.xml
index a2784c4485..161fd1c114 100644
--- a/doc/classes/MeshConvexDecompositionSettings.xml
+++ b/doc/classes/MeshConvexDecompositionSettings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MeshConvexDecompositionSettings" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MeshConvexDecompositionSettings" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Parameters to be used with a [Mesh] convex decomposition operation.
</brief_description>
diff --git a/doc/classes/MeshDataTool.xml b/doc/classes/MeshDataTool.xml
index 3b208f1fb7..e61e68ddde 100644
--- a/doc/classes/MeshDataTool.xml
+++ b/doc/classes/MeshDataTool.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MeshDataTool" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MeshDataTool" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Helper tool to access and edit [Mesh] data.
</brief_description>
diff --git a/doc/classes/MeshInstance2D.xml b/doc/classes/MeshInstance2D.xml
index 4e2715a52a..fa6d28c131 100644
--- a/doc/classes/MeshInstance2D.xml
+++ b/doc/classes/MeshInstance2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MeshInstance2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MeshInstance2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Node used for displaying a [Mesh] in 2D.
</brief_description>
diff --git a/doc/classes/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml
index fb6702263e..37947b4add 100644
--- a/doc/classes/MeshInstance3D.xml
+++ b/doc/classes/MeshInstance3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MeshInstance3D" inherits="GeometryInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MeshInstance3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Node that instances meshes into a scenario.
</brief_description>
diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml
index 9266b3dade..f7099e569f 100644
--- a/doc/classes/MeshLibrary.xml
+++ b/doc/classes/MeshLibrary.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MeshLibrary" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MeshLibrary" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Library of meshes.
</brief_description>
diff --git a/doc/classes/MeshTexture.xml b/doc/classes/MeshTexture.xml
index 4959cbed8c..bea99a4d5c 100644
--- a/doc/classes/MeshTexture.xml
+++ b/doc/classes/MeshTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MeshTexture" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MeshTexture" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Simple texture that uses a mesh to draw itself.
</brief_description>
diff --git a/doc/classes/MethodTweener.xml b/doc/classes/MethodTweener.xml
index 9a576d532a..c6e2bb6767 100644
--- a/doc/classes/MethodTweener.xml
+++ b/doc/classes/MethodTweener.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MethodTweener" inherits="Tweener" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MethodTweener" inherits="Tweener" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Interpolates an abstract value and supplies it to a method called over time.
</brief_description>
diff --git a/doc/classes/MissingNode.xml b/doc/classes/MissingNode.xml
index 0ad97e084e..6e5f839778 100644
--- a/doc/classes/MissingNode.xml
+++ b/doc/classes/MissingNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MissingNode" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MissingNode" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An internal editor class intended for keeping the data of unrecognized nodes.
</brief_description>
diff --git a/doc/classes/MissingResource.xml b/doc/classes/MissingResource.xml
index f63a6401d8..84a12290b3 100644
--- a/doc/classes/MissingResource.xml
+++ b/doc/classes/MissingResource.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MissingResource" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MissingResource" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An internal editor class intended for keeping the data of unrecognized resources.
</brief_description>
diff --git a/doc/classes/MovieWriter.xml b/doc/classes/MovieWriter.xml
index b84bfaec0c..4cd89e5e2d 100644
--- a/doc/classes/MovieWriter.xml
+++ b/doc/classes/MovieWriter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MovieWriter" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MovieWriter" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract class for non-real-time video recording encoders.
</brief_description>
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index c92b462bdb..0543b9abcf 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiMesh" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MultiMesh" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides high-performance drawing of a mesh multiple times using GPU instancing.
</brief_description>
diff --git a/doc/classes/MultiMeshInstance2D.xml b/doc/classes/MultiMeshInstance2D.xml
index b410b0130e..dc38d920bc 100644
--- a/doc/classes/MultiMeshInstance2D.xml
+++ b/doc/classes/MultiMeshInstance2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiMeshInstance2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MultiMeshInstance2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Node that instances a [MultiMesh] in 2D.
</brief_description>
diff --git a/doc/classes/MultiMeshInstance3D.xml b/doc/classes/MultiMeshInstance3D.xml
index f4b8046070..a50411cd63 100644
--- a/doc/classes/MultiMeshInstance3D.xml
+++ b/doc/classes/MultiMeshInstance3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiMeshInstance3D" inherits="GeometryInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MultiMeshInstance3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Node that instances a [MultiMesh].
</brief_description>
diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml
index 86de14d471..95baf7c706 100644
--- a/doc/classes/MultiplayerAPI.xml
+++ b/doc/classes/MultiplayerAPI.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiplayerAPI" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MultiplayerAPI" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
High-level multiplayer API interface.
</brief_description>
diff --git a/doc/classes/MultiplayerAPIExtension.xml b/doc/classes/MultiplayerAPIExtension.xml
index 8aee570072..4a2d397260 100644
--- a/doc/classes/MultiplayerAPIExtension.xml
+++ b/doc/classes/MultiplayerAPIExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiplayerAPIExtension" inherits="MultiplayerAPI" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MultiplayerAPIExtension" inherits="MultiplayerAPI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class used for extending the [MultiplayerAPI].
</brief_description>
diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml
index 49cf0c350e..350fffed32 100644
--- a/doc/classes/MultiplayerPeer.xml
+++ b/doc/classes/MultiplayerPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiplayerPeer" inherits="PacketPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MultiplayerPeer" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract class for specialized [PacketPeer]s used by the [MultiplayerAPI].
</brief_description>
diff --git a/doc/classes/MultiplayerPeerExtension.xml b/doc/classes/MultiplayerPeerExtension.xml
index 7c712a2d1e..9b2b5dbc94 100644
--- a/doc/classes/MultiplayerPeerExtension.xml
+++ b/doc/classes/MultiplayerPeerExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiplayerPeerExtension" inherits="MultiplayerPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="MultiplayerPeerExtension" inherits="MultiplayerPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Class that can be inherited to implement custom multiplayer API networking layers via GDExtension.
</brief_description>
diff --git a/doc/classes/Mutex.xml b/doc/classes/Mutex.xml
index 75c4e58748..4fdf46bb3a 100644
--- a/doc/classes/Mutex.xml
+++ b/doc/classes/Mutex.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Mutex" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Mutex" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A binary [Semaphore] for synchronization of multiple [Thread]s.
</brief_description>
diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml
index 332219be1e..c1570f3149 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationAgent2D" inherits="Node" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationAgent2D" inherits="Node" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D agent used to pathfind to a position while avoiding obstacles.
</brief_description>
@@ -53,7 +53,7 @@
<method name="get_final_position">
<return type="Vector2" />
<description>
- Returns the reachable final position of the current navigation path in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame.
+ Returns the reachable final position of the current navigation path in global coordinates. This position can change if the agent needs to update the navigation path which makes the agent emit the [signal path_changed] signal.
</description>
</method>
<method name="get_navigation_layer_value" qualifiers="const">
@@ -84,13 +84,14 @@
<method name="is_navigation_finished">
<return type="bool" />
<description>
- Returns true if the navigation path's final position has been reached.
+ Returns [code]true[/code] if the end of the currently loaded navigation path has been reached.
+ [b]Note:[/b] While true prefer to stop calling update functions like [method get_next_path_position]. This avoids jittering the standing agent due to calling repeated path updates.
</description>
</method>
<method name="is_target_reachable">
<return type="bool" />
<description>
- Returns true if [member target_position] is reachable. The target position is set using [member target_position].
+ Returns [code]true[/code] if [method get_final_position] is within [member target_desired_distance] of the [member target_position].
</description>
</method>
<method name="is_target_reached" qualifiers="const">
@@ -229,17 +230,20 @@
</signal>
<signal name="navigation_finished">
<description>
- Notifies when the final position is reached.
+ Emitted once per loaded path when the agent internal navigation path index reaches the last index of the loaded path array. The agent internal navigation path index can be received with [method get_current_navigation_path_index].
</description>
</signal>
<signal name="path_changed">
<description>
- Notifies when the navigation path changes.
+ Emitted when the agent had to update the loaded path:
+ - because path was previously empty.
+ - because navigation map has changed.
+ - because agent pushed further away from the current path segment than the [member path_max_distance].
</description>
</signal>
<signal name="target_reached">
<description>
- Notifies when the player-defined [member target_position] is reached.
+ Emitted once per loaded path when the agent's global position is the first time within [member target_desired_distance] to the [member target_position].
</description>
</signal>
<signal name="velocity_computed">
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
index 2450f84929..aef9b0ac56 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationAgent3D" inherits="Node" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationAgent3D" inherits="Node" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D agent used to pathfind to a position while avoiding obstacles.
</brief_description>
@@ -53,7 +53,7 @@
<method name="get_final_position">
<return type="Vector3" />
<description>
- Returns the reachable final position of the current navigation path in global coordinates. This position can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame.
+ Returns the reachable final position of the current navigation path in global coordinates. This position can change if the agent needs to update the navigation path which makes the agent emit the [signal path_changed] signal.
</description>
</method>
<method name="get_navigation_layer_value" qualifiers="const">
@@ -84,13 +84,14 @@
<method name="is_navigation_finished">
<return type="bool" />
<description>
- Returns true if the navigation path's final position has been reached.
+ Returns [code]true[/code] if the end of the currently loaded navigation path has been reached.
+ [b]Note:[/b] While true prefer to stop calling update functions like [method get_next_path_position]. This avoids jittering the standing agent due to calling repeated path updates.
</description>
</method>
<method name="is_target_reachable">
<return type="bool" />
<description>
- Returns true if [member target_position] is reachable. The target position is set using [member target_position].
+ Returns [code]true[/code] if [method get_final_position] is within [member target_desired_distance] of the [member target_position].
</description>
</method>
<method name="is_target_reached" qualifiers="const">
@@ -230,23 +231,26 @@
- [code]type[/code]: Always [constant NavigationPathQueryResult3D.PATH_SEGMENT_TYPE_LINK].
- [code]rid[/code]: The [RID] of the link.
- [code]owner[/code]: The object which manages the link (usually [NavigationLink3D]).
- - [code]link_entry_position[/code]: If [code]owner[/code] is available and the owner is a [NavigationLink2D], it will contain the global position of the link's point the agent is entering.
- - [code]link_exit_position[/code]: If [code]owner[/code] is available and the owner is a [NavigationLink2D], it will contain the global position of the link's point which the agent is exiting.
+ - [code]link_entry_position[/code]: If [code]owner[/code] is available and the owner is a [NavigationLink3D], it will contain the global position of the link's point the agent is entering.
+ - [code]link_exit_position[/code]: If [code]owner[/code] is available and the owner is a [NavigationLink3D], it will contain the global position of the link's point which the agent is exiting.
</description>
</signal>
<signal name="navigation_finished">
<description>
- Notifies when the final position is reached.
+ Emitted once per loaded path when the agent internal navigation path index reaches the last index of the loaded path array. The agent internal navigation path index can be received with [method get_current_navigation_path_index].
</description>
</signal>
<signal name="path_changed">
<description>
- Notifies when the navigation path changes.
+ Emitted when the agent had to update the loaded path:
+ - because path was previously empty.
+ - because navigation map has changed.
+ - because agent pushed further away from the current path segment than the [member path_max_distance].
</description>
</signal>
<signal name="target_reached">
<description>
- Notifies when the player-defined [member target_position] is reached.
+ Emitted once per loaded path when the agent's global position is the first time within [member target_desired_distance] to the [member target_position].
</description>
</signal>
<signal name="velocity_computed">
diff --git a/doc/classes/NavigationLink2D.xml b/doc/classes/NavigationLink2D.xml
index 7dd7e31775..b12051b4f4 100644
--- a/doc/classes/NavigationLink2D.xml
+++ b/doc/classes/NavigationLink2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationLink2D" inherits="Node2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationLink2D" inherits="Node2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A link between two positions on [NavigationRegion2D]s that agents can be routed through.
</brief_description>
diff --git a/doc/classes/NavigationLink3D.xml b/doc/classes/NavigationLink3D.xml
index 1ef59305e2..90eaaaee6d 100644
--- a/doc/classes/NavigationLink3D.xml
+++ b/doc/classes/NavigationLink3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationLink3D" inherits="Node3D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationLink3D" inherits="Node3D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A link between two positions on [NavigationRegion3D]s that agents can be routed through.
</brief_description>
diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml
index f481fd7099..464ffd50af 100644
--- a/doc/classes/NavigationMesh.xml
+++ b/doc/classes/NavigationMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationMesh" inherits="Resource" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationMesh" inherits="Resource" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A navigation mesh that defines traversable areas and obstacles.
</brief_description>
@@ -18,6 +18,12 @@
Adds a polygon using the indices of the vertices you get when calling [method get_vertices].
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the internal arrays for vertices and polygon indices.
+ </description>
+ </method>
<method name="clear_polygons">
<return type="void" />
<description>
@@ -103,10 +109,10 @@
The maximum distance the detail mesh surface should deviate from heightfield, in cell unit.
</member>
<member name="edge_max_error" type="float" setter="set_edge_max_error" getter="get_edge_max_error" default="1.3">
- The maximum distance a simplfied contour's border edges should deviate the original raw contour.
+ The maximum distance a simplified contour's border edges should deviate the original raw contour.
</member>
- <member name="edge_max_length" type="float" setter="set_edge_max_length" getter="get_edge_max_length" default="12.0">
- The maximum allowed length for contour edges along the border of the mesh.
+ <member name="edge_max_length" type="float" setter="set_edge_max_length" getter="get_edge_max_length" default="0.0">
+ The maximum allowed length for contour edges along the border of the mesh. A value of [code]0.0[/code] disables this feature.
[b]Note:[/b] While baking, this value will be rounded up to the nearest multiple of [member cell_size].
</member>
<member name="filter_baking_aabb" type="AABB" setter="set_filter_baking_aabb" getter="get_filter_baking_aabb" default="AABB(0, 0, 0, 0, 0, 0)">
diff --git a/doc/classes/NavigationMeshGenerator.xml b/doc/classes/NavigationMeshGenerator.xml
index 6870e2f9b2..dc9b7dc3b2 100644
--- a/doc/classes/NavigationMeshGenerator.xml
+++ b/doc/classes/NavigationMeshGenerator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationMeshGenerator" inherits="Object" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationMeshGenerator" inherits="Object" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Helper class for creating and clearing navigation meshes.
</brief_description>
@@ -47,6 +47,7 @@
<description>
Parses the [SceneTree] for source geometry according to the properties of [param navigation_mesh]. Updates the provided [param source_geometry_data] resource with the resulting data. The resource can then be used to bake a navigation mesh with [method bake_from_source_geometry_data]. After the process is finished the optional [param callback] will be called.
[b]Note:[/b] This function needs to run on the main thread or with a deferred call as the SceneTree is not thread-safe.
+ [b]Performance:[/b] While convenient, reading data arrays from [Mesh] resources can affect the frame rate negatively. The data needs to be received from the GPU, stalling the [RenderingServer] in the process. For performance prefer the use of e.g. collision shapes or creating the data arrays entirely in code.
</description>
</method>
</methods>
diff --git a/doc/classes/NavigationMeshSourceGeometryData3D.xml b/doc/classes/NavigationMeshSourceGeometryData3D.xml
index b929e82436..bf57baeb44 100644
--- a/doc/classes/NavigationMeshSourceGeometryData3D.xml
+++ b/doc/classes/NavigationMeshSourceGeometryData3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationMeshSourceGeometryData3D" inherits="Resource" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationMeshSourceGeometryData3D" inherits="Resource" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Container for parsed source geometry data used in navigation mesh baking.
</brief_description>
diff --git a/doc/classes/NavigationObstacle2D.xml b/doc/classes/NavigationObstacle2D.xml
index 2d94e0a025..09882da3b9 100644
--- a/doc/classes/NavigationObstacle2D.xml
+++ b/doc/classes/NavigationObstacle2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationObstacle2D" inherits="Node2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationObstacle2D" inherits="Node2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
2D Obstacle used in navigation to constrain avoidance controlled agents outside or inside an area.
</brief_description>
diff --git a/doc/classes/NavigationObstacle3D.xml b/doc/classes/NavigationObstacle3D.xml
index 2a921d3b8c..6f1649a457 100644
--- a/doc/classes/NavigationObstacle3D.xml
+++ b/doc/classes/NavigationObstacle3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationObstacle3D" inherits="Node3D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationObstacle3D" inherits="Node3D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
3D Obstacle used in navigation to constrain avoidance controlled agents outside or inside an area.
</brief_description>
diff --git a/doc/classes/NavigationPathQueryParameters2D.xml b/doc/classes/NavigationPathQueryParameters2D.xml
index c2da20b207..4acb6b697f 100644
--- a/doc/classes/NavigationPathQueryParameters2D.xml
+++ b/doc/classes/NavigationPathQueryParameters2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPathQueryParameters2D" inherits="RefCounted" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPathQueryParameters2D" inherits="RefCounted" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for 2D navigation path queries.
</brief_description>
diff --git a/doc/classes/NavigationPathQueryParameters3D.xml b/doc/classes/NavigationPathQueryParameters3D.xml
index 91b1aaec42..204e915efd 100644
--- a/doc/classes/NavigationPathQueryParameters3D.xml
+++ b/doc/classes/NavigationPathQueryParameters3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPathQueryParameters3D" inherits="RefCounted" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPathQueryParameters3D" inherits="RefCounted" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for 3D navigation path queries.
</brief_description>
diff --git a/doc/classes/NavigationPathQueryResult2D.xml b/doc/classes/NavigationPathQueryResult2D.xml
index e9acdea5ba..e02133cfba 100644
--- a/doc/classes/NavigationPathQueryResult2D.xml
+++ b/doc/classes/NavigationPathQueryResult2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPathQueryResult2D" inherits="RefCounted" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPathQueryResult2D" inherits="RefCounted" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents the result of a 2D pathfinding query.
</brief_description>
diff --git a/doc/classes/NavigationPathQueryResult3D.xml b/doc/classes/NavigationPathQueryResult3D.xml
index 8953f0e6df..9631c6a644 100644
--- a/doc/classes/NavigationPathQueryResult3D.xml
+++ b/doc/classes/NavigationPathQueryResult3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPathQueryResult3D" inherits="RefCounted" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPathQueryResult3D" inherits="RefCounted" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents the result of a 3D pathfinding query.
</brief_description>
diff --git a/doc/classes/NavigationPolygon.xml b/doc/classes/NavigationPolygon.xml
index a40f3d3d38..fe28c5a468 100644
--- a/doc/classes/NavigationPolygon.xml
+++ b/doc/classes/NavigationPolygon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationPolygon" inherits="Resource" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationPolygon" inherits="Resource" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A navigation polygon that defines traversable areas and obstacles.
</brief_description>
@@ -69,6 +69,12 @@
Adds a polygon using the indices of the vertices you get when calling [method get_vertices].
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the internal arrays for vertices and polygon indices.
+ </description>
+ </method>
<method name="clear_outlines">
<return type="void" />
<description>
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index 05cd49f323..acd789cc22 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationRegion2D" inherits="Node2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationRegion2D" inherits="Node2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A traversable 2D region that [NavigationAgent2D]s can use for pathfinding.
</brief_description>
@@ -30,6 +30,12 @@
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
+ <method name="get_navigation_map" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Returns the current navigation map [RID] used by this region.
+ </description>
+ </method>
<method name="get_region_rid" qualifiers="const">
<return type="RID" />
<description>
@@ -52,6 +58,13 @@
Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
</description>
</method>
+ <method name="set_navigation_map">
+ <return type="void" />
+ <param index="0" name="navigation_map" type="RID" />
+ <description>
+ Sets the [RID] of the navigation map this region should use. By default the region will automatically join the [World2D] default navigation map so this function is only required to override the default map.
+ </description>
+ </method>
</methods>
<members>
<member name="avoidance_layers" type="int" setter="set_avoidance_layers" getter="get_avoidance_layers" default="1">
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index 88b4f0dbf1..7e8ead2032 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationRegion3D" inherits="Node3D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationRegion3D" inherits="Node3D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A traversable 3D region that [NavigationAgent3D]s can use for pathfinding.
</brief_description>
@@ -30,6 +30,12 @@
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
+ <method name="get_navigation_map" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Returns the current navigation map [RID] used by this region.
+ </description>
+ </method>
<method name="get_region_rid" qualifiers="const">
<return type="RID" />
<description>
@@ -44,6 +50,13 @@
Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
</description>
</method>
+ <method name="set_navigation_map">
+ <return type="void" />
+ <param index="0" name="navigation_map" type="RID" />
+ <description>
+ Sets the [RID] of the navigation map this region should use. By default the region will automatically join the [World3D] default navigation map so this function is only required to override the default map.
+ </description>
+ </method>
</methods>
<members>
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 5364c3f13d..32215316d1 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationServer2D" inherits="Object" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationServer2D" inherits="Object" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A server interface for low-level 2D navigation access.
</brief_description>
@@ -207,6 +207,13 @@
Create a new link between two positions on a map.
</description>
</method>
+ <method name="link_get_enabled" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns [code]true[/code] if the specified [param link] is enabled.
+ </description>
+ </method>
<method name="link_get_end_position" qualifiers="const">
<return type="Vector2" />
<param index="0" name="link" type="RID" />
@@ -271,6 +278,14 @@
Sets whether this [param link] can be travelled in both directions.
</description>
</method>
+ <method name="link_set_enabled">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="enabled" type="bool" />
+ <description>
+ If [param enabled] is [code]true[/code] the specified [param link] will contribute to its current navigation map.
+ </description>
+ </method>
<method name="link_set_end_position">
<return type="void" />
<param index="0" name="link" type="RID" />
@@ -601,6 +616,13 @@
Returns how many connections this [param region] has with other regions in the map.
</description>
</method>
+ <method name="region_get_enabled" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="region" type="RID" />
+ <description>
+ Returns [code]true[/code] if the specified [param region] is enabled.
+ </description>
+ </method>
<method name="region_get_enter_cost" qualifiers="const">
<return type="float" />
<param index="0" name="region" type="RID" />
@@ -653,6 +675,14 @@
[b]Note:[/b] If navigation meshes from different navigation regions overlap (which should be avoided in general) the result might not be what is expected.
</description>
</method>
+ <method name="region_set_enabled">
+ <return type="void" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="enabled" type="bool" />
+ <description>
+ If [param enabled] is [code]true[/code] the specified [param region] will contribute to its current navigation map.
+ </description>
+ </method>
<method name="region_set_enter_cost">
<return type="void" />
<param index="0" name="region" type="RID" />
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 97d81af602..ebde6fdf7b 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationServer3D" inherits="Object" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NavigationServer3D" inherits="Object" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A server interface for low-level 3D navigation access.
</brief_description>
<description>
- NavigationServer2D is the server that handles navigation maps, regions and agents. It does not handle A* navigation from [AStar3D].
+ NavigationServer3D is the server that handles navigation maps, regions and agents. It does not handle A* navigation from [AStar3D].
Maps are made up of regions, which are made of navigation meshes. Together, they define the navigable areas in the 3D world.
[b]Note:[/b] Most [NavigationServer3D] changes take effect after the next physics frame and not immediately. This includes all changes made to maps, regions or agents by navigation-related nodes in the scene tree or made through scripts.
For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
@@ -248,6 +248,13 @@
Create a new link between two positions on a map.
</description>
</method>
+ <method name="link_get_enabled" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns [code]true[/code] if the specified [param link] is enabled.
+ </description>
+ </method>
<method name="link_get_end_position" qualifiers="const">
<return type="Vector3" />
<param index="0" name="link" type="RID" />
@@ -312,6 +319,14 @@
Sets whether this [param link] can be travelled in both directions.
</description>
</method>
+ <method name="link_set_enabled">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="enabled" type="bool" />
+ <description>
+ If [param enabled] is [code]true[/code] the specified [param link] will contribute to its current navigation map.
+ </description>
+ </method>
<method name="link_set_end_position">
<return type="void" />
<param index="0" name="link" type="RID" />
@@ -685,6 +700,7 @@
<description>
Parses the [SceneTree] for source geometry according to the properties of [param navigation_mesh]. Updates the provided [param source_geometry_data] resource with the resulting data. The resource can then be used to bake a navigation mesh with [method bake_from_source_geometry_data]. After the process is finished the optional [param callback] will be called.
[b]Note:[/b] This function needs to run on the main thread or with a deferred call as the SceneTree is not thread-safe.
+ [b]Performance:[/b] While convenient, reading data arrays from [Mesh] resources can affect the frame rate negatively. The data needs to be received from the GPU, stalling the [RenderingServer] in the process. For performance prefer the use of e.g. collision shapes or creating the data arrays entirely in code.
</description>
</method>
<method name="query_path" qualifiers="const">
@@ -695,12 +711,13 @@
Queries a path in a given navigation map. Start and target position and other parameters are defined through [NavigationPathQueryParameters3D]. Updates the provided [NavigationPathQueryResult3D] result object with the path among other results requested by the query.
</description>
</method>
- <method name="region_bake_navigation_mesh">
+ <method name="region_bake_navigation_mesh" is_deprecated="true">
<return type="void" />
<param index="0" name="navigation_mesh" type="NavigationMesh" />
<param index="1" name="root_node" type="Node" />
<description>
Bakes the [param navigation_mesh] with bake source geometry collected starting from the [param root_node].
+ [i]Deprecated.[/i] This function is deprecated due to core threading changes. To upgrade existing code, first create a [NavigationMeshSourceGeometryData3D] resource. Use this resource with [method parse_source_geometry_data] to parse the SceneTree for nodes that should contribute to the navigation mesh baking. The SceneTree parsing needs to happen on the main thread. After the parsing is finished use the resource with [method bake_from_source_geometry_data] to bake a navigation mesh.
</description>
</method>
<method name="region_create">
@@ -732,6 +749,13 @@
Returns how many connections this [param region] has with other regions in the map.
</description>
</method>
+ <method name="region_get_enabled" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="region" type="RID" />
+ <description>
+ Returns [code]true[/code] if the specified [param region] is enabled.
+ </description>
+ </method>
<method name="region_get_enter_cost" qualifiers="const">
<return type="float" />
<param index="0" name="region" type="RID" />
@@ -784,6 +808,14 @@
[b]Note:[/b] If navigation meshes from different navigation regions overlap (which should be avoided in general) the result might not be what is expected.
</description>
</method>
+ <method name="region_set_enabled">
+ <return type="void" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="enabled" type="bool" />
+ <description>
+ If [param enabled] is [code]true[/code] the specified [param region] will contribute to its current navigation map.
+ </description>
+ </method>
<method name="region_set_enter_cost">
<return type="void" />
<param index="0" name="region" type="RID" />
diff --git a/doc/classes/NinePatchRect.xml b/doc/classes/NinePatchRect.xml
index d5283236a9..c30662b122 100644
--- a/doc/classes/NinePatchRect.xml
+++ b/doc/classes/NinePatchRect.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NinePatchRect" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NinePatchRect" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control that displays a texture by keeping its corners intact, but tiling its edges and center.
</brief_description>
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 6bc167637e..ce02c3e51a 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Node" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Node" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for all scene objects.
</brief_description>
@@ -761,8 +761,8 @@
<param index="0" name="id" type="int" />
<param index="1" name="recursive" type="bool" default="true" />
<description>
- Sets the node's multiplayer authority to the peer with the given peer ID. The multiplayer authority is the peer that has authority over the node on the network. Useful in conjunction with [method rpc_config] and the [MultiplayerAPI]. Inherited from the parent node by default, which ultimately defaults to peer ID 1 (the server). If [param recursive], the given peer is recursively set as the authority for all children of this node.
- [b]Warning:[/b] This does [b]not[/b] automatically replicate the new authority to other peers. It is developer's responsibility to do so. You can propagate the information about the new authority using [member MultiplayerSpawner.spawn_function], an RPC, or using a [MultiplayerSynchronizer].
+ Sets the node's multiplayer authority to the peer with the given peer ID. The multiplayer authority is the peer that has authority over the node on the network. Useful in conjunction with [method rpc_config] and the [MultiplayerAPI]. Defaults to peer ID 1 (the server). If [param recursive], the given peer is recursively set as the authority for all children of this node.
+ [b]Warning:[/b] This does [b]not[/b] automatically replicate the new authority to other peers. It is developer's responsibility to do so. You can propagate the information about the new authority using [member MultiplayerSpawner.spawn_function], an RPC, or using a [MultiplayerSynchronizer]. Also, the parent's authority does [b]not[/b] propagate to newly added children.
</description>
</method>
<method name="set_physics_process">
@@ -858,8 +858,8 @@
[b]Note:[/b] Auto-generated names might include the [code]@[/code] character, which is reserved for unique names when using [method add_child]. When setting the name manually, any [code]@[/code] will be removed.
</member>
<member name="owner" type="Node" setter="set_owner" getter="get_owner">
- The node owner. A node can have any other node as owner (as long as it is a valid parent, grandparent, etc. ascending in the tree). When saving a node (using [PackedScene]), all the nodes it owns will be saved with it. This allows for the creation of complex [SceneTree]s, with instancing and subinstancing.
- [b]Note:[/b] If you want a child to be persisted to a [PackedScene], you must set [member owner] in addition to calling [method add_child]. This is typically relevant for [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]tool scripts[/url] and [url=$DOCS_URL/tutorials/plugins/editor/index.html]editor plugins[/url]. If [method add_child] is called without setting [member owner], the newly added [Node] will not be visible in the scene tree, though it will be visible in the 2D/3D view.
+ The node owner. A node can have any ancestor node as owner (i.e. a parent, grandparent, etc. node ascending in the tree). This implies that [method add_child] should be called before setting the owner, so that this relationship of parenting exists. When saving a node (using [PackedScene]), all the nodes it owns will be saved with it. This allows for the creation of complex scene trees, with instancing and subinstancing.
+ [b]Note:[/b] If you want a child to be persisted to a [PackedScene], you must set [member owner] in addition to calling [method add_child]. This is typically relevant for [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]tool scripts[/url] and [url=$DOCS_URL/tutorials/plugins/editor/index.html]editor plugins[/url]. If a new node is added to the tree without setting its owner as an ancestor in that tree, it will be visible in the 2D/3D view, but not in the scene tree (and not persisted when packing or saving).
</member>
<member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Node.ProcessMode" default="0">
Can be used to pause or unpause the node, or make the node paused based on the [SceneTree], or make it inherit the process mode from its parent (default).
diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml
index ee8e65e57a..091acdf6f2 100644
--- a/doc/classes/Node2D.xml
+++ b/doc/classes/Node2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Node2D" inherits="CanvasItem" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Node2D" inherits="CanvasItem" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D game object, inherited by all 2D-related nodes. Has a position, rotation, scale, and Z index.
</brief_description>
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index 8247911a34..b5ead07a10 100644
--- a/doc/classes/Node3D.xml
+++ b/doc/classes/Node3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Node3D" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Node3D" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Most basic 3D game object, parent of all 3D-related nodes.
</brief_description>
@@ -291,7 +291,7 @@
Access to the node rotation as a [Quaternion]. This property is ideal for tweening complex rotations.
</member>
<member name="rotation" type="Vector3" setter="set_rotation" getter="get_rotation" default="Vector3(0, 0, 0)">
- Rotation part of the local transformation in radians, specified in terms of Euler angles. The angles construct a rotaton in the order specified by the [member rotation_order] property.
+ Rotation part of the local transformation in radians, specified in terms of Euler angles. The angles construct a rotation in the order specified by the [member rotation_order] property.
[b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful.
[b]Note:[/b] This property is edited in the inspector in degrees. If you want to use degrees in a script, use [member rotation_degrees].
</member>
diff --git a/doc/classes/Node3DGizmo.xml b/doc/classes/Node3DGizmo.xml
index 78142a0ade..9a02374efb 100644
--- a/doc/classes/Node3DGizmo.xml
+++ b/doc/classes/Node3DGizmo.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Node3DGizmo" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Node3DGizmo" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index 516498473e..77a5cfa6c6 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NodePath" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="NodePath" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A pre-parsed scene tree path.
</brief_description>
diff --git a/doc/classes/ORMMaterial3D.xml b/doc/classes/ORMMaterial3D.xml
index 21043ef454..d134107618 100644
--- a/doc/classes/ORMMaterial3D.xml
+++ b/doc/classes/ORMMaterial3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ORMMaterial3D" inherits="BaseMaterial3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ORMMaterial3D" inherits="BaseMaterial3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Physically based rendering (PBR) material that can be applied to 3D objects, can use an ORM texture.
</brief_description>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 0696ae224a..03169d390a 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OS" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="OS" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides access to common operating system functionalities.
</brief_description>
@@ -240,8 +240,8 @@
<method name="get_granted_permissions" qualifiers="const">
<return type="PackedStringArray" />
<description>
- With this function, you can get the list of dangerous permissions that have been granted to the Android application.
- [b]Note:[/b] This method is implemented only on Android.
+ On Android devices: With this function, you can get the list of dangerous permissions that have been granted.
+ On macOS (sandboxed applications only): This function returns the list of user selected folders accessible to the application. Use native file dialog to request folder access permission.
</description>
</method>
<method name="get_keycode_string" qualifiers="const">
@@ -534,6 +534,13 @@
Returns [code]true[/code] if the project will automatically restart when it exits for any reason, [code]false[/code] otherwise. See also [method set_restart_on_exit] and [method get_restart_on_exit_arguments].
</description>
</method>
+ <method name="is_sandboxed" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if application is running in the sandbox.
+ [b]Note:[/b] This method is implemented on macOS.
+ </description>
+ </method>
<method name="is_stdout_verbose" qualifiers="const">
<return type="bool" />
<description>
@@ -602,6 +609,12 @@
[b]Note:[/b] This method is implemented only on Android.
</description>
</method>
+ <method name="revoke_granted_permissions">
+ <return type="void" />
+ <description>
+ On macOS (sandboxed applications only), this function clears list of user selected folders accessible to the application.
+ </description>
+ </method>
<method name="set_environment" qualifiers="const">
<return type="void" />
<param index="0" name="variable" type="String" />
@@ -657,7 +670,7 @@
Requests the OS to open the file manager, then navigate to the given [param file_or_dir_path] and select the target file or folder.
If [param file_or_dir_path] is a valid directory path, and [param open_folder] is [code]true[/code], the method will open the file manager and enter the target folder without selecting anything.
Use [method ProjectSettings.globalize_path] to convert a [code]res://[/code] or [code]user://[/code] path into a system path for use with this method.
- [b]Note:[/b] Currently this method is only implemented on Windows. On other platforms, it will fallback to [method shell_open] with a directory path for [param file_or_dir_path].
+ [b]Note:[/b] Currently this method is only implemented on Windows and macOS. On other platforms, it will fallback to [method shell_open] with a directory path of [param file_or_dir_path] with prefix [code]file://[/code].
</description>
</method>
<method name="unset_environment" qualifiers="const">
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 54d6374336..fc349f3913 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for all other classes in the engine.
</brief_description>
diff --git a/doc/classes/Occluder3D.xml b/doc/classes/Occluder3D.xml
index afd2873021..b229343b40 100644
--- a/doc/classes/Occluder3D.xml
+++ b/doc/classes/Occluder3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Occluder3D" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Occluder3D" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Occluder shape resource for use with occlusion culling in [OccluderInstance3D].
</brief_description>
diff --git a/doc/classes/OccluderInstance3D.xml b/doc/classes/OccluderInstance3D.xml
index 172781f5dc..65b1bead9a 100644
--- a/doc/classes/OccluderInstance3D.xml
+++ b/doc/classes/OccluderInstance3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OccluderInstance3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="OccluderInstance3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides occlusion culling for 3D nodes, which improves performance in closed areas.
</brief_description>
@@ -36,7 +36,7 @@
</member>
<member name="bake_simplification_distance" type="float" setter="set_bake_simplification_distance" getter="get_bake_simplification_distance" default="0.1">
The simplification distance to use for simplifying the generated occluder polygon (in 3D units). Higher values result in a less detailed occluder mesh, which improves performance but reduces culling accuracy.
- The occluder geometry is rendered on the CPU, so it is important to keep its geometry as simple as possible. Since the buffer is rendered at a low resolution, less detailed occluder meshes generally still work well. The default value is fairly aggressive, so you may have to decrase it if you run into false negatives (objects being occluded even though they are visible by the camera). A value of [code]0.01[/code] will act conservatively, and will keep geometry [i]perceptually[/i] unaffected in the occlusion culling buffer. Depending on the scene, a value of [code]0.01[/code] may still simplify the mesh noticeably compared to disabling simplification entirely.
+ The occluder geometry is rendered on the CPU, so it is important to keep its geometry as simple as possible. Since the buffer is rendered at a low resolution, less detailed occluder meshes generally still work well. The default value is fairly aggressive, so you may have to decrease it if you run into false negatives (objects being occluded even though they are visible by the camera). A value of [code]0.01[/code] will act conservatively, and will keep geometry [i]perceptually[/i] unaffected in the occlusion culling buffer. Depending on the scene, a value of [code]0.01[/code] may still simplify the mesh noticeably compared to disabling simplification entirely.
Setting this to [code]0.0[/code] disables simplification entirely, but vertices in the exact same position will still be merged. The mesh will also be re-indexed to reduce both the number of vertices and indices.
[b]Note:[/b] This uses the [url=https://meshoptimizer.org/]meshoptimizer[/url] library under the hood, similar to LOD generation.
</member>
diff --git a/doc/classes/OccluderPolygon2D.xml b/doc/classes/OccluderPolygon2D.xml
index 6a48481de5..a78375ad01 100644
--- a/doc/classes/OccluderPolygon2D.xml
+++ b/doc/classes/OccluderPolygon2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OccluderPolygon2D" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="OccluderPolygon2D" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Defines a 2D polygon for LightOccluder2D.
</brief_description>
diff --git a/doc/classes/OfflineMultiplayerPeer.xml b/doc/classes/OfflineMultiplayerPeer.xml
index dcb0072a79..59b275d161 100644
--- a/doc/classes/OfflineMultiplayerPeer.xml
+++ b/doc/classes/OfflineMultiplayerPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OfflineMultiplayerPeer" inherits="MultiplayerPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="OfflineMultiplayerPeer" inherits="MultiplayerPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [MultiplayerPeer] which is always connected and acts as a server.
</brief_description>
diff --git a/doc/classes/OmniLight3D.xml b/doc/classes/OmniLight3D.xml
index 6bd549a361..44d1f8902e 100644
--- a/doc/classes/OmniLight3D.xml
+++ b/doc/classes/OmniLight3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OmniLight3D" inherits="Light3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="OmniLight3D" inherits="Light3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Omnidirectional light, such as a light bulb or a candle.
</brief_description>
diff --git a/doc/classes/OpenXRAPIExtension.xml b/doc/classes/OpenXRAPIExtension.xml
new file mode 100644
index 0000000000..181da916d1
--- /dev/null
+++ b/doc/classes/OpenXRAPIExtension.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="OpenXRAPIExtension" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Makes the OpenXR API available for GDExtension.
+ </brief_description>
+ <description>
+ [OpenXRAPIExtension] makes OpenXR available for GDExtension. It provides the OpenXR API to GDExtension through the [method get_instance_proc_addr] method, and the OpenXR instance through [method get_instance].
+ It also provides methods for querying the status of OpenXR initialization, and helper methods for ease of use of the API with GDExtension.
+ </description>
+ <tutorials>
+ <link title="XrResult documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrResult.html</link>
+ <link title="XrInstance documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrInstance.html</link>
+ <link title="XrSpace documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSpace.html</link>
+ <link title="XrSession documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSession.html</link>
+ <link title="XrSystemId documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSystemId.html</link>
+ <link title="xrBeginSession documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/xrBeginSession.html</link>
+ <link title="XrPosef documentation">https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrPosef.html</link>
+ </tutorials>
+ <methods>
+ <method name="can_render">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if OpenXR is initialized for rendering with an XR viewport.
+ </description>
+ </method>
+ <method name="get_error_string">
+ <return type="String" />
+ <param index="0" name="result" type="int" />
+ <description>
+ Returns an error string for the given [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrResult.html]XrResult[/url].
+ </description>
+ </method>
+ <method name="get_instance">
+ <return type="int" />
+ <description>
+ Returns the [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrInstance.html]XrInstance[/url] created during the initialization of the OpenXR API.
+ </description>
+ </method>
+ <method name="get_instance_proc_addr">
+ <return type="int" />
+ <param index="0" name="name" type="String" />
+ <description>
+ Returns the function pointer of the OpenXR function with the specified name, cast to an integer. If the function with the given name does not exist, the method returns [code]0[/code].
+ [b]Note:[/b] [code]openxr/util.h[/code] contains utility macros for acquiring OpenXR functions, e.g. [code]GDEXTENSION_INIT_XR_FUNC_V(xrCreateAction)[/code].
+ </description>
+ </method>
+ <method name="get_next_frame_time">
+ <return type="int" />
+ <description>
+ Returns the timing for the next frame.
+ </description>
+ </method>
+ <method name="get_play_space">
+ <return type="int" />
+ <description>
+ Returns the play space, which is an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSpace.html]XrSpace[/url] cast to an integer.
+ </description>
+ </method>
+ <method name="get_session">
+ <return type="int" />
+ <description>
+ Returns the OpenXR session, which is an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSession.html]XrSession[/url] cast to an integer.
+ </description>
+ </method>
+ <method name="get_swapchain_format_name">
+ <return type="String" />
+ <param index="0" name="swapchain_format" type="int" />
+ <description>
+ Returns the name of the specified swapchain format.
+ </description>
+ </method>
+ <method name="get_system_id">
+ <return type="int" />
+ <description>
+ Returns the id of the system, which is a [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSystemId.html]XrSystemId[/url] cast to an integer.
+ </description>
+ </method>
+ <method name="is_initialized">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if OpenXR is initialized.
+ </description>
+ </method>
+ <method name="is_running">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if OpenXR is running ([url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/xrBeginSession.html]xrBeginSession[/url] was successfully called and the swapchains were created).
+ </description>
+ </method>
+ <method name="openxr_is_enabled" qualifiers="static">
+ <return type="bool" />
+ <param index="0" name="check_run_in_editor" type="bool" />
+ <description>
+ Returns [code]true[/code] if OpenXR is enabled.
+ </description>
+ </method>
+ <method name="transform_from_pose">
+ <return type="Transform3D" />
+ <param index="0" name="pose" type="const void*" />
+ <description>
+ Creates a [Transform3D] from an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrPosef.html]XrPosef[/url].
+ </description>
+ </method>
+ <method name="xr_result">
+ <return type="bool" />
+ <param index="0" name="result" type="int" />
+ <param index="1" name="format" type="String" />
+ <param index="2" name="args" type="Array" />
+ <description>
+ Returns [code]true[/code] if the provided [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrResult.html]XrResult[/url] (cast to an integer) is successful. Otherwise returns [code]false[/code] and prints the [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrResult.html]XrResult[/url] converted to a string, with the specified additional information.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/OpenXRExtensionWrapperExtension.xml b/doc/classes/OpenXRExtensionWrapperExtension.xml
new file mode 100644
index 0000000000..004d10e588
--- /dev/null
+++ b/doc/classes/OpenXRExtensionWrapperExtension.xml
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="OpenXRExtensionWrapperExtension" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Allows clients to implement OpenXR extensions with GDExtension.
+ </brief_description>
+ <description>
+ [OpenXRExtensionWrapperExtension] allows clients to implement OpenXR extensions with GDExtension. The extension should be registered with [method register_extension_wrapper].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_get_requested_extensions" qualifiers="virtual">
+ <return type="Dictionary" />
+ <description>
+ Returns a [Dictionary] of OpenXR extensions related to this extension. The [Dictionary] should contain the name of the extension, mapped to a [code]bool *[/code] cast to an integer:
+ - If the [code]bool *[/code] is a [code]nullptr[/code] this extension is mandatory.
+ - If the [code]bool *[/code] points to a boolean, the boolean will be updated to [code]true[/code] if the extension is enabled.
+ </description>
+ </method>
+ <method name="_on_before_instance_created" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called before the OpenXR instance is created.
+ </description>
+ </method>
+ <method name="_on_event_polled" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="event" type="const void*" />
+ <description>
+ Called when there is an OpenXR event to process. When implementing, return [code]true[/code] if the event was handled, return [code]false[/code] otherwise.
+ </description>
+ </method>
+ <method name="_on_instance_created" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="instance" type="int" />
+ <description>
+ Called right after the OpenXR instance is created.
+ </description>
+ </method>
+ <method name="_on_instance_destroyed" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called right before the OpenXR instance is destroyed.
+ </description>
+ </method>
+ <method name="_on_pre_render" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called right before the XR viewports begin their rendering step.
+ </description>
+ </method>
+ <method name="_on_process" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called as part of the OpenXR process handling. This happens right before general and physics processing steps of the main loop. During this step controller data is queried and made available to game logic.
+ </description>
+ </method>
+ <method name="_on_register_metadata" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Allows extensions to register additional controller metadata. This function is called even when the OpenXR API is not constructed as the metadata needs to be available to the editor.
+ Extensions should also provide metadata regardless of whether they are supported on the host system. The controller data is used to setup action maps for users who may have access to the relevant hardware.
+ </description>
+ </method>
+ <method name="_on_session_created" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="session" type="int" />
+ <description>
+ Called right after the OpenXR session is created.
+ </description>
+ </method>
+ <method name="_on_session_destroyed" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called right before the OpenXR session is destroyed.
+ </description>
+ </method>
+ <method name="_on_state_exiting" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the OpenXR session state is changed to exiting.
+ </description>
+ </method>
+ <method name="_on_state_focused" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the OpenXR session state is changed to focused. This state is the active state when the game runs.
+ </description>
+ </method>
+ <method name="_on_state_idle" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the OpenXR session state is changed to idle.
+ </description>
+ </method>
+ <method name="_on_state_loss_pending" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the OpenXR session state is changed to loss pending.
+ </description>
+ </method>
+ <method name="_on_state_ready" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the OpenXR session state is changed to ready. This means OpenXR is ready to set up the session.
+ </description>
+ </method>
+ <method name="_on_state_stopping" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the OpenXR session state is changed to stopping.
+ </description>
+ </method>
+ <method name="_on_state_synchronized" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the OpenXR session state is changed to synchronized. OpenXR also returns to this state when the application loses focus.
+ </description>
+ </method>
+ <method name="_on_state_visible" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the OpenXR session state is changed to visible. This means OpenXR is now ready to receive frames.
+ </description>
+ </method>
+ <method name="_set_instance_create_info_and_get_next_pointer" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="next_pointer" type="void*" />
+ <description>
+ Adds additional data structures when the OpenXR instance is created.
+ </description>
+ </method>
+ <method name="_set_session_create_and_get_next_pointer" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="next_pointer" type="void*" />
+ <description>
+ Adds additional data structures when the OpenXR session is created.
+ </description>
+ </method>
+ <method name="_set_swapchain_create_info_and_get_next_pointer" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="next_pointer" type="void*" />
+ <description>
+ Adds additional data structures when creating OpenXR swapchains.
+ </description>
+ </method>
+ <method name="_set_system_properties_and_get_next_pointer" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="next_pointer" type="void*" />
+ <description>
+ Adds additional data structures when interogating OpenXR system abilities.
+ </description>
+ </method>
+ <method name="get_openxr_api">
+ <return type="OpenXRAPIExtension" />
+ <description>
+ Returns the created [OpenXRAPIExtension], which can be used to access the OpenXR API.
+ </description>
+ </method>
+ <method name="register_extension_wrapper">
+ <return type="void" />
+ <description>
+ Registers the extension. This should happen at core module initialization level.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/OptimizedTranslation.xml b/doc/classes/OptimizedTranslation.xml
index 7d55355363..124f430f1b 100644
--- a/doc/classes/OptimizedTranslation.xml
+++ b/doc/classes/OptimizedTranslation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OptimizedTranslation" inherits="Translation" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="OptimizedTranslation" inherits="Translation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An optimized translation, used by default for CSV Translations.
</brief_description>
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index 84c8b89021..659f08d49a 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OptionButton" inherits="Button" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="OptionButton" inherits="Button" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A button that brings up a dropdown with selectable options when pressed.
</brief_description>
diff --git a/doc/classes/PCKPacker.xml b/doc/classes/PCKPacker.xml
index ae9fe65856..2627c8b7d3 100644
--- a/doc/classes/PCKPacker.xml
+++ b/doc/classes/PCKPacker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PCKPacker" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PCKPacker" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Creates packages that can be loaded into a running project.
</brief_description>
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index 3926ea8beb..60d3a55711 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedByteArray" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedByteArray" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A packed array of bytes.
</brief_description>
@@ -346,7 +346,7 @@
<param index="0" name="byte_offset" type="int" />
<param index="1" name="allow_objects" type="bool" default="false" />
<description>
- Returns [code]true[/code] if a valid [Variant] value can be decoded at the [param byte_offset]. Returns [code]false[/code] othewrise or when the value is [Object]-derived and [param allow_objects] is [code]false[/code].
+ Returns [code]true[/code] if a valid [Variant] value can be decoded at the [param byte_offset]. Returns [code]false[/code] otherwise or when the value is [Object]-derived and [param allow_objects] is [code]false[/code].
</description>
</method>
<method name="hex_encode" qualifiers="const">
diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml
index eb5a0edfd6..4908a861b3 100644
--- a/doc/classes/PackedColorArray.xml
+++ b/doc/classes/PackedColorArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedColorArray" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedColorArray" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A packed array of [Color]s.
</brief_description>
diff --git a/doc/classes/PackedDataContainer.xml b/doc/classes/PackedDataContainer.xml
index 8b500b41bd..048c72126a 100644
--- a/doc/classes/PackedDataContainer.xml
+++ b/doc/classes/PackedDataContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedDataContainer" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedDataContainer" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Efficiently packs and serializes [Array] or [Dictionary].
</brief_description>
diff --git a/doc/classes/PackedDataContainerRef.xml b/doc/classes/PackedDataContainerRef.xml
index 5199d9b445..75222784ca 100644
--- a/doc/classes/PackedDataContainerRef.xml
+++ b/doc/classes/PackedDataContainerRef.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedDataContainerRef" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedDataContainerRef" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An internal class used by [PackedDataContainer] to pack nested arrays and dictionaries.
</brief_description>
diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml
index 6e33ad8f73..56f9633533 100644
--- a/doc/classes/PackedFloat32Array.xml
+++ b/doc/classes/PackedFloat32Array.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedFloat32Array" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedFloat32Array" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A packed array of 32-bit floating-point values.
</brief_description>
diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml
index 844eae3019..b08bdafc83 100644
--- a/doc/classes/PackedFloat64Array.xml
+++ b/doc/classes/PackedFloat64Array.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedFloat64Array" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedFloat64Array" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A packed array of 64-bit floating-point values.
</brief_description>
diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml
index 04f3caa52a..c70cadc2fe 100644
--- a/doc/classes/PackedInt32Array.xml
+++ b/doc/classes/PackedInt32Array.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedInt32Array" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedInt32Array" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A packed array of 32-bit integers.
</brief_description>
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index 1150f7b1cb..339ab26a68 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedInt64Array" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedInt64Array" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A packed array of 64-bit integers.
</brief_description>
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index 241dd637fc..f945ce30ad 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedScene" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedScene" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An abstraction of a serialized scene.
</brief_description>
diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml
index b442085d4d..c2ae3cf3d3 100644
--- a/doc/classes/PackedStringArray.xml
+++ b/doc/classes/PackedStringArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedStringArray" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedStringArray" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A packed array of [String]s.
</brief_description>
diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml
index a5a5d2f2df..9f8671f076 100644
--- a/doc/classes/PackedVector2Array.xml
+++ b/doc/classes/PackedVector2Array.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedVector2Array" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedVector2Array" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A packed array of [Vector2]s.
</brief_description>
diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml
index 2557549703..54f65a619b 100644
--- a/doc/classes/PackedVector3Array.xml
+++ b/doc/classes/PackedVector3Array.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedVector3Array" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PackedVector3Array" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A packed array of [Vector3]s.
</brief_description>
diff --git a/doc/classes/PacketPeer.xml b/doc/classes/PacketPeer.xml
index 8ba9474232..85917efe25 100644
--- a/doc/classes/PacketPeer.xml
+++ b/doc/classes/PacketPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PacketPeer" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PacketPeer" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstraction and base class for packet-based protocols.
</brief_description>
diff --git a/doc/classes/PacketPeerDTLS.xml b/doc/classes/PacketPeerDTLS.xml
index d94afe05be..4e2a7b70cd 100644
--- a/doc/classes/PacketPeerDTLS.xml
+++ b/doc/classes/PacketPeerDTLS.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PacketPeerDTLS" inherits="PacketPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PacketPeerDTLS" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
DTLS packet peer.
</brief_description>
diff --git a/doc/classes/PacketPeerExtension.xml b/doc/classes/PacketPeerExtension.xml
index 0edcbd7b12..c37da6402f 100644
--- a/doc/classes/PacketPeerExtension.xml
+++ b/doc/classes/PacketPeerExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PacketPeerExtension" inherits="PacketPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PacketPeerExtension" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/PacketPeerStream.xml b/doc/classes/PacketPeerStream.xml
index dbc832a6a1..57bd4e007a 100644
--- a/doc/classes/PacketPeerStream.xml
+++ b/doc/classes/PacketPeerStream.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PacketPeerStream" inherits="PacketPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PacketPeerStream" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Wrapper to use a PacketPeer over a StreamPeer.
</brief_description>
diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml
index cc8eee97b1..bd774ac34c 100644
--- a/doc/classes/PacketPeerUDP.xml
+++ b/doc/classes/PacketPeerUDP.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PacketPeerUDP" inherits="PacketPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PacketPeerUDP" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
UDP packet peer.
</brief_description>
diff --git a/doc/classes/Panel.xml b/doc/classes/Panel.xml
index 92ed109e70..db1fa1ccda 100644
--- a/doc/classes/Panel.xml
+++ b/doc/classes/Panel.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Panel" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Panel" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A GUI control that displays a [StyleBox].
</brief_description>
diff --git a/doc/classes/PanelContainer.xml b/doc/classes/PanelContainer.xml
index 2217fde78c..c6b3604cc4 100644
--- a/doc/classes/PanelContainer.xml
+++ b/doc/classes/PanelContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PanelContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PanelContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that keeps its child controls within the area of a [StyleBox].
</brief_description>
diff --git a/doc/classes/PanoramaSkyMaterial.xml b/doc/classes/PanoramaSkyMaterial.xml
index 2a266fa2c1..ab32ca48dd 100644
--- a/doc/classes/PanoramaSkyMaterial.xml
+++ b/doc/classes/PanoramaSkyMaterial.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PanoramaSkyMaterial" inherits="Material" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PanoramaSkyMaterial" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Material] used with [Sky] to draw a background texture.
</brief_description>
diff --git a/doc/classes/ParallaxBackground.xml b/doc/classes/ParallaxBackground.xml
index 76dcf6e83a..8838742bff 100644
--- a/doc/classes/ParallaxBackground.xml
+++ b/doc/classes/ParallaxBackground.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ParallaxBackground" inherits="CanvasLayer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ParallaxBackground" inherits="CanvasLayer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node used to create a parallax scrolling background.
</brief_description>
diff --git a/doc/classes/ParallaxLayer.xml b/doc/classes/ParallaxLayer.xml
index 54301f1577..86ac2165d8 100644
--- a/doc/classes/ParallaxLayer.xml
+++ b/doc/classes/ParallaxLayer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ParallaxLayer" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ParallaxLayer" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A parallax scrolling layer to be used with [ParallaxBackground].
</brief_description>
diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml
index 3a7fa0760f..69d3351733 100644
--- a/doc/classes/ParticleProcessMaterial.xml
+++ b/doc/classes/ParticleProcessMaterial.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ParticleProcessMaterial" inherits="Material" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ParticleProcessMaterial" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Particle properties for [GPUParticles3D] and [GPUParticles2D] nodes.
</brief_description>
diff --git a/doc/classes/Path2D.xml b/doc/classes/Path2D.xml
index 93e8c83182..7c4b182258 100644
--- a/doc/classes/Path2D.xml
+++ b/doc/classes/Path2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Path2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Path2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Contains a [Curve2D] path for [PathFollow2D] nodes to follow.
</brief_description>
diff --git a/doc/classes/Path3D.xml b/doc/classes/Path3D.xml
index d41766e119..730bcfd48c 100644
--- a/doc/classes/Path3D.xml
+++ b/doc/classes/Path3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Path3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Path3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Contains a [Curve3D] path for [PathFollow3D] nodes to follow.
</brief_description>
diff --git a/doc/classes/PathFollow2D.xml b/doc/classes/PathFollow2D.xml
index d958d4c14f..61db34fb02 100644
--- a/doc/classes/PathFollow2D.xml
+++ b/doc/classes/PathFollow2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PathFollow2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PathFollow2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Point sampler for a [Path2D].
</brief_description>
diff --git a/doc/classes/PathFollow3D.xml b/doc/classes/PathFollow3D.xml
index 8d4101df0b..b505c6ea8b 100644
--- a/doc/classes/PathFollow3D.xml
+++ b/doc/classes/PathFollow3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PathFollow3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PathFollow3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Point sampler for a [Path3D].
</brief_description>
diff --git a/doc/classes/Performance.xml b/doc/classes/Performance.xml
index 65680e8615..377dbba9fc 100644
--- a/doc/classes/Performance.xml
+++ b/doc/classes/Performance.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Performance" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Performance" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exposes performance-related data.
</brief_description>
diff --git a/doc/classes/PhysicalBone2D.xml b/doc/classes/PhysicalBone2D.xml
index f201016f9c..b22b246978 100644
--- a/doc/classes/PhysicalBone2D.xml
+++ b/doc/classes/PhysicalBone2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicalBone2D" inherits="RigidBody2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicalBone2D" inherits="RigidBody2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [RigidBody2D]-derived node used to make [Bone2D]s in a [Skeleton2D] react to physics.
</brief_description>
@@ -32,7 +32,7 @@
The index of the [Bone2D] that this [PhysicalBone2D] should simulate.
</member>
<member name="bone2d_nodepath" type="NodePath" setter="set_bone2d_nodepath" getter="get_bone2d_nodepath" default="NodePath(&quot;&quot;)">
- The [NodePath] to the [Bone2D] that this [PhysicalBone2D] isshould simulate.
+ The [NodePath] to the [Bone2D] that this [PhysicalBone2D] should simulate.
</member>
<member name="follow_bone_when_simulating" type="bool" setter="set_follow_bone_when_simulating" getter="get_follow_bone_when_simulating" default="false">
If [code]true[/code], the [PhysicalBone2D] will keep the transform of the bone it is bound to when simulating physics.
diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml
index 06941c0a50..b69fb7050e 100644
--- a/doc/classes/PhysicalBone3D.xml
+++ b/doc/classes/PhysicalBone3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicalBone3D" inherits="PhysicsBody3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicalBone3D" inherits="PhysicsBody3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics body used to make bones in a [Skeleton3D] react to physics.
</brief_description>
diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml
index 7f996a987d..e6a9980e19 100644
--- a/doc/classes/PhysicalSkyMaterial.xml
+++ b/doc/classes/PhysicalSkyMaterial.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicalSkyMaterial" inherits="Material" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicalSkyMaterial" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
[Sky] [Material] used for a physically based sky.
</brief_description>
diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index 445cf3a762..adfdfdc445 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsBody2D" inherits="CollisionObject2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsBody2D" inherits="CollisionObject2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for 2D game objects affected by physics.
</brief_description>
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
index b8e77083f1..ff994fe6c5 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsBody3D" inherits="CollisionObject3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsBody3D" inherits="CollisionObject3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for 3D game objects affected by physics.
</brief_description>
diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml
index 7928fa1717..7051663a78 100644
--- a/doc/classes/PhysicsDirectBodyState2D.xml
+++ b/doc/classes/PhysicsDirectBodyState2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectBodyState2D" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsDirectBodyState2D" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides direct access to a physics body in the [PhysicsServer2D].
</brief_description>
diff --git a/doc/classes/PhysicsDirectBodyState2DExtension.xml b/doc/classes/PhysicsDirectBodyState2DExtension.xml
index eee723ca0f..04612b461e 100644
--- a/doc/classes/PhysicsDirectBodyState2DExtension.xml
+++ b/doc/classes/PhysicsDirectBodyState2DExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectBodyState2DExtension" inherits="PhysicsDirectBodyState2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsDirectBodyState2DExtension" inherits="PhysicsDirectBodyState2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides virtual methods that can be overridden to create custom [PhysicsDirectBodyState2D] implementations.
</brief_description>
diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml
index 8b2656187c..42c65763aa 100644
--- a/doc/classes/PhysicsDirectBodyState3D.xml
+++ b/doc/classes/PhysicsDirectBodyState3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectBodyState3D" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsDirectBodyState3D" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides direct access to a physics body in the [PhysicsServer3D].
</brief_description>
diff --git a/doc/classes/PhysicsDirectBodyState3DExtension.xml b/doc/classes/PhysicsDirectBodyState3DExtension.xml
index 8bca17a08f..ddcc8a865f 100644
--- a/doc/classes/PhysicsDirectBodyState3DExtension.xml
+++ b/doc/classes/PhysicsDirectBodyState3DExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectBodyState3DExtension" inherits="PhysicsDirectBodyState3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsDirectBodyState3DExtension" inherits="PhysicsDirectBodyState3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides virtual methods that can be overridden to create custom [PhysicsDirectBodyState3D] implementations.
</brief_description>
diff --git a/doc/classes/PhysicsDirectSpaceState2D.xml b/doc/classes/PhysicsDirectSpaceState2D.xml
index 2d88601319..94e9096334 100644
--- a/doc/classes/PhysicsDirectSpaceState2D.xml
+++ b/doc/classes/PhysicsDirectSpaceState2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectSpaceState2D" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsDirectSpaceState2D" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides direct access to a physics space in the [PhysicsServer2D].
</brief_description>
diff --git a/doc/classes/PhysicsDirectSpaceState2DExtension.xml b/doc/classes/PhysicsDirectSpaceState2DExtension.xml
index f38d7ec4b4..8a0498cbd9 100644
--- a/doc/classes/PhysicsDirectSpaceState2DExtension.xml
+++ b/doc/classes/PhysicsDirectSpaceState2DExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectSpaceState2DExtension" inherits="PhysicsDirectSpaceState2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsDirectSpaceState2DExtension" inherits="PhysicsDirectSpaceState2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides virtual methods that can be overridden to create custom [PhysicsDirectSpaceState2D] implementations.
</brief_description>
diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml
index e3eda631c6..17324e49c6 100644
--- a/doc/classes/PhysicsDirectSpaceState3D.xml
+++ b/doc/classes/PhysicsDirectSpaceState3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectSpaceState3D" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsDirectSpaceState3D" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides direct access to a physics space in the [PhysicsServer3D].
</brief_description>
diff --git a/doc/classes/PhysicsDirectSpaceState3DExtension.xml b/doc/classes/PhysicsDirectSpaceState3DExtension.xml
index b3377c31b1..372b059cb6 100644
--- a/doc/classes/PhysicsDirectSpaceState3DExtension.xml
+++ b/doc/classes/PhysicsDirectSpaceState3DExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectSpaceState3DExtension" inherits="PhysicsDirectSpaceState3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsDirectSpaceState3DExtension" inherits="PhysicsDirectSpaceState3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides virtual methods that can be overridden to create custom [PhysicsDirectSpaceState3D] implementations.
</brief_description>
diff --git a/doc/classes/PhysicsMaterial.xml b/doc/classes/PhysicsMaterial.xml
index 16a1989e8c..30c2400775 100644
--- a/doc/classes/PhysicsMaterial.xml
+++ b/doc/classes/PhysicsMaterial.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsMaterial" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsMaterial" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds physics-related properties of a surface, namely its roughness and bounciness.
</brief_description>
diff --git a/doc/classes/PhysicsPointQueryParameters2D.xml b/doc/classes/PhysicsPointQueryParameters2D.xml
index 82a32b79e0..521e584173 100644
--- a/doc/classes/PhysicsPointQueryParameters2D.xml
+++ b/doc/classes/PhysicsPointQueryParameters2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsPointQueryParameters2D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsPointQueryParameters2D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for [method PhysicsDirectSpaceState2D.intersect_point].
</brief_description>
diff --git a/doc/classes/PhysicsPointQueryParameters3D.xml b/doc/classes/PhysicsPointQueryParameters3D.xml
index e28a0ed869..1cbc11bd03 100644
--- a/doc/classes/PhysicsPointQueryParameters3D.xml
+++ b/doc/classes/PhysicsPointQueryParameters3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsPointQueryParameters3D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsPointQueryParameters3D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for [method PhysicsDirectSpaceState3D.intersect_point].
</brief_description>
diff --git a/doc/classes/PhysicsRayQueryParameters2D.xml b/doc/classes/PhysicsRayQueryParameters2D.xml
index fa1067a245..3d69e092f6 100644
--- a/doc/classes/PhysicsRayQueryParameters2D.xml
+++ b/doc/classes/PhysicsRayQueryParameters2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsRayQueryParameters2D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsRayQueryParameters2D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for [method PhysicsDirectSpaceState2D.intersect_ray].
</brief_description>
diff --git a/doc/classes/PhysicsRayQueryParameters3D.xml b/doc/classes/PhysicsRayQueryParameters3D.xml
index dd3df6db2f..b203b8f555 100644
--- a/doc/classes/PhysicsRayQueryParameters3D.xml
+++ b/doc/classes/PhysicsRayQueryParameters3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsRayQueryParameters3D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsRayQueryParameters3D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for [method PhysicsDirectSpaceState3D.intersect_ray].
</brief_description>
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index ddbe0ff027..39d18a9e35 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsServer2D" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsServer2D" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A server interface for low-level 2D physics access.
</brief_description>
diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml
index 96d2f45fc3..e2f86cae5d 100644
--- a/doc/classes/PhysicsServer2DExtension.xml
+++ b/doc/classes/PhysicsServer2DExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsServer2DExtension" inherits="PhysicsServer2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsServer2DExtension" inherits="PhysicsServer2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides virtual methods that can be overridden to create custom [PhysicsServer2D] implementations.
</brief_description>
diff --git a/doc/classes/PhysicsServer2DManager.xml b/doc/classes/PhysicsServer2DManager.xml
index 5fc161207b..5b6e9812f6 100644
--- a/doc/classes/PhysicsServer2DManager.xml
+++ b/doc/classes/PhysicsServer2DManager.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsServer2DManager" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsServer2DManager" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton for managing [PhysicsServer2D] implementations.
</brief_description>
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index 22f7579017..f3441f45ed 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsServer3D" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsServer3D" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A server interface for low-level 3D physics access.
</brief_description>
<description>
- PhysicsServer2D is the server responsible for all 2D physics. It can directly create and manipulate all physics objects:
+ PhysicsServer3D is the server responsible for all 3D physics. It can directly create and manipulate all physics objects:
- A [i]space[/i] is a self-contained world for a physics simulation. It contains bodies, areas, and joints. Its state can be queried for collision and intersection information, and several parameters of the simulation can be modified.
- A [i]shape[/i] is a geometric shape such as a sphere, a box, a cylinder, or a polygon. It can be used for collision detection by adding it to a body/area, possibly with an extra transformation relative to the body/area's origin. Bodies/areas can have multiple (transformed) shapes added to them, and a single shape can be added to bodies/areas multiple times with different local transformations.
- A [i]body[/i] is a physical object which can be in static, kinematic, or rigid mode. Its state (such as position and velocity) can be queried and updated. A force integration callback can be set to customize the body's physics.
@@ -1146,7 +1146,7 @@
A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
</constant>
<constant name="SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION" value="3" enum="SliderJointParam">
- The amount of restitution once the limits are surpassed. The lower, the more velocityenergy gets lost.
+ The amount of restitution once the limits are surpassed. The lower, the more velocity-energy gets lost.
</constant>
<constant name="SLIDER_JOINT_LINEAR_LIMIT_DAMPING" value="4" enum="SliderJointParam">
The amount of damping once the slider limits are surpassed.
diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml
index cddf696554..e58a7ff9a8 100644
--- a/doc/classes/PhysicsServer3DExtension.xml
+++ b/doc/classes/PhysicsServer3DExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsServer3DExtension" inherits="PhysicsServer3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsServer3DExtension" inherits="PhysicsServer3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides virtual methods that can be overridden to create custom [PhysicsServer3D] implementations.
</brief_description>
diff --git a/doc/classes/PhysicsServer3DManager.xml b/doc/classes/PhysicsServer3DManager.xml
index fbc1111861..a187f3c355 100644
--- a/doc/classes/PhysicsServer3DManager.xml
+++ b/doc/classes/PhysicsServer3DManager.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsServer3DManager" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsServer3DManager" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton for managing [PhysicsServer3D] implementations.
</brief_description>
diff --git a/doc/classes/PhysicsServer3DRenderingServerHandler.xml b/doc/classes/PhysicsServer3DRenderingServerHandler.xml
index 11c82e0327..da04cd918c 100644
--- a/doc/classes/PhysicsServer3DRenderingServerHandler.xml
+++ b/doc/classes/PhysicsServer3DRenderingServerHandler.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsServer3DRenderingServerHandler" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsServer3DRenderingServerHandler" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A class used to provide [method PhysicsServer3DExtension._soft_body_update_rendering_server] with a rendering handler for soft bodies.
</brief_description>
diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml
index a8de91736b..915d94a54c 100644
--- a/doc/classes/PhysicsShapeQueryParameters2D.xml
+++ b/doc/classes/PhysicsShapeQueryParameters2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsShapeQueryParameters2D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsShapeQueryParameters2D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for [method PhysicsDirectSpaceState2D.intersect_shape].
</brief_description>
diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml
index af2cab0992..eba2b8287f 100644
--- a/doc/classes/PhysicsShapeQueryParameters3D.xml
+++ b/doc/classes/PhysicsShapeQueryParameters3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsShapeQueryParameters3D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsShapeQueryParameters3D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for [method PhysicsDirectSpaceState3D.intersect_shape].
</brief_description>
diff --git a/doc/classes/PhysicsTestMotionParameters2D.xml b/doc/classes/PhysicsTestMotionParameters2D.xml
index 31394d188e..1288bfaf91 100644
--- a/doc/classes/PhysicsTestMotionParameters2D.xml
+++ b/doc/classes/PhysicsTestMotionParameters2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsTestMotionParameters2D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsTestMotionParameters2D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for [method PhysicsServer2D.body_test_motion].
</brief_description>
diff --git a/doc/classes/PhysicsTestMotionParameters3D.xml b/doc/classes/PhysicsTestMotionParameters3D.xml
index a7c85c363c..9995f0cbc8 100644
--- a/doc/classes/PhysicsTestMotionParameters3D.xml
+++ b/doc/classes/PhysicsTestMotionParameters3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsTestMotionParameters3D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsTestMotionParameters3D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides parameters for [method PhysicsServer3D.body_test_motion].
</brief_description>
diff --git a/doc/classes/PhysicsTestMotionResult2D.xml b/doc/classes/PhysicsTestMotionResult2D.xml
index db882889cc..1b12431f7f 100644
--- a/doc/classes/PhysicsTestMotionResult2D.xml
+++ b/doc/classes/PhysicsTestMotionResult2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsTestMotionResult2D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsTestMotionResult2D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Describes the motion and collision result from [method PhysicsServer2D.body_test_motion].
</brief_description>
diff --git a/doc/classes/PhysicsTestMotionResult3D.xml b/doc/classes/PhysicsTestMotionResult3D.xml
index c15324c741..0dac6115bc 100644
--- a/doc/classes/PhysicsTestMotionResult3D.xml
+++ b/doc/classes/PhysicsTestMotionResult3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsTestMotionResult3D" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicsTestMotionResult3D" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Describes the motion and collision result from [method PhysicsServer3D.body_test_motion].
</brief_description>
diff --git a/doc/classes/PinJoint2D.xml b/doc/classes/PinJoint2D.xml
index 8c3fd935c6..6adfc818e7 100644
--- a/doc/classes/PinJoint2D.xml
+++ b/doc/classes/PinJoint2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PinJoint2D" inherits="Joint2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PinJoint2D" inherits="Joint2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics joint that attaches two 2D physics bodies at a single point, allowing them to freely rotate.
</brief_description>
diff --git a/doc/classes/PinJoint3D.xml b/doc/classes/PinJoint3D.xml
index c02c4c960f..9009f0b658 100644
--- a/doc/classes/PinJoint3D.xml
+++ b/doc/classes/PinJoint3D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PinJoint3D" inherits="Joint3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PinJoint3D" inherits="Joint3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics joint that attaches two 3D physics bodies at a single point, allowing them to freely rotate.
</brief_description>
<description>
- A physics joint that attaches two 2D physics bodies at a single point, allowing them to freely rotate. For example, a [RigidBody3D] can be attached to a [StaticBody3D] to create a pendulum or a seesaw.
+ A physics joint that attaches two 3D physics bodies at a single point, allowing them to freely rotate. For example, a [RigidBody3D] can be attached to a [StaticBody3D] to create a pendulum or a seesaw.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PlaceholderCubemap.xml b/doc/classes/PlaceholderCubemap.xml
index 715cb13046..b760bf359b 100644
--- a/doc/classes/PlaceholderCubemap.xml
+++ b/doc/classes/PlaceholderCubemap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PlaceholderCubemap" inherits="PlaceholderTextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PlaceholderCubemap" inherits="PlaceholderTextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Placeholder class for a cubemap texture.
</brief_description>
diff --git a/doc/classes/PlaceholderCubemapArray.xml b/doc/classes/PlaceholderCubemapArray.xml
index 7270d44f81..1074824c0f 100644
--- a/doc/classes/PlaceholderCubemapArray.xml
+++ b/doc/classes/PlaceholderCubemapArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PlaceholderCubemapArray" inherits="PlaceholderTextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PlaceholderCubemapArray" inherits="PlaceholderTextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Placeholder class for a cubemap texture array.
</brief_description>
diff --git a/doc/classes/PlaceholderMaterial.xml b/doc/classes/PlaceholderMaterial.xml
index e386cbe8c5..25957f5fb2 100644
--- a/doc/classes/PlaceholderMaterial.xml
+++ b/doc/classes/PlaceholderMaterial.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PlaceholderMaterial" inherits="Material" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PlaceholderMaterial" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Placeholder class for a material.
</brief_description>
diff --git a/doc/classes/PlaceholderMesh.xml b/doc/classes/PlaceholderMesh.xml
index 5f4068d8b6..30234dbeab 100644
--- a/doc/classes/PlaceholderMesh.xml
+++ b/doc/classes/PlaceholderMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PlaceholderMesh" inherits="Mesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PlaceholderMesh" inherits="Mesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Placeholder class for a mesh.
</brief_description>
diff --git a/doc/classes/PlaceholderTexture2D.xml b/doc/classes/PlaceholderTexture2D.xml
index ba934ebf3c..c48a9ee58b 100644
--- a/doc/classes/PlaceholderTexture2D.xml
+++ b/doc/classes/PlaceholderTexture2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PlaceholderTexture2D" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PlaceholderTexture2D" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Placeholder class for a 2-dimensional texture.
</brief_description>
diff --git a/doc/classes/PlaceholderTexture2DArray.xml b/doc/classes/PlaceholderTexture2DArray.xml
index 665f87d920..3dcd578648 100644
--- a/doc/classes/PlaceholderTexture2DArray.xml
+++ b/doc/classes/PlaceholderTexture2DArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PlaceholderTexture2DArray" inherits="PlaceholderTextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PlaceholderTexture2DArray" inherits="PlaceholderTextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Placeholder class for a 2-dimensional texture array.
</brief_description>
diff --git a/doc/classes/PlaceholderTexture3D.xml b/doc/classes/PlaceholderTexture3D.xml
index b5b136b035..d290799f64 100644
--- a/doc/classes/PlaceholderTexture3D.xml
+++ b/doc/classes/PlaceholderTexture3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PlaceholderTexture3D" inherits="Texture3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PlaceholderTexture3D" inherits="Texture3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Placeholder class for a 3-dimensional texture.
</brief_description>
diff --git a/doc/classes/PlaceholderTextureLayered.xml b/doc/classes/PlaceholderTextureLayered.xml
index 954a9f6154..a0385b2793 100644
--- a/doc/classes/PlaceholderTextureLayered.xml
+++ b/doc/classes/PlaceholderTextureLayered.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PlaceholderTextureLayered" inherits="TextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PlaceholderTextureLayered" inherits="TextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Placeholder class for a 2-dimensional texture array.
</brief_description>
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index 0b147934d4..6faf83c0d6 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Plane" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Plane" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A plane in Hessian normal form.
</brief_description>
diff --git a/doc/classes/PlaneMesh.xml b/doc/classes/PlaneMesh.xml
index 0d2ee5179e..e8947ffd67 100644
--- a/doc/classes/PlaneMesh.xml
+++ b/doc/classes/PlaneMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PlaneMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PlaneMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Class representing a planar [PrimitiveMesh].
</brief_description>
diff --git a/doc/classes/PointLight2D.xml b/doc/classes/PointLight2D.xml
index ae8fc708fa..556ad50cb1 100644
--- a/doc/classes/PointLight2D.xml
+++ b/doc/classes/PointLight2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PointLight2D" inherits="Light2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PointLight2D" inherits="Light2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Positional 2D light source.
</brief_description>
diff --git a/doc/classes/PointMesh.xml b/doc/classes/PointMesh.xml
index 3741baba4c..201e44af19 100644
--- a/doc/classes/PointMesh.xml
+++ b/doc/classes/PointMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PointMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PointMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Mesh with a single Point primitive.
</brief_description>
diff --git a/doc/classes/Polygon2D.xml b/doc/classes/Polygon2D.xml
index e40abd3312..73c3c022b7 100644
--- a/doc/classes/Polygon2D.xml
+++ b/doc/classes/Polygon2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Polygon2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Polygon2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D polygon.
</brief_description>
diff --git a/doc/classes/PolygonOccluder3D.xml b/doc/classes/PolygonOccluder3D.xml
index aab6c5c6d0..a33722c38a 100644
--- a/doc/classes/PolygonOccluder3D.xml
+++ b/doc/classes/PolygonOccluder3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PolygonOccluder3D" inherits="Occluder3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PolygonOccluder3D" inherits="Occluder3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Flat 2D polygon shape for use with occlusion culling in [OccluderInstance3D].
</brief_description>
diff --git a/doc/classes/PolygonPathFinder.xml b/doc/classes/PolygonPathFinder.xml
index 045cb568de..f37a8a05e4 100644
--- a/doc/classes/PolygonPathFinder.xml
+++ b/doc/classes/PolygonPathFinder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PolygonPathFinder" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PolygonPathFinder" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/Popup.xml b/doc/classes/Popup.xml
index cacf4ee7f2..29b44a98f2 100644
--- a/doc/classes/Popup.xml
+++ b/doc/classes/Popup.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Popup" inherits="Window" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Popup" inherits="Window" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for contextual windows and panels with fixed position.
</brief_description>
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 2b91236f56..daf3163842 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PopupMenu" inherits="Popup" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PopupMenu" inherits="Popup" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modal window used to display a list of options.
</brief_description>
diff --git a/doc/classes/PopupPanel.xml b/doc/classes/PopupPanel.xml
index a60d64e730..ad981116de 100644
--- a/doc/classes/PopupPanel.xml
+++ b/doc/classes/PopupPanel.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PopupPanel" inherits="Popup" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PopupPanel" inherits="Popup" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A popup with a panel background.
</brief_description>
diff --git a/doc/classes/PortableCompressedTexture2D.xml b/doc/classes/PortableCompressedTexture2D.xml
index c5e49eb15c..3fc2aa2ab9 100644
--- a/doc/classes/PortableCompressedTexture2D.xml
+++ b/doc/classes/PortableCompressedTexture2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PortableCompressedTexture2D" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PortableCompressedTexture2D" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides a compressed texture for disk and/or VRAM in a way that is portable.
</brief_description>
diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml
index 7bcf3ce46b..d04d8eea52 100644
--- a/doc/classes/PrimitiveMesh.xml
+++ b/doc/classes/PrimitiveMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PrimitiveMesh" inherits="Mesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PrimitiveMesh" inherits="Mesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh.
</brief_description>
diff --git a/doc/classes/PrismMesh.xml b/doc/classes/PrismMesh.xml
index 2cecbdd920..862994e9b7 100644
--- a/doc/classes/PrismMesh.xml
+++ b/doc/classes/PrismMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PrismMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PrismMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Class representing a prism-shaped [PrimitiveMesh].
</brief_description>
diff --git a/doc/classes/ProceduralSkyMaterial.xml b/doc/classes/ProceduralSkyMaterial.xml
index 802a54afde..e3a1177cfa 100644
--- a/doc/classes/ProceduralSkyMaterial.xml
+++ b/doc/classes/ProceduralSkyMaterial.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ProceduralSkyMaterial" inherits="Material" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ProceduralSkyMaterial" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Material] used with [Sky] to generate a background based on user input parameters.
</brief_description>
diff --git a/doc/classes/ProgressBar.xml b/doc/classes/ProgressBar.xml
index cf39fb4247..595749f4b6 100644
--- a/doc/classes/ProgressBar.xml
+++ b/doc/classes/ProgressBar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ProgressBar" inherits="Range" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ProgressBar" inherits="Range" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control used for visual representation of a percentage.
</brief_description>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 21d5c30ae9..02f001edc9 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ProjectSettings" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ProjectSettings" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Stores globally-accessible variables.
</brief_description>
@@ -819,7 +819,7 @@
Name of the .NET assembly. This name is used as the name of the [code].csproj[/code] and [code].sln[/code] files. By default, it's set to the name of the project ([member application/config/name]) allowing to change it in the future without affecting the .NET assembly.
</member>
<member name="dotnet/project/assembly_reload_attempts" type="int" setter="" getter="" default="3">
- Number of times to attempt assembly reloading after rebuilding .NET assembies. Effectively also the timeout in seconds to wait for unloading of script assemblies to finish.
+ Number of times to attempt assembly reloading after rebuilding .NET assemblies. Effectively also the timeout in seconds to wait for unloading of script assemblies to finish.
</member>
<member name="dotnet/project/solution_directory" type="String" setter="" getter="" default="&quot;&quot;">
Directory that contains the [code].sln[/code] file. By default, the [code].sln[/code] files is in the root of the project directory, next to the [code]project.godot[/code] and [code].csproj[/code] files.
@@ -935,23 +935,26 @@
Path to a custom [Font] resource to use as default for all GUI elements of the project.
</member>
<member name="gui/theme/default_font_antialiasing" type="int" setter="" getter="" default="1">
- Font anti-aliasing mode. See [member FontFile.antialiasing].
+ Font anti-aliasing mode for the default project font. See [member FontFile.antialiasing].
+ [b]Note:[/b] This setting does not affect custom [Font]s used within the project. Use the [b]Import[/b] dock for that instead (see [member ResourceImporterDynamicFont.antialiasing]).
</member>
<member name="gui/theme/default_font_generate_mipmaps" type="bool" setter="" getter="" default="false">
If set to [code]true[/code], the default font will have mipmaps generated. This prevents text from looking grainy when a [Control] is scaled down, or when a [Label3D] is viewed from a long distance (if [member Label3D.texture_filter] is set to a mode that displays mipmaps).
Enabling [member gui/theme/default_font_generate_mipmaps] increases font generation time and memory usage. Only enable this setting if you actually need it.
- [b]Note:[/b] This setting does not affect custom [Font]s used within the project.
+ [b]Note:[/b] This setting does not affect custom [Font]s used within the project. Use the [b]Import[/b] dock for that instead (see [member ResourceImporterDynamicFont.generate_mipmaps]).
</member>
<member name="gui/theme/default_font_hinting" type="int" setter="" getter="" default="1">
- Default font hinting mode. See [member FontFile.hinting].
+ Font hinting mode for the default project font. See [member FontFile.hinting].
+ [b]Note:[/b] This setting does not affect custom [Font]s used within the project. Use the [b]Import[/b] dock for that instead (see [member ResourceImporterDynamicFont.hinting]).
</member>
<member name="gui/theme/default_font_multichannel_signed_distance_field" type="bool" setter="" getter="" default="false">
If set to [code]true[/code], the default font will use multichannel signed distance field (MSDF) for crisp rendering at any size. Since this approach does not rely on rasterizing the font every time its size changes, this allows for resizing the font in real-time without any performance penalty. Text will also not look grainy for [Control]s that are scaled down (or for [Label3D]s viewed from a long distance).
MSDF font rendering can be combined with [member gui/theme/default_font_generate_mipmaps] to further improve font rendering quality when scaled down.
- [b]Note:[/b] This setting does not affect custom [Font]s used within the project.
+ [b]Note:[/b] This setting does not affect custom [Font]s used within the project. Use the [b]Import[/b] dock for that instead (see [member ResourceImporterDynamicFont.multichannel_signed_distance_field]).
</member>
<member name="gui/theme/default_font_subpixel_positioning" type="int" setter="" getter="" default="1">
- Default font glyph subpixel positioning mode. See [member FontFile.subpixel_positioning].
+ Font glyph subpixel positioning mode for the default project font. See [member FontFile.subpixel_positioning].
+ [b]Note:[/b] This setting does not affect custom [Font]s used within the project. Use the [b]Import[/b] dock for that instead (see [member ResourceImporterDynamicFont.subpixel_positioning]).
</member>
<member name="gui/theme/default_theme_scale" type="float" setter="" getter="" default="1.0">
The default scale factor for [Control]s, when not overridden by a [Theme].
@@ -1943,13 +1946,13 @@
<member name="memory/limits/multithreaded_server/rid_pool_prealloc" type="int" setter="" getter="" default="60">
This is used by servers when used in multi-threading mode (servers and visual). RIDs are preallocated to avoid stalling the server requesting them on threads. If servers get stalled too often when loading resources in a thread, increase this number.
</member>
- <member name="navigation/2d/default_cell_size" type="int" setter="" getter="" default="1">
+ <member name="navigation/2d/default_cell_size" type="float" setter="" getter="" default="1.0">
Default cell size for 2D navigation maps. See [method NavigationServer2D.map_set_cell_size].
</member>
- <member name="navigation/2d/default_edge_connection_margin" type="int" setter="" getter="" default="1">
+ <member name="navigation/2d/default_edge_connection_margin" type="float" setter="" getter="" default="1.0">
Default edge connection margin for 2D navigation maps. See [method NavigationServer2D.map_set_edge_connection_margin].
</member>
- <member name="navigation/2d/default_link_connection_radius" type="int" setter="" getter="" default="4">
+ <member name="navigation/2d/default_link_connection_radius" type="float" setter="" getter="" default="4.0">
Default link connection radius for 2D navigation maps. See [method NavigationServer2D.map_set_link_connection_radius].
</member>
<member name="navigation/2d/use_edge_connections" type="bool" setter="" getter="" default="true">
@@ -1967,6 +1970,9 @@
<member name="navigation/3d/default_link_connection_radius" type="float" setter="" getter="" default="1.0">
Default link connection radius for 3D navigation maps. See [method NavigationServer3D.map_set_link_connection_radius].
</member>
+ <member name="navigation/3d/default_up" type="Vector3" setter="" getter="" default="Vector3(0, 1, 0)">
+ Default up orientation for 3D navigation maps. See [method NavigationServer3D.map_set_up].
+ </member>
<member name="navigation/3d/use_edge_connections" type="bool" setter="" getter="" default="true">
If enabled 3D navigation regions will use edge connections to connect with other navigation regions within proximity of the navigation map edge connection margin. This setting only affects World3D default navigation maps.
</member>
diff --git a/doc/classes/Projection.xml b/doc/classes/Projection.xml
index 49392ce6f2..694556a693 100644
--- a/doc/classes/Projection.xml
+++ b/doc/classes/Projection.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Projection" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Projection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 4×4 matrix for 3D projective transformations.
</brief_description>
diff --git a/doc/classes/PropertyTweener.xml b/doc/classes/PropertyTweener.xml
index 9859095e4d..73e594218d 100644
--- a/doc/classes/PropertyTweener.xml
+++ b/doc/classes/PropertyTweener.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PropertyTweener" inherits="Tweener" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PropertyTweener" inherits="Tweener" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Interpolates an [Object]'s property over time.
</brief_description>
diff --git a/doc/classes/QuadMesh.xml b/doc/classes/QuadMesh.xml
index 6b0c6503ce..c5164e9feb 100644
--- a/doc/classes/QuadMesh.xml
+++ b/doc/classes/QuadMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="QuadMesh" inherits="PlaneMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="QuadMesh" inherits="PlaneMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Class representing a square mesh facing the camera.
</brief_description>
diff --git a/doc/classes/QuadOccluder3D.xml b/doc/classes/QuadOccluder3D.xml
index d1706ba6a0..717cc44bb5 100644
--- a/doc/classes/QuadOccluder3D.xml
+++ b/doc/classes/QuadOccluder3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="QuadOccluder3D" inherits="Occluder3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="QuadOccluder3D" inherits="Occluder3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Flat plane shape for use with occlusion culling in [OccluderInstance3D].
</brief_description>
diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml
index a606570ccf..0499d51d79 100644
--- a/doc/classes/Quaternion.xml
+++ b/doc/classes/Quaternion.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Quaternion" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Quaternion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A unit quaternion used for representing 3D rotations.
</brief_description>
diff --git a/doc/classes/RDAttachmentFormat.xml b/doc/classes/RDAttachmentFormat.xml
index 1c32041f4b..876162b80a 100644
--- a/doc/classes/RDAttachmentFormat.xml
+++ b/doc/classes/RDAttachmentFormat.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDAttachmentFormat" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDAttachmentFormat" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Attachment format (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDFramebufferPass.xml b/doc/classes/RDFramebufferPass.xml
index 5a296da19c..5ebe656aa9 100644
--- a/doc/classes/RDFramebufferPass.xml
+++ b/doc/classes/RDFramebufferPass.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDFramebufferPass" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDFramebufferPass" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Framebuffer pass attachment description (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDPipelineColorBlendState.xml b/doc/classes/RDPipelineColorBlendState.xml
index 363349927e..550d1ab93e 100644
--- a/doc/classes/RDPipelineColorBlendState.xml
+++ b/doc/classes/RDPipelineColorBlendState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineColorBlendState" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDPipelineColorBlendState" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Pipeline color blend state (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDPipelineColorBlendStateAttachment.xml b/doc/classes/RDPipelineColorBlendStateAttachment.xml
index 783c8b1864..616e6343ba 100644
--- a/doc/classes/RDPipelineColorBlendStateAttachment.xml
+++ b/doc/classes/RDPipelineColorBlendStateAttachment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineColorBlendStateAttachment" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDPipelineColorBlendStateAttachment" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Pipeline color blend state attachment (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDPipelineDepthStencilState.xml b/doc/classes/RDPipelineDepthStencilState.xml
index 3893e0188d..fa2a4e17c9 100644
--- a/doc/classes/RDPipelineDepthStencilState.xml
+++ b/doc/classes/RDPipelineDepthStencilState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineDepthStencilState" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDPipelineDepthStencilState" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Pipeline depth/stencil state (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDPipelineMultisampleState.xml b/doc/classes/RDPipelineMultisampleState.xml
index 635a2480de..8f43b3a2f7 100644
--- a/doc/classes/RDPipelineMultisampleState.xml
+++ b/doc/classes/RDPipelineMultisampleState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineMultisampleState" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDPipelineMultisampleState" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Pipeline multisample state (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDPipelineRasterizationState.xml b/doc/classes/RDPipelineRasterizationState.xml
index 79d0eeef48..9da66f3d0d 100644
--- a/doc/classes/RDPipelineRasterizationState.xml
+++ b/doc/classes/RDPipelineRasterizationState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineRasterizationState" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDPipelineRasterizationState" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Pipeline rasterization state (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDPipelineSpecializationConstant.xml b/doc/classes/RDPipelineSpecializationConstant.xml
index 9b1ca98708..3a45465cbf 100644
--- a/doc/classes/RDPipelineSpecializationConstant.xml
+++ b/doc/classes/RDPipelineSpecializationConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineSpecializationConstant" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDPipelineSpecializationConstant" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Pipeline specialization constant (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDSamplerState.xml b/doc/classes/RDSamplerState.xml
index 464fe61543..44f040dabd 100644
--- a/doc/classes/RDSamplerState.xml
+++ b/doc/classes/RDSamplerState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDSamplerState" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDSamplerState" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Sampler state (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDShaderFile.xml b/doc/classes/RDShaderFile.xml
index 98c719e6c8..62e2b02e2c 100644
--- a/doc/classes/RDShaderFile.xml
+++ b/doc/classes/RDShaderFile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDShaderFile" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDShaderFile" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Compiled shader file in SPIR-V form (used by [RenderingDevice]). Not to be confused with Godot's own [Shader].
</brief_description>
diff --git a/doc/classes/RDShaderSPIRV.xml b/doc/classes/RDShaderSPIRV.xml
index 3fc69431d2..de7c1a4ca7 100644
--- a/doc/classes/RDShaderSPIRV.xml
+++ b/doc/classes/RDShaderSPIRV.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDShaderSPIRV" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDShaderSPIRV" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
SPIR-V intermediate representation as part of a [RDShaderFile] (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDShaderSource.xml b/doc/classes/RDShaderSource.xml
index 054e882b91..062c22f11f 100644
--- a/doc/classes/RDShaderSource.xml
+++ b/doc/classes/RDShaderSource.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDShaderSource" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDShaderSource" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Shader source code (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDTextureFormat.xml b/doc/classes/RDTextureFormat.xml
index 7308127c3f..f8de7feda0 100644
--- a/doc/classes/RDTextureFormat.xml
+++ b/doc/classes/RDTextureFormat.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDTextureFormat" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDTextureFormat" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture format (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDTextureView.xml b/doc/classes/RDTextureView.xml
index 4e4e93f88a..30b6bfedf5 100644
--- a/doc/classes/RDTextureView.xml
+++ b/doc/classes/RDTextureView.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDTextureView" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDTextureView" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture view (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDUniform.xml b/doc/classes/RDUniform.xml
index a2d05502e7..7aab8b2810 100644
--- a/doc/classes/RDUniform.xml
+++ b/doc/classes/RDUniform.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDUniform" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDUniform" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Shader uniform (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RDVertexAttribute.xml b/doc/classes/RDVertexAttribute.xml
index 9347edf9db..31605f5471 100644
--- a/doc/classes/RDVertexAttribute.xml
+++ b/doc/classes/RDVertexAttribute.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDVertexAttribute" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RDVertexAttribute" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Vertex attribute (used by [RenderingDevice]).
</brief_description>
diff --git a/doc/classes/RID.xml b/doc/classes/RID.xml
index 907a322df8..8fd93d00b9 100644
--- a/doc/classes/RID.xml
+++ b/doc/classes/RID.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RID" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RID" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A handle for a [Resource]'s unique identifier.
</brief_description>
diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml
index 66b0f89023..383988360f 100644
--- a/doc/classes/RandomNumberGenerator.xml
+++ b/doc/classes/RandomNumberGenerator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RandomNumberGenerator" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RandomNumberGenerator" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides methods for generating pseudo-random numbers.
</brief_description>
diff --git a/doc/classes/Range.xml b/doc/classes/Range.xml
index e75b47af24..820ff04b70 100644
--- a/doc/classes/Range.xml
+++ b/doc/classes/Range.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Range" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Range" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for controls that represent a number within a range.
</brief_description>
diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml
index bcf1e364e9..6986b17c64 100644
--- a/doc/classes/RayCast2D.xml
+++ b/doc/classes/RayCast2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RayCast2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RayCast2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A ray in 2D space, used to find the first [CollisionObject2D] it intersects.
</brief_description>
diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml
index fa2badb1db..83476a6d48 100644
--- a/doc/classes/RayCast3D.xml
+++ b/doc/classes/RayCast3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RayCast3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RayCast3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A ray in 3D space, used to find the first [CollisionObject3D] it intersects.
</brief_description>
@@ -131,6 +131,9 @@
<member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" default="true">
If [code]true[/code], collisions will be ignored for this RayCast3D's immediate parent.
</member>
+ <member name="hit_back_faces" type="bool" setter="set_hit_back_faces" getter="is_hit_back_faces_enabled" default="true">
+ If [code]true[/code], the ray will hit back faces with concave polygon shapes with back face enabled or heightmap shapes.
+ </member>
<member name="hit_from_inside" type="bool" setter="set_hit_from_inside" getter="is_hit_from_inside_enabled" default="false">
If [code]true[/code], the ray will detect a hit when starting inside shapes. In this case the collision normal will be [code]Vector3(0, 0, 0)[/code]. Does not affect shapes with no volume like concave polygon or heightmap.
</member>
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index 344db842be..1b6e2bbeb2 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Rect2" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Rect2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D axis-aligned bounding box using floating-point coordinates.
</brief_description>
diff --git a/doc/classes/Rect2i.xml b/doc/classes/Rect2i.xml
index 31e5879ab4..5bb1a83cdc 100644
--- a/doc/classes/Rect2i.xml
+++ b/doc/classes/Rect2i.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Rect2i" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Rect2i" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D axis-aligned bounding box using integer coordinates.
</brief_description>
diff --git a/doc/classes/RectangleShape2D.xml b/doc/classes/RectangleShape2D.xml
index 5d0ccea297..721d73dc14 100644
--- a/doc/classes/RectangleShape2D.xml
+++ b/doc/classes/RectangleShape2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RectangleShape2D" inherits="Shape2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RectangleShape2D" inherits="Shape2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D rectangle shape used for physics collision.
</brief_description>
diff --git a/doc/classes/RefCounted.xml b/doc/classes/RefCounted.xml
index d4244dbcb7..eaf32a7b54 100644
--- a/doc/classes/RefCounted.xml
+++ b/doc/classes/RefCounted.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RefCounted" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RefCounted" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for reference-counted objects.
</brief_description>
diff --git a/doc/classes/ReferenceRect.xml b/doc/classes/ReferenceRect.xml
index fc6b6287f5..18e2fd5e95 100644
--- a/doc/classes/ReferenceRect.xml
+++ b/doc/classes/ReferenceRect.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ReferenceRect" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ReferenceRect" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A rectangle hint for designing UIs.
</brief_description>
diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml
index 42922d51e2..f53ddfc3ac 100644
--- a/doc/classes/ReflectionProbe.xml
+++ b/doc/classes/ReflectionProbe.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ReflectionProbe" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ReflectionProbe" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Captures its surroundings to create fast, accurate reflections from a given point.
</brief_description>
diff --git a/doc/classes/RemoteTransform2D.xml b/doc/classes/RemoteTransform2D.xml
index 85371151e4..d1f0e7cd69 100644
--- a/doc/classes/RemoteTransform2D.xml
+++ b/doc/classes/RemoteTransform2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RemoteTransform2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RemoteTransform2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
RemoteTransform2D pushes its own [Transform2D] to another [Node2D] derived node in the scene.
</brief_description>
diff --git a/doc/classes/RemoteTransform3D.xml b/doc/classes/RemoteTransform3D.xml
index 9d23661ded..a89e666d9b 100644
--- a/doc/classes/RemoteTransform3D.xml
+++ b/doc/classes/RemoteTransform3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RemoteTransform3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RemoteTransform3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
RemoteTransform3D pushes its own [Transform3D] to another [Node3D] derived Node in the scene.
</brief_description>
diff --git a/doc/classes/RenderSceneBuffers.xml b/doc/classes/RenderSceneBuffers.xml
new file mode 100644
index 0000000000..b2a5213dba
--- /dev/null
+++ b/doc/classes/RenderSceneBuffers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RenderSceneBuffers" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Abstract scene buffers object, created for each viewport for which 3D rendering is done.
+ </brief_description>
+ <description>
+ Abstract scene buffers object, created for each viewport for which 3D rendering is done. It manages any additional buffers used during rendering and will discard buffers when the viewport is resized.
+ [b]Note:[/b] this is an internal rendering server object only exposed for GDExtension plugins.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="configure">
+ <return type="void" />
+ <param index="0" name="config" type="RenderSceneBuffersConfiguration" />
+ <description>
+ This method is called by the rendering server when the associated viewports configuration is changed. It will discard the old buffers and recreate the internal buffers used.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/RenderSceneBuffersConfiguration.xml b/doc/classes/RenderSceneBuffersConfiguration.xml
new file mode 100644
index 0000000000..cb36955206
--- /dev/null
+++ b/doc/classes/RenderSceneBuffersConfiguration.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RenderSceneBuffersConfiguration" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Configuration object used to setup a [RenderSceneBuffers] object.
+ </brief_description>
+ <description>
+ This configuration object is created and populated by the render engine on a viewport change and used to (re)configure a [RenderSceneBuffers] object.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="fsr_sharpness" type="float" setter="set_fsr_sharpness" getter="get_fsr_sharpness" default="0.0">
+ FSR Sharpness applicable if FSR upscaling is used.
+ </member>
+ <member name="internal_size" type="Vector2i" setter="set_internal_size" getter="get_internal_size" default="Vector2i(0, 0)">
+ The size of the 3D render buffer used for rendering.
+ </member>
+ <member name="msaa_3d" type="int" setter="set_msaa_3d" getter="get_msaa_3d" enum="RenderingServer.ViewportMSAA" default="0">
+ The MSAA mode we're using for 3D rendering.
+ </member>
+ <member name="render_target" type="RID" setter="set_render_target" getter="get_render_target" default="RID()">
+ The render target associated with these buffer.
+ </member>
+ <member name="scaling_3d_mode" type="int" setter="set_scaling_3d_mode" getter="get_scaling_3d_mode" enum="RenderingServer.ViewportScaling3DMode" default="255">
+ The requested scaling mode with which we upscale/downscale if [member internal_size] and [member target_size] are not equal.
+ </member>
+ <member name="screen_space_aa" type="int" setter="set_screen_space_aa" getter="get_screen_space_aa" enum="RenderingServer.ViewportScreenSpaceAA" default="0">
+ The requested screen space AA applied in post processing.
+ </member>
+ <member name="target_size" type="Vector2i" setter="set_target_size" getter="get_target_size" default="Vector2i(0, 0)">
+ The target (upscale) size if scaling is used.
+ </member>
+ <member name="texture_mipmap_bias" type="float" setter="set_texture_mipmap_bias" getter="get_texture_mipmap_bias" default="0.0">
+ Bias applied to mipmaps.
+ </member>
+ <member name="view_count" type="int" setter="set_view_count" getter="get_view_count" default="1">
+ The number of views we're rendering.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/RenderSceneBuffersExtension.xml b/doc/classes/RenderSceneBuffersExtension.xml
new file mode 100644
index 0000000000..f9960f0fbe
--- /dev/null
+++ b/doc/classes/RenderSceneBuffersExtension.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RenderSceneBuffersExtension" inherits="RenderSceneBuffers" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ This class allows for a RenderSceneBuffer implementation to be made in GDExtension.
+ </brief_description>
+ <description>
+ This class allows for a RenderSceneBuffer implementation to be made in GDExtension.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_configure" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="config" type="RenderSceneBuffersConfiguration" />
+ <description>
+ Implement this in GDExtension to handle the (re)sizing of a viewport.
+ </description>
+ </method>
+ <method name="_set_fsr_sharpness" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="fsr_sharpness" type="float" />
+ <description>
+ Implement this in GDExtension to record a new FSR sharpness value.
+ </description>
+ </method>
+ <method name="_set_texture_mipmap_bias" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="texture_mipmap_bias" type="float" />
+ <description>
+ Implement this in GDExtension to change the texture mipmap bias.
+ </description>
+ </method>
+ <method name="_set_use_debanding" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="use_debanding" type="bool" />
+ <description>
+ Implement this in GDExtension to react to the debanding flag changing.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/RenderSceneBuffersRD.xml b/doc/classes/RenderSceneBuffersRD.xml
new file mode 100644
index 0000000000..80a644ad26
--- /dev/null
+++ b/doc/classes/RenderSceneBuffersRD.xml
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RenderSceneBuffersRD" inherits="RenderSceneBuffers" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Abstract render scene buffer implementation for the RenderingDevice based renderers.
+ </brief_description>
+ <description>
+ This object manages all 3D rendering buffers for the rendering device based renderers. An instance of this object is created for every viewport that has 3D rendering enabled.
+ All buffers are organised in [b]contexts[/b]. The default context is called [b]render_buffers[/b] and can contain amongst others the color buffer, depth buffer, velocity buffers, VRS density map and MSAA variants of these buffers.
+ Buffers are only guaranteed to exist during rendering of the viewport.
+ [b]Note:[/b] this is an internal rendering server object only exposed for GDExtension plugins.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="clear_context">
+ <return type="void" />
+ <param index="0" name="context" type="StringName" />
+ <description>
+ Frees all buffers related to this context.
+ </description>
+ </method>
+ <method name="create_texture">
+ <return type="RID" />
+ <param index="0" name="context" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="data_format" type="int" enum="RenderingDevice.DataFormat" />
+ <param index="3" name="usage_bits" type="int" />
+ <param index="4" name="texture_samples" type="int" enum="RenderingDevice.TextureSamples" />
+ <param index="5" name="size" type="Vector2i" />
+ <param index="6" name="layers" type="int" />
+ <param index="7" name="mipmaps" type="int" />
+ <param index="8" name="unique" type="bool" />
+ <description>
+ Create a new texture with the given definition and cache this under the given name. Will return the existing texture if it already exists.
+ </description>
+ </method>
+ <method name="create_texture_from_format">
+ <return type="RID" />
+ <param index="0" name="context" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="format" type="RDTextureFormat" />
+ <param index="3" name="view" type="RDTextureView" />
+ <param index="4" name="unique" type="bool" />
+ <description>
+ Create a new texture using the given format and view and cache this under the given name. Will return the existing texture if it already exists.
+ </description>
+ </method>
+ <method name="create_texture_view">
+ <return type="RID" />
+ <param index="0" name="context" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="view_name" type="StringName" />
+ <param index="3" name="view" type="RDTextureView" />
+ <description>
+ Create a new texture view for an existing texture and cache this under the given view_name. Will return the existing teture view if it already exists. Will error if the source texture doesn't exist.
+ </description>
+ </method>
+ <method name="get_color_layer">
+ <return type="RID" />
+ <param index="0" name="layer" type="int" />
+ <description>
+ Returns the specified layer from the color texture we are rendering 3D content to.
+ </description>
+ </method>
+ <method name="get_color_texture">
+ <return type="RID" />
+ <description>
+ Returns the color texture we are rendering 3D content to. If multiview is used this will be a texture array with all views.
+ </description>
+ </method>
+ <method name="get_depth_layer">
+ <return type="RID" />
+ <param index="0" name="layer" type="int" />
+ <description>
+ Returns the specified layer from the depth texture we are rendering 3D content to.
+ </description>
+ </method>
+ <method name="get_depth_texture">
+ <return type="RID" />
+ <description>
+ Returns the depth texture we are rendering 3D content to. If multiview is used this will be a texture array with all views.
+ </description>
+ </method>
+ <method name="get_internal_size" qualifiers="const">
+ <return type="Vector2i" />
+ <description>
+ Returns the internal size of the render buffer (size before upscaling) with which textures are created by default.
+ </description>
+ </method>
+ <method name="get_render_target" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Returns the render target associated with this buffers object.
+ </description>
+ </method>
+ <method name="get_texture" qualifiers="const">
+ <return type="RID" />
+ <param index="0" name="context" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <description>
+ Returns a cached texture with this name.
+ </description>
+ </method>
+ <method name="get_texture_format" qualifiers="const">
+ <return type="RDTextureFormat" />
+ <param index="0" name="context" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <description>
+ Returns the texture format information with which a cached texture was created.
+ </description>
+ </method>
+ <method name="get_texture_slice">
+ <return type="RID" />
+ <param index="0" name="context" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="layer" type="int" />
+ <param index="3" name="mipmap" type="int" />
+ <param index="4" name="layers" type="int" />
+ <param index="5" name="mipmaps" type="int" />
+ <description>
+ Returns a specific slice (layer or mipmap) for a cached texture.
+ </description>
+ </method>
+ <method name="get_texture_slice_size">
+ <return type="Vector2i" />
+ <param index="0" name="context" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="mipmap" type="int" />
+ <description>
+ Returns the texture size of a given slice of a cached texture.
+ </description>
+ </method>
+ <method name="get_use_taa" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [b]true[/b] if TAA is enabled.
+ </description>
+ </method>
+ <method name="get_velocity_layer">
+ <return type="RID" />
+ <param index="0" name="layer" type="int" />
+ <description>
+ Returns the specified layer from the velocity texture we are rendering 3D content to.
+ </description>
+ </method>
+ <method name="get_velocity_texture">
+ <return type="RID" />
+ <description>
+ Returns the velocity texture we are rendering 3D content to. If multiview is used this will be a texture array with all views.
+ </description>
+ </method>
+ <method name="get_view_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the view count for the associated viewport.
+ </description>
+ </method>
+ <method name="has_texture" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="context" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <description>
+ Returns [b]true[/b] if a cached texture exists for this name.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index f557dc2fdd..3205a33168 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RenderingDevice" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RenderingDevice" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstraction for working with modern low-level graphics APIs.
</brief_description>
@@ -16,8 +16,8 @@
<methods>
<method name="barrier">
<return type="void" />
- <param index="0" name="from" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
- <param index="1" name="to" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="0" name="from" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
+ <param index="1" name="to" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
<description>
Puts a memory barrier in place. This is used for synchronization to avoid data races. See also [method full_barrier], which may be useful for debugging.
</description>
@@ -27,7 +27,7 @@
<param index="0" name="buffer" type="RID" />
<param index="1" name="offset" type="int" />
<param index="2" name="size_bytes" type="int" />
- <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
<description>
</description>
</method>
@@ -46,7 +46,7 @@
<param index="1" name="offset" type="int" />
<param index="2" name="size_bytes" type="int" />
<param index="3" name="data" type="PackedByteArray" />
- <param index="4" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="4" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
<description>
</description>
</method>
@@ -114,7 +114,7 @@
</method>
<method name="compute_list_end">
<return type="void" />
- <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
<description>
Finishes a list of compute commands created with the [code]compute_*[/code] methods.
</description>
@@ -214,7 +214,7 @@
<param index="0" name="screen" type="int" default="0" />
<param index="1" name="clear_color" type="Color" default="Color(0, 0, 0, 1)" />
<description>
- High-level variant of [method draw_list_begin], with the parameters automtaically being adjusted for drawing onto the window specified by the [param screen] ID.
+ High-level variant of [method draw_list_begin], with the parameters automatically being adjusted for drawing onto the window specified by the [param screen] ID.
[b]Note:[/b] Cannot be used with local RenderingDevices, as these don't have a screen. If called on a local RenderingDevice, [method draw_list_begin_for_screen] returns [constant INVALID_ID].
</description>
</method>
@@ -296,7 +296,7 @@
</method>
<method name="draw_list_end">
<return type="void" />
- <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
<description>
Finishes a list of raster drawing commands created with the [code]draw_*[/code] methods.
</description>
@@ -682,7 +682,7 @@
<param index="3" name="mipmap_count" type="int" />
<param index="4" name="base_layer" type="int" />
<param index="5" name="layer_count" type="int" />
- <param index="6" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="6" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
<description>
Clears the specified [param texture] by replacing all of its pixels with the specified [param color]. [param base_mipmap] and [param mipmap_count] determine which mipmaps of the texture are affected by this clear operation, while [param base_layer] and [param layer_count] determine which layers of a 3D texture (or texture array) are affected by this clear operation. For 2D textures (which only have one layer by design), [param base_layer] and [param layer_count] must both be [code]0[/code].
[b]Note:[/b] [param 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 [constant FINAL_ACTION_CONTINUE]) to clear this texture.
@@ -699,7 +699,7 @@
<param index="6" name="dst_mipmap" type="int" />
<param index="7" name="src_layer" type="int" />
<param index="8" name="dst_layer" type="int" />
- <param index="9" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="9" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
<description>
Copies the [param from_texture] to [param to_texture] with the specified [param from_pos], [param to_pos] and [param size] coordinates. The Z axis of the [param from_pos], [param to_pos] and [param size] must be [code]0[/code] for 2-dimensional textures. Source and destination mipmaps/layers must also be specified, with these parameters being [code]0[/code] for textures without mipmaps or single-layer textures. Returns [constant @GlobalScope.OK] if the texture copy was successful or [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise.
[b]Note:[/b] [param from_texture] 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 [constant FINAL_ACTION_CONTINUE]) to copy this texture.
@@ -752,6 +752,13 @@
[b]Note:[/b] [param texture] requires the [constant TEXTURE_USAGE_CAN_COPY_FROM_BIT] to be retrieved. Otherwise, an error is printed and a empty [PackedByteArray] is returned.
</description>
</method>
+ <method name="texture_get_format">
+ <return type="RDTextureFormat" />
+ <param index="0" name="texture" type="RID" />
+ <description>
+ Returns the data format used to create this texture.
+ </description>
+ </method>
<method name="texture_get_native_handle">
<return type="int" />
<param index="0" name="texture" type="RID" />
@@ -786,7 +793,7 @@
<return type="int" enum="Error" />
<param index="0" name="from_texture" type="RID" />
<param index="1" name="to_texture" type="RID" />
- <param index="2" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="2" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
<description>
Resolves the [param from_texture] texture onto [param to_texture] with multisample antialiasing enabled. This must be used when rendering a framebuffer for MSAA to work. Returns [constant @GlobalScope.OK] if successful, [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise.
[b]Note:[/b] [param from_texture] and [param to_texture] textures must have the same dimension, format and type (color or depth).
@@ -803,7 +810,7 @@
<param index="0" name="texture" type="RID" />
<param index="1" name="layer" type="int" />
<param index="2" name="data" type="PackedByteArray" />
- <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="7" />
+ <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" is_bitfield="true" default="15" />
<description>
Updates texture data with new data, replacing the previous data in place. The updated texture data must have the same dimensions and format. For 2D textures (which only have one layer), [param layer] must be [code]0[/code]. Returns [constant @GlobalScope.OK] if the update was successful, [constant @GlobalScope.ERR_INVALID_PARAMETER] otherwise.
[b]Note:[/b] Updating textures is forbidden during creation of a draw or compute list.
@@ -1580,19 +1587,25 @@
<constant name="DATA_FORMAT_MAX" value="218" enum="DataFormat">
Represents the size of the [enum DataFormat] enum.
</constant>
- <constant name="BARRIER_MASK_RASTER" value="1" enum="BarrierMask" is_bitfield="true">
- Raster barrier mask.
+ <constant name="BARRIER_MASK_VERTEX" value="1" enum="BarrierMask" is_bitfield="true">
+ Vertex shader barrier mask.
+ </constant>
+ <constant name="BARRIER_MASK_FRAGMENT" value="2" enum="BarrierMask" is_bitfield="true">
+ Fragment shader barrier mask.
</constant>
- <constant name="BARRIER_MASK_COMPUTE" value="2" enum="BarrierMask" is_bitfield="true">
+ <constant name="BARRIER_MASK_COMPUTE" value="4" enum="BarrierMask" is_bitfield="true">
Compute barrier mask.
</constant>
- <constant name="BARRIER_MASK_TRANSFER" value="4" enum="BarrierMask" is_bitfield="true">
+ <constant name="BARRIER_MASK_TRANSFER" value="8" enum="BarrierMask" is_bitfield="true">
Transfer barrier mask.
</constant>
- <constant name="BARRIER_MASK_ALL_BARRIERS" value="7" enum="BarrierMask" is_bitfield="true">
+ <constant name="BARRIER_MASK_RASTER" value="3" enum="BarrierMask" is_bitfield="true">
+ Raster barrier mask (vertex and fragment). Equivalent to [code]BARRIER_MASK_VERTEX | BARRIER_MASK_FRAGMENT[/code].
+ </constant>
+ <constant name="BARRIER_MASK_ALL_BARRIERS" value="15" enum="BarrierMask" is_bitfield="true">
Barrier mask for all types (raster, compute, transfer). Equivalent to [code]BARRIER_MASK_RASTER | BARRIER_MASK_COMPUTE | BARRIER_MASK_TRANSFER[/code].
</constant>
- <constant name="BARRIER_MASK_NO_BARRIER" value="8" enum="BarrierMask" is_bitfield="true">
+ <constant name="BARRIER_MASK_NO_BARRIER" value="16" enum="BarrierMask" is_bitfield="true">
No barrier for any type.
</constant>
<constant name="TEXTURE_TYPE_1D" value="0" enum="TextureType">
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 9681b6e512..64d54b3ba0 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RenderingServer" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RenderingServer" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Server for anything visible.
</brief_description>
@@ -3281,6 +3281,13 @@
[b]Note:[/b] The [param texture] must have the same width, height, depth and format as the current texture data. Otherwise, an error will be printed and the original texture won't be modified. If you need to use different width, height, depth or format, use [method texture_replace] instead.
</description>
</method>
+ <method name="texture_get_format" qualifiers="const">
+ <return type="int" enum="Image.Format" />
+ <param index="0" name="texture" type="RID" />
+ <description>
+ Returns the [enum Image.Format] for the texture.
+ </description>
+ </method>
<method name="texture_get_native_handle" qualifiers="const">
<return type="int" />
<param index="0" name="texture" type="RID" />
@@ -3319,6 +3326,14 @@
[i]Deprecated.[/i] ProxyTexture was removed in Godot 4, so this method cannot be used anymore.
</description>
</method>
+ <method name="texture_rd_create">
+ <return type="RID" />
+ <param index="0" name="rd_texture" type="RID" />
+ <param index="1" name="layer_type" type="int" enum="RenderingServer.TextureLayeredType" default="0" />
+ <description>
+ Creates a new texture object based on a texture created directly on the [RenderingDevice]. If the texture contains layers, [param layer_type] is used to define the layer type.
+ </description>
+ </method>
<method name="texture_replace">
<return type="void" />
<param index="0" name="texture" type="RID" />
@@ -4628,6 +4643,8 @@
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS" value="10" enum="ViewportDebugDraw">
Draws the shadow atlas that stores shadows from [DirectionalLight3D]s in the upper left quadrant of the [Viewport].
+ The slice of the camera frustum related to the shadow map cascade is superimposed to visualize coverage. The color of each slice matches the colors used for [constant VIEWPORT_DEBUG_DRAW_PSSM_SPLITS]. When shadow cascades are blended the overlap is taken into account when drawing the frustum slices.
+ The last cascade shows all frustum slices to illustrate the coverage of all slices.
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE" value="11" enum="ViewportDebugDraw">
Draws the estimated scene luminance. This is a 1×1 texture that is generated when autoexposure is enabled to control the scene's exposure.
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index 7d2cb57421..2a2239f660 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Resource" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Resource" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for serializable objects.
</brief_description>
@@ -32,7 +32,7 @@
<method name="emit_changed">
<return type="void" />
<description>
- Emits the [signal changed] signal. This method is called automatically for built-in resources.
+ Emits the [signal changed] signal. This method is called automatically for some built-in resources.
[b]Note:[/b] For custom resources, it's recommended to call this method whenever a meaningful change occurs, such as a modified property. This ensures that custom [Object]s depending on the resource are properly updated.
[codeblock]
var damage:
diff --git a/doc/classes/ResourceFormatLoader.xml b/doc/classes/ResourceFormatLoader.xml
index 466dcf7e2d..61eafb4527 100644
--- a/doc/classes/ResourceFormatLoader.xml
+++ b/doc/classes/ResourceFormatLoader.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceFormatLoader" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ResourceFormatLoader" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Loads a specific resource type from a file.
</brief_description>
diff --git a/doc/classes/ResourceFormatSaver.xml b/doc/classes/ResourceFormatSaver.xml
index 93f1809aa1..ae5a6b57f0 100644
--- a/doc/classes/ResourceFormatSaver.xml
+++ b/doc/classes/ResourceFormatSaver.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceFormatSaver" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ResourceFormatSaver" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Saves a specific resource type to a file.
</brief_description>
diff --git a/doc/classes/ResourceImporter.xml b/doc/classes/ResourceImporter.xml
index bafd6145f3..c34b27913f 100644
--- a/doc/classes/ResourceImporter.xml
+++ b/doc/classes/ResourceImporter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceImporter" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ResourceImporter" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for resource importers.
</brief_description>
diff --git a/doc/classes/ResourceImporterBMFont.xml b/doc/classes/ResourceImporterBMFont.xml
new file mode 100644
index 0000000000..3ec2e4afb7
--- /dev/null
+++ b/doc/classes/ResourceImporterBMFont.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterBMFont" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports a bitmap font in the BMFont ([code].fnt[/code]) format.
+ </brief_description>
+ <description>
+ The BMFont format is a format created by the [url=https://www.angelcode.com/products/bmfont/]BMFont[/url] program. Many BMFont-compatible programs also exist, like [url=https://www.bmglyph.com/]BMGlyph[/url].
+ Compared to [ResourceImporterImageFont], [ResourceImporterBMFont] supports bitmap fonts with varying glyph widths/heights.
+ See also [ResourceImporterDynamicFont].
+ </description>
+ <tutorials>
+ <link title="Bitmap fonts - Using fonts">$DOCS_URL/tutorials/ui/gui_using_fonts.html#bitmap-fonts</link>
+ </tutorials>
+ <members>
+ <member name="compress" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], uses lossless compression for the resulting font.
+ </member>
+ <member name="fallbacks" type="Array" setter="" getter="" default="[]">
+ List of font fallbacks to use if a glyph isn't found in this bitmap font. Fonts at the beginning of the array are attempted first.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterBitMap.xml b/doc/classes/ResourceImporterBitMap.xml
new file mode 100644
index 0000000000..e54947ebb6
--- /dev/null
+++ b/doc/classes/ResourceImporterBitMap.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterBitMap" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports a [BitMap] resource (2D array of boolean values).
+ </brief_description>
+ <description>
+ [BitMap] resources are typically used as click masks in [TextureButton] and [TouchScreenButton].
+ </description>
+ <tutorials>
+ <link title="Importing images">$DOCS_URL/tutorials/assets_pipeline/importing_images.html</link>
+ </tutorials>
+ <members>
+ <member name="create_from" type="int" setter="" getter="" default="0">
+ The data source to use for generating the bitmap.
+ [b]Black &amp; White:[/b] Pixels whose HSV value is greater than the [member threshold] will be considered as "enabled" (bit is [code]true[/code]). If the pixel is lower than or equal to the threshold, it will be considered as "disabled" (bit is [code]false[/code]).
+ [b]Alpha:[/b] Pixels whose alpha value is greater than the [member threshold] will be considered as "enabled" (bit is [code]true[/code]). If the pixel is lower than or equal to the threshold, it will be considered as "disabled" (bit is [code]false[/code]).
+ </member>
+ <member name="threshold" type="float" setter="" getter="" default="0.5">
+ The threshold to use to determine which bits should be considered enabled or disabled. See also [member create_from].
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterCSVTranslation.xml b/doc/classes/ResourceImporterCSVTranslation.xml
new file mode 100644
index 0000000000..e34f90d4ca
--- /dev/null
+++ b/doc/classes/ResourceImporterCSVTranslation.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterCSVTranslation" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports comma-separated values
+ </brief_description>
+ <description>
+ Comma-separated values are a plain text table storage format. The format's simplicity makes it easy to edit in any text editor or spreadsheet software. This makes it a common choice for game localization.
+ [b]Example CSV file:[/b]
+ [codeblock]
+ keys,en,es,ja
+ GREET,"Hello, friend!","Hola, amigo!",こんにちは
+ ASK,How are you?,Cómo está?,元気ですか
+ BYE,Goodbye,Adiós,さようなら
+ QUOTE,"""Hello"" said the man.","""Hola"" dijo el hombre.",「こんにちは」男は言いました
+ [/codeblock]
+ </description>
+ <tutorials>
+ <link title="Importing translations">https://docs.godotengine.org/en/latest/tutorials/assets_pipeline/importing_translations.html</link>
+ </tutorials>
+ <members>
+ <member name="compress" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], creates an [OptimizedTranslation] instead of a [Translation]. This makes the resulting file smaller at the cost of a small CPU overhead.
+ </member>
+ <member name="delimiter" type="int" setter="" getter="" default="0">
+ The delimiter to use in the CSV file. The default value matches the common CSV convention. Tab-separated values are sometimes called TSV files.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterDynamicFont.xml b/doc/classes/ResourceImporterDynamicFont.xml
new file mode 100644
index 0000000000..437b3c8a96
--- /dev/null
+++ b/doc/classes/ResourceImporterDynamicFont.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterDynamicFont" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports a TTF, TTC, OTF, OTC, WOFF or WOFF2 font file for font rendering that adapts to any size.
+ </brief_description>
+ <description>
+ Unlike bitmap fonts, dynamic fonts can be resized to any size and still look crisp. Dynamic fonts also optionally support MSDF font rendering, which allows for run-time scale changes with no re-rasterization cost.
+ While WOFF and especially WOFF2 tend to result in smaller file sizes, there is no universally "better" font format. In most situations, it's recommended to use the font format that was shipped on the font developer's website.
+ See also [ResourceImporterBMFont] and [ResourceImporterImageFont].
+ </description>
+ <tutorials>
+ <link title="Dynamic fonts - Using fonts">$DOCS_URL/tutorials/ui/gui_using_fonts.html#dynamic-fonts</link>
+ </tutorials>
+ <members>
+ <member name="allow_system_fallback" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], automatically use system fonts as a fallback if a glyph isn't found in this dynamic font. This makes supporting CJK characters or emoji more straightforward, as you don't need to include a CJK/emoji font in your project. See also [member fallbacks].
+ [b]Note:[/b] The appearance of system fonts varies across platforms. Loading system fonts is only supported on Windows, macOS, Linux, Android and iOS.
+ </member>
+ <member name="antialiasing" type="int" setter="" getter="" default="1">
+ The font antialiasing method to use.
+ [b]Disabled:[/b] Most suited for pixel art fonts, although you do not [i]have[/i] to change the antialiasing from the default [b]Grayscale[/b] if the font file was well-created and the font is used at an integer multiple of its intended size. If pixel art fonts have a bad appearance at their intended size, try setting [member subpixel_positioning] to [b]Disabled[/b] instead.
+ [b]Grayscale:[/b] Use grayscale antialiasing. This is the approach used by the operating system on macOS, Android and iOS.
+ [b]LCD Subpixel:[/b] Use antialiasing with subpixel patterns to make fonts sharper on LCD displays. This is the approach used by the operating system on Windows and most Linux distributions. The downside is that this can introduce "fringing" on edges, especially on display technologies that don't use standard RGB subpixels (such as OLED displays). The LCD subpixel layout is globally controlled by [member ProjectSettings.gui/theme/lcd_subpixel_layout], which also allows falling back to grayscale antialiasing.
+ </member>
+ <member name="compress" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], uses lossless compression for the resulting font.
+ </member>
+ <member name="fallbacks" type="Array" setter="" getter="" default="[]">
+ List of font fallbacks to use if a glyph isn't found in this dynamic font. Fonts at the beginning of the array are attempted first, but fallback fonts that don't support the glyph's language and script are attempted last (see [member language_support] and [member script_support]). See also [member allow_system_fallback].
+ </member>
+ <member name="force_autohinter" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], forces generation of hinting data for the font using [url=https://freetype.org/]FreeType[/url]'s autohinter. This will make [member hinting] effective with fonts that don't include hinting data.
+ </member>
+ <member name="generate_mipmaps" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], this font will have mipmaps generated. This prevents text from looking grainy when a [Control] is scaled down, or when a [Label3D] is viewed from a long distance (if [member Label3D.texture_filter] is set to a mode that displays mipmaps).
+ Enabling [member generate_mipmaps] increases font generation time and memory usage. Only enable this setting if you actually need it.
+ </member>
+ <member name="hinting" type="int" setter="" getter="" default="1">
+ The hinting mode to use. This controls how aggressively glyph edges should be snapped to pixels when rasterizing the font. Depending on personal preference, you may prefer using one hinting mode over the other. Hinting modes other than [b]None[/b] are only effective if the font contains hinting data (see [member force_autohinter]).
+ [b]None:[/b] Smoothest appearance, which can make the font look blurry at small sizes.
+ [b]Light:[/b] Sharp result by snapping glyph edges to pixels on the Y axis only.
+ [b]Full:[/b] Sharpest by snapping glyph edges to pixels on both X and Y axes.
+ </member>
+ <member name="language_support" type="Dictionary" setter="" getter="" default="{}">
+ Override the list of languages supported by this font. If left empty, this is supplied by the font metadata. There is usually no need to change this. See also [member script_support].
+ </member>
+ <member name="msdf_pixel_range" type="int" setter="" getter="" default="8">
+ The width of the range around the shape between the minimum and maximum representable signed distance. If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline. The default [member msdf_pixel_range] value of [code]8[/code] allows outline sizes up to [code]4[/code] to look correct.
+ </member>
+ <member name="msdf_size" type="int" setter="" getter="" default="48">
+ Source font size used to generate MSDF textures. Higher values allow for more precision, but are slower to render and require more memory. Only increase this value if you notice a visible lack of precision in glyph rendering. Only effective if [member multichannel_signed_distance_field] is [code]true[/code].
+ </member>
+ <member name="multichannel_signed_distance_field" type="bool" setter="" getter="" default="false">
+ If set to [code]true[/code], the default font will use multichannel signed distance field (MSDF) for crisp rendering at any size. Since this approach does not rely on rasterizing the font every time its size changes, this allows for resizing the font in real-time without any performance penalty. Text will also not look grainy for [Control]s that are scaled down (or for [Label3D]s viewed from a long distance).
+ MSDF font rendering can be combined with [member generate_mipmaps] to further improve font rendering quality when scaled down.
+ </member>
+ <member name="opentype_features" type="Dictionary" setter="" getter="" default="{}">
+ The OpenType features to enable, disable or set a value for this font. This can be used to enable optional features provided by the font, such as ligatures or alternative glyphs. The list of supported OpenType features varies on a per-font basis.
+ </member>
+ <member name="oversampling" type="float" setter="" getter="" default="0.0">
+ If set to a value greater than [code]0.0[/code], overrides the oversampling factor for the font. This can be used to render the font at a higher or lower resolution than intended without affecting its physical size. In most cases, this should be left at [code]0.0[/code].
+ </member>
+ <member name="preload" type="Array" setter="" getter="" default="[]">
+ The glyph ranges to prerender. This can avoid stuttering during gameplay when new characters need to be rendered, especially if [member subpixel_positioning] is enabled. The downside of using preloading is that initial project load times will increase, as well as memory usage.
+ </member>
+ <member name="script_support" type="Dictionary" setter="" getter="" default="{}">
+ Override the list of language scripts supported by this font. If left empty, this is supplied by the font metadata. There is usually no need to change this. See also [member language_support].
+ </member>
+ <member name="subpixel_positioning" type="int" setter="" getter="" default="1">
+ Subpixel positioning improves font rendering appearance, especially at smaller font sizes. The downside is that it takes more time to initially render the font, which can cause stuttering during gameplay, especially if used with large font sizes. This should be set to [b]Disabled[/b] for fonts with a pixel art appearance.
+ [b]Disabled:[/b] No subpixel positioning. Lowest quality, fastest rendering.
+ [b]Auto:[/b] Use subpixel positioning at small font sizes (the chosen quality varies depending on font size). Large fonts will not use subpixel positioning. This is a good tradeoff between performance and quality.
+ [b]One Half of a Pixel:[/b] Always perform intermediate subpixel positioning regardless of font size. High quality, slow rendering.
+ [b]One Quarter of a Pixel:[/b] Always perform precise subpixel positioning regardless of font size. Highest quality, slowest rendering.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterImage.xml b/doc/classes/ResourceImporterImage.xml
new file mode 100644
index 0000000000..8fbec8af01
--- /dev/null
+++ b/doc/classes/ResourceImporterImage.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterImage" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports a image for use in scripting, with no rendering capabilities.
+ </brief_description>
+ <description>
+ This importer imports [Image] resources, as opposed to [CompressedTexture2D]. If you need to render the image in 2D or 3D, use [ResourceImporterTexture] instead.
+ </description>
+ <tutorials>
+ <link title="Importing images">$DOCS_URL/tutorials/assets_pipeline/importing_images.html</link>
+ </tutorials>
+</class>
diff --git a/doc/classes/ResourceImporterImageFont.xml b/doc/classes/ResourceImporterImageFont.xml
new file mode 100644
index 0000000000..96598f78df
--- /dev/null
+++ b/doc/classes/ResourceImporterImageFont.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterImageFont" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports a fixed-width bitmap font where all glyphs have the same width and height.
+ </brief_description>
+ <description>
+ This image-based workflow can be easier to use than [ResourceImporterBMFont], but it requires all glyphs to have the same width and height. This makes [ResourceImporterImageFont] most suited to fixed-width fonts.
+ See also [ResourceImporterDynamicFont].
+ </description>
+ <tutorials>
+ <link title="Bitmap fonts - Using fonts">$DOCS_URL/tutorials/ui/gui_using_fonts.html#bitmap-fonts</link>
+ </tutorials>
+ <members>
+ <member name="character_margin" type="Rect2i" setter="" getter="" default="Rect2i(0, 0, 0, 0)">
+ Margin applied around every imported glyph. If your font image contains guides (in the form of lines between glyphs) or if spacing between characters appears incorrect, try adjusting [member character_margin].
+ </member>
+ <member name="character_ranges" type="PackedStringArray" setter="" getter="" default="PackedStringArray()">
+ The character ranges to import from the font image. This is an array that maps each position on the image (in tile coordinates, not pixels). The font atlas is traversed from left to right and top to bottom. Characters can be specified with decimal numbers (127), hexadecimal numbers ([code]0x007f[/code]) or between single quotes ([code]'~'[/code]). Ranges can be specified with a hyphen between characters.
+ For instance, [code]0-127[/code] (or [code]0x0000-0x007f[/code]) denotes the full ASCII range. As another example, [code]' '-'~'[/code] is equivalent to [code]32-127[/code] and denotes the range of printable (visible) ASCII characters.
+ Make sure [member character_ranges] doesn't exceed the number of [member columns] * [member rows] defined. Otherwise, the font will fail to import.
+ </member>
+ <member name="columns" type="int" setter="" getter="" default="1">
+ Number of columns in the font image. See also [member rows].
+ </member>
+ <member name="compress" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], uses lossless compression for the resulting font.
+ </member>
+ <member name="fallbacks" type="Array" setter="" getter="" default="[]">
+ List of font fallbacks to use if a glyph isn't found in this bitmap font. Fonts at the beginning of the array are attempted first.
+ </member>
+ <member name="image_margin" type="Rect2i" setter="" getter="" default="Rect2i(0, 0, 0, 0)">
+ Margin to cut on the sides of the entire image. This can be used to cut parts of the image that contain attribution information or similar.
+ </member>
+ <member name="rows" type="int" setter="" getter="" default="1">
+ Number of rows in the font image. See also [member columns].
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterLayeredTexture.xml b/doc/classes/ResourceImporterLayeredTexture.xml
new file mode 100644
index 0000000000..6d3c868e3d
--- /dev/null
+++ b/doc/classes/ResourceImporterLayeredTexture.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterLayeredTexture" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports a 3-dimensional texture ([Texture3D]), a [Texture2DArray], a [Cubemap] or a [CubemapArray].
+ </brief_description>
+ <description>
+ This imports a 3-dimensional texture, which can then be used in custom shaders, as a [FogMaterial] density map or as a [GPUParticlesAttractorVectorField3D]. See also [ResourceImporterTexture] and [ResourceImporterTextureAtlas].
+ </description>
+ <tutorials>
+ <link title="Importing images">$DOCS_URL/tutorials/assets_pipeline/importing_images.html</link>
+ </tutorials>
+ <members>
+ <member name="compress/channel_pack" type="int" setter="" getter="" default="0">
+ Controls how color channels should be used in the imported texture.
+ [b]sRGB Friendly:[/b], prevents the RG color format from being used, as it does not support sRGB color.
+ [b]Optimized:[/b], allows the RG color format to be used if the texture does not use the blue channel. This reduces memory usage if the texture's blue channel can be discarded (all pixels must have a blue value of [code]0[/code]).
+ [b]Normal Map (RG Channels):[/b] This forces all layers from the texture to be imported with the RG color format to reduce memory usage, with only the red and green channels preserved. This only has an effect on textures with the VRAM Compressed or Basis Universal compression modes. This mode is only available in layered textures ([Cubemap], [CubemapArray], [Texture2DArray] and [Texture3D]).
+ </member>
+ <member name="compress/hdr_compression" type="int" setter="" getter="" default="1">
+ Controls how VRAM compression should be performed for HDR images.
+ [b]Disabled:[/b] Never use VRAM compression for HDR textures, regardless of whether they're opaque or transparent. Instead, the texture is converted to RGBE9995 (9-bits per channel + 5-bit exponent = 32 bits per pixel) to reduce memory usage compared to a half-float or single-precision float image format.
+ [b]Opaque Only:[/b] Only uses VRAM compression for opaque HDR textures. This is due to a limitation of HDR formats, as there is no VRAM-compressed HDR format that supports transparency at the same time.
+ [b]Always:[/b] Force VRAM compression even for HDR textures with an alpha channel. To perform this, the alpha channel is discarded on import.
+ [b]Note:[/b] Only effective on Radiance HDR ([code].hdr[/code]) and OpenEXR ([code].exr[/code]) images.
+ </member>
+ <member name="compress/high_quality" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], uses BPTC compression on desktop platforms and ASTC compression on mobile platforms. When using BPTC, BC7 is used for SDR textures and BC6H is used for HDR textures.
+ If [code]false[/code], uses the faster but lower-quality S3TC compression on desktop platforms and ETC2 on mobile/web platforms. When using S3TC, DXT1 (BC1) is used for opaque textures and DXT5 (BC3) is used for transparent or normal map (RGTC) textures.
+ BPTC and ASTC support VRAM compression for HDR textures, but S3TC and ETC2 do not (see [member compress/hdr_compression]).
+ </member>
+ <member name="compress/lossy_quality" type="float" setter="" getter="" default="0.7">
+ The quality to use when using the [b]Lossy[/b] compression mode. Higher values result in better quality, at the cost of larger file sizes. Lossy quality does not affect memory usage of the imported texture, only its file size on disk.
+ </member>
+ <member name="compress/mode" type="int" setter="" getter="" default="1">
+ The compression mode to use. Each compression mode provides a different tradeoff:
+ [b]Lossless[/b]: Original quality, high memory usage, high size on disk, fast import.
+ [b]Lossy:[/b] Reduced quality, high memory usage, low size on disk, fast import.
+ [b]VRAM Compressed:[/b] Reduced quality, low memory usage, low size on disk, slowest import. Only use for textures in 3D scenes, not for 2D elements.
+ [b]VRAM Uncompressed:[/b] Original quality, high memory usage, highest size on disk, fastest import.
+ [b]Basis Universal:[/b] Reduced quality, low memory usage, lowest size on disk, slow import. Only use for textures in 3D scenes, not for 2D elements.
+ See [url=https://docs.godotengine.org/en/latest/tutorials/assets_pipeline/importing_images.html#compress-mode]Compress mode[/url] in the manual for more details.
+ </member>
+ <member name="mipmaps/generate" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], smaller versions of the texture are generated on import. For example, a 64×64 texture will generate 6 mipmaps (32×32, 16×16, 8×8, 4×4, 2×2, 1×1). This has several benefits:
+ - Textures will not become grainy in the distance (in 3D), or if scaled down due to [Camera2D] zoom or [CanvasItem] scale (in 2D).
+ - Performance will improve if the texture is displayed in the distance, since sampling smaller versions of the original texture is faster and requires less memory bandwidth.
+ The downside of mipmaps is that they increase memory usage by roughly 33% (for [Texture2DArray], [Cubemap] and [CubemapArray]) or 14% (for [Texture3D]).
+ It's recommended to enable mipmaps in 3D. However, in 2D, this should only be enabled if your project visibly benefits from having mipmaps enabled. If the camera never zooms out significantly, there won't be a benefit to enabling mipmaps but memory usage will increase.
+ </member>
+ <member name="mipmaps/limit" type="int" setter="" getter="" default="-1">
+ Unimplemented. This currently has no effect when changed.
+ </member>
+ <member name="slices/arrangement" type="int" setter="" getter="" default="1">
+ Controls how the cubemap's texture is internally laid out. When using high-resolution cubemaps, [b]2×3[/b] and [b]3×2[/b] are less prone to exceeding hardware texture size limits compared to [b]1×6[/b] and [b]6×1[/b].
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterOBJ.xml b/doc/classes/ResourceImporterOBJ.xml
new file mode 100644
index 0000000000..70b57b4d2d
--- /dev/null
+++ b/doc/classes/ResourceImporterOBJ.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterOBJ" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports an OBJ 3D model as a standalone [Mesh] or scene.
+ </brief_description>
+ <description>
+ Unlike [ResourceImporterScene], [ResourceImporterOBJ] will import a single [Mesh] resource by default instead of importing a [PackedScene]. This makes it easier to use the [Mesh] resource in nodes that expect direct [Mesh] resources, such as [GridMap], [GPUParticles3D] or [CPUParticles3D]. Note that it is still possible to save mesh resources from 3D scenes using the [b]Advanced Import Settings[/b] dialog, regardless of the source format.
+ See also [ResourceImporterScene], which is used for more advanced 3D formats such as glTF.
+ </description>
+ <tutorials>
+ <link title="Importing 3D scenes">$DOCS_URL/tutorials/assets_pipeline/importing_scenes.html</link>
+ </tutorials>
+ <members>
+ <member name="generate_tangents" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], generate vertex tangents using [url=http://www.mikktspace.com/]Mikktspace[/url] if the source mesh doesn't have tangent data. When possible, it's recommended to let the 3D modeling software generate tangents on export instead on relying on this option. Tangents are required for correct display of normal and height maps, along with any material/shader features that require tangents.
+ If you don't need material features that require tangents, disabling this can reduce output file size and speed up importing if the source 3D file doesn't contain tangents.
+ </member>
+ <member name="offset_mesh" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)">
+ Offsets the mesh's data by the specified value. This can be used to work around misaligned meshes without having to modify the source file.
+ </member>
+ <member name="optimize_mesh" type="bool" setter="" getter="" default="true">
+ Unused parameter. This currently has no effect.
+ </member>
+ <member name="scale_mesh" type="Vector3" setter="" getter="" default="Vector3(1, 1, 1)">
+ Scales the mesh's data by the specified value. This can be used to work around misscaled meshes without having to modify the source file.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterScene.xml b/doc/classes/ResourceImporterScene.xml
new file mode 100644
index 0000000000..b7d42b5a09
--- /dev/null
+++ b/doc/classes/ResourceImporterScene.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterScene" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports a glTF, FBX, Collada or Blender 3D scene.
+ </brief_description>
+ <description>
+ See also [ResourceImporterOBJ], which is used for OBJ models that can be imported as a standalone [Mesh] or a scene.
+ Additional options (such as extracting individual meshes or materials to files) are available in the [b]Advanced Import Settings[/b] dialog. This dialog can be accessed by double-clicking a 3D scene in the FileSystem dock or by selecting a 3D scene in the FileSystem dock, going to the Import dock and choosing [b]Advanced[/b].
+ [b]Note:[/b] [ResourceImporterScene] is [i]not[/i] used for [PackedScene]s, such as [code].tscn[/code] and [code].scn[/code] files.
+ </description>
+ <tutorials>
+ <link title="Importing 3D scenes">$DOCS_URL/tutorials/assets_pipeline/importing_scenes.html</link>
+ </tutorials>
+ <members>
+ <member name="_subresources" type="Dictionary" setter="" getter="" default="{}">
+ Contains properties for the scene's subresources. This is an internal option which is not visible in the Import dock.
+ </member>
+ <member name="animation/fps" type="float" setter="" getter="" default="30">
+ The number of frames per second to use for baking animation curves to a series of points with linear interpolation. It's recommended to configure this value to match the value you're using as a baseline in your 3D modeling software. Higher values result in more precise animation with fast movement changes, at the cost of higher file sizes and memory usage. Thanks to interpolation, there is usually not much benefit in going above 30 FPS (as the animation will still appear smooth at higher rendering framerates).
+ </member>
+ <member name="animation/import" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], import animations from the 3D scene.
+ </member>
+ <member name="animation/remove_immutable_tracks" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], remove animation tracks that only contain default values. This can reduce output file size and memory usage with certain 3D scenes, depending on the contents of their animation tracks.
+ </member>
+ <member name="animation/trimming" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], trim the beginning and end of animations if there are no keyframe changes. This can reduce output file size and memory usage with certain 3D scenes, depending on the contents of their animation tracks.
+ </member>
+ <member name="import_script/path" type="String" setter="" getter="" default="&quot;&quot;">
+ Path to an import script, which can run code after the import process has completed for custom processing. See [url=$DOCS_URL/tutorials/assets_pipeline/importing_scenes.html#doc-importing-3d-scenes-import-script]Using import scripts for automation[/url] for more information.
+ </member>
+ <member name="meshes/create_shadow_meshes" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], enables the generation of shadow meshes on import. This optimizes shadow rendering without reducing quality by welding vertices together when possible. This in turn reduces the memory bandwidth required to render shadows. Shadow mesh generation currently doesn't support using a lower detail level than the source mesh (but shadow rendering will make use of LODs when relevant).
+ </member>
+ <member name="meshes/ensure_tangents" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], generate vertex tangents using [url=http://www.mikktspace.com/]Mikktspace[/url] if the input meshes don't have tangent data. When possible, it's recommended to let the 3D modeling software generate tangents on export instead on relying on this option. Tangents are required for correct display of normal and height maps, along with any material/shader features that require tangents.
+ If you don't need material features that require tangents, disabling this can reduce output file size and speed up importing if the source 3D file doesn't contain tangents.
+ </member>
+ <member name="meshes/generate_lods" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], generates lower detail variants of the mesh which will be displayed in the distance to improve rendering performance. Not all meshes benefit from LOD, especially if they are never rendered from far away. Disabling this can reduce output file size and speed up importing. See [url=$DOCS_URL/tutorials/3d/mesh_lod.html#doc-mesh-lod]Mesh level of detail (LOD)[/url] for more information.
+ </member>
+ <member name="meshes/light_baking" type="int" setter="" getter="" default="1">
+ Configures the meshes' [member GeometryInstance3D.gi_mode] in the 3D scene. If set to [b]Static Lightmaps[/b], sets the meshes' GI mode to Static and generates UV2 on import for [LightmapGI] baking.
+ </member>
+ <member name="meshes/lightmap_texel_size" type="float" setter="" getter="" default="0.2">
+ Controls the size of each texel on the baked lightmap. A smaller value results in more precise lightmaps, at the cost of larger lightmap sizes and longer bake times.
+ [b]Note:[/b] Only effective if [member meshes/light_baking] is set to [b]Static Lightmaps[/b].
+ </member>
+ <member name="nodes/apply_root_scale" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], [member nodes/root_scale] will be applied on the meshes and animations directly, while keeping the root node's scale to the default [code](1, 1, 1)[/code]. This means that if you add a child node later on within the imported scene, it won't be scaled. If disabled, [member nodes/root_scale] will multiply the scale of the root node instead.
+ </member>
+ <member name="nodes/root_name" type="String" setter="" getter="" default="&quot;Scene Root&quot;">
+ The name of the root node in the imported scene. This is generally not noticeable when instancing the scene in the editor (or drag-and-dropping from the FileSystem dock), as the root node is renamed to match the filename in this case.
+ </member>
+ <member name="nodes/root_scale" type="float" setter="" getter="" default="1.0">
+ The scale of meshes and animations (if [member nodes/apply_root_scale] is [code]true[/code]), or the scale of the root node in the imported scene (if [member nodes/apply_root_scale] is [code]false[/code]).
+ </member>
+ <member name="nodes/root_type" type="String" setter="" getter="" default="&quot;Node3D&quot;">
+ The node type to use as a root node. Using node types that inherit from [Node3D] is recommended. Otherwise, you'll lose the ability to position the node directly in the 3D editor.
+ </member>
+ <member name="skins/use_named_skins" type="bool" setter="" getter="" default="true">
+ If checked, use named [Skin]s for animation. The [MeshInstance3D] node contains 3 properties of relevance here: a skeleton [NodePath] pointing to the [Skeleton3D] node (usually [code]..[/code]), a mesh, and a skin:
+ - The [Skeleton3D] node contains a list of bones with names, their pose and rest, a name and a parent bone.
+ - The mesh is all of the raw vertex data needed to display a mesh. In terms of the mesh, it knows how vertices are weight-painted and uses some internal numbering often imported from 3D modeling software.
+ - The skin contains the information necessary to bind this mesh onto this Skeleton3D. For every one of the internal bone IDs chosen by the 3D modeling software, it contains two things. Firstly, a matrix known as the Bind Pose Matrix, Inverse Bind Matrix, or IBM for short. Secondly, the [Skin] contains each bone's name (if [member skins/use_named_skins] is [code]true[/code]), or the bone's index within the [Skeleton3D] list (if [member skins/use_named_skins] is [code]false[/code]).
+ Together, this information is enough to tell Godot how to use the bone poses in the [Skeleton3D] node to render the mesh from each [MeshInstance3D]. Note that each [MeshInstance3D] may share binds, as is common in models exported from Blender, or each [MeshInstance3D] may use a separate [Skin] object, as is common in models exported from other tools such as Maya.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterShaderFile.xml b/doc/classes/ResourceImporterShaderFile.xml
new file mode 100644
index 0000000000..85863758d8
--- /dev/null
+++ b/doc/classes/ResourceImporterShaderFile.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterShaderFile" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports native GLSL shaders (not Godot shaders) as a [RDShaderFile].
+ </brief_description>
+ <description>
+ This imports native GLSL shaders as [RDShaderFile] resources, for use with low-level [RenderingDevice] operations. This importer does [i]not[/i] handle [code].gdshader[/code] files.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/ResourceImporterTexture.xml b/doc/classes/ResourceImporterTexture.xml
new file mode 100644
index 0000000000..b81ebf383a
--- /dev/null
+++ b/doc/classes/ResourceImporterTexture.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterTexture" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports an image for use in 2D or 3D rendering.
+ </brief_description>
+ <description>
+ This importer imports [CompressedTexture2D] resources. If you need to process the image in scripts in a more convenient way, use [ResourceImporterImage] instead. See also [ResourceImporterLayeredTexture].
+ </description>
+ <tutorials>
+ <link title="Importing images">$DOCS_URL/tutorials/assets_pipeline/importing_images.html</link>
+ </tutorials>
+ <members>
+ <member name="compress/channel_pack" type="int" setter="" getter="" default="0">
+ Controls how color channels should be used in the imported texture.
+ [b]sRGB Friendly:[/b] Prevents the RG color format from being used, as it does not support sRGB color.
+ [b]Optimized:[/b] Allows the RG color format to be used if the texture does not use the blue channel. This reduces memory usage if the texture's blue channel can be discarded (all pixels must have a blue value of [code]0[/code]).
+ </member>
+ <member name="compress/hdr_compression" type="int" setter="" getter="" default="1">
+ Controls how VRAM compression should be performed for HDR images.
+ [b]Disabled:[/b] Never use VRAM compression for HDR textures, regardless of whether they're opaque or transparent. Instead, the texture is converted to RGBE9995 (9-bits per channel + 5-bit exponent = 32 bits per pixel) to reduce memory usage compared to a half-float or single-precision float image format.
+ [b]Opaque Only:[/b] Only uses VRAM compression for opaque HDR textures. This is due to a limitation of HDR formats, as there is no VRAM-compressed HDR format that supports transparency at the same time.
+ [b]Always:[/b] Force VRAM compression even for HDR textures with an alpha channel. To perform this, the alpha channel is discarded on import.
+ [b]Note:[/b] Only effective on Radiance HDR ([code].hdr[/code]) and OpenEXR ([code].exr[/code]) images.
+ </member>
+ <member name="compress/high_quality" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], uses BPTC compression on desktop platforms and ASTC compression on mobile platforms. When using BPTC, BC7 is used for SDR textures and BC6H is used for HDR textures.
+ If [code]false[/code], uses the faster but lower-quality S3TC compression on desktop platforms and ETC2 on mobile/web platforms. When using S3TC, DXT1 (BC1) is used for opaque textures and DXT5 (BC3) is used for transparent or normal map (RGTC) textures.
+ BPTC and ASTC support VRAM compression for HDR textures, but S3TC and ETC2 do not (see [member compress/hdr_compression]).
+ </member>
+ <member name="compress/lossy_quality" type="float" setter="" getter="" default="0.7">
+ The quality to use when using the [b]Lossy[/b] compression mode. Higher values result in better quality, at the cost of larger file sizes. Lossy quality does not affect memory usage of the imported texture, only its file size on disk.
+ </member>
+ <member name="compress/mode" type="int" setter="" getter="" default="0">
+ The compression mode to use. Each compression mode provides a different tradeoff:
+ [b]Lossless[/b]: Original quality, high memory usage, high size on disk, fast import.
+ [b]Lossy:[/b] Reduced quality, high memory usage, low size on disk, fast import.
+ [b]VRAM Compressed:[/b] Reduced quality, low memory usage, low size on disk, slowest import. Only use for textures in 3D scenes, not for 2D elements.
+ [b]VRAM Uncompressed:[/b] Original quality, high memory usage, highest size on disk, fastest import.
+ [b]Basis Universal:[/b] Reduced quality, low memory usage, lowest size on disk, slow import. Only use for textures in 3D scenes, not for 2D elements.
+ See [url=https://docs.godotengine.org/en/latest/tutorials/assets_pipeline/importing_images.html#compress-mode]Compress mode[/url] in the manual for more details.
+ </member>
+ <member name="compress/normal_map" type="int" setter="" getter="" default="0">
+ When using a texture as normal map, only the red and green channels are required. Given regular texture compression algorithms produce artifacts that don't look that nice in normal maps, the RGTC compression format is the best fit for this data. Forcing this option to Enable will make Godot import the image as RGTC compressed. By default, it's set to Detect. This means that if the texture is ever detected to be used as a normal map, it will be changed to Enable and reimported automatically.
+ Note that RGTC compression affects the resulting normal map image. You will have to adjust custom shaders that use the normal map's blue channel to take this into account. Built-in material shaders already ignore the blue channel in a normal map (regardless of the actual normal map's contents).
+ </member>
+ <member name="detect_3d/compress_to" type="int" setter="" getter="" default="1">
+ This changes the [member compress/mode] option that is used when a texture is detected as being used in 3D.
+ Changing this import option only has an effect if a texture is detected as being used in 3D. Changing this to [b]Disabled[/b] then reimporting will not change the existing compress mode on a texture (if it's detected to be used in 3D), but choosing [b]VRAM Compressed[/b] or [b]Basis Universal[/b] will.
+ </member>
+ <member name="editor/convert_colors_with_editor_theme" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], converts the imported image's colors to match [member EditorSettings.interface/theme/icon_and_font_color]. This assumes the image uses the exact same colors as [url=$DOCS_URL/contributing/development/editor/creating_icons.html]Godot's own color palette for editor icons[/url], with the source file designed for a dark editor theme. This should be enabled for editor plugin icons and custom class icons, but should be left disabled otherwise.
+ [b]Note:[/b] Only available for SVG images.
+ </member>
+ <member name="editor/scale_with_editor_scale" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], scales the imported image to match [member EditorSettings.interface/editor/custom_display_scale]. This should be enabled for editor plugin icons and custom class icons, but should be left disabled otherwise.
+ [b]Note:[/b] Only available for SVG images.
+ </member>
+ <member name="mipmaps/generate" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], smaller versions of the texture are generated on import. For example, a 64×64 texture will generate 6 mipmaps (32×32, 16×16, 8×8, 4×4, 2×2, 1×1). This has several benefits:
+ - Textures will not become grainy in the distance (in 3D), or if scaled down due to [Camera2D] zoom or [CanvasItem] scale (in 2D).
+ - Performance will improve if the texture is displayed in the distance, since sampling smaller versions of the original texture is faster and requires less memory bandwidth.
+ The downside of mipmaps is that they increase memory usage by roughly 33%.
+ It's recommended to enable mipmaps in 3D. However, in 2D, this should only be enabled if your project visibly benefits from having mipmaps enabled. If the camera never zooms out significantly, there won't be a benefit to enabling mipmaps but memory usage will increase.
+ </member>
+ <member name="mipmaps/limit" type="int" setter="" getter="" default="-1">
+ Unimplemented. This currently has no effect when changed.
+ </member>
+ <member name="process/fix_alpha_border" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], puts pixels of the same surrounding color in transition from transparent to opaque areas. For textures displayed with bilinear filtering, this helps mitigate the outline effect when exporting images from an image editor.
+ It's recommended to leave this enabled (as it is by default), unless this causes issues for a particular image.
+ </member>
+ <member name="process/hdr_as_srgb" type="bool" setter="" getter="" default="false">
+ Some HDR images you can find online may be broken and contain sRGB color data (instead of linear color data). It is advised not to use those files. If you absolutely have to, enabling [member process/hdr_as_srgb] will make them look correct.
+ [b]Warning:[/b] Enabling [member process/hdr_as_srgb] on well-formatted HDR images will cause the resulting image to look too dark, so leave this on [code]false[/code] if unsure.
+ </member>
+ <member name="process/hdr_clamp_exposure" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], clamps exposure in the imported high dynamic range images using a smart clamping formula (without introducing [i]visible[/i] clipping).
+ Some HDR panorama images you can find online may contain extremely bright pixels, due to being taken from real life sources without any clipping.
+ While these HDR panorama images are accurate to real life, this can cause the radiance map generated by Godot to contain sparkles when used as a background sky. This can be seen in material reflections (even on rough materials in extreme cases). Enabling [member process/hdr_clamp_exposure] can resolve this.
+ </member>
+ <member name="process/normal_map_invert_y" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], convert the normal map from Y- (DirectX-style) to Y+ (OpenGL-style) by inverting its green color channel. This is the normal map convention expected by Godot.
+ More information about normal maps (including a coordinate order table for popular engines) can be found [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details]here[/url].
+ </member>
+ <member name="process/premult_alpha" type="bool" setter="" getter="" default="false">
+ An alternative to fixing darkened borders with [member process/fix_alpha_border] is to use premultiplied alpha. By enabling this option, the texture will be converted to this format. A premultiplied alpha texture requires specific materials to be displayed correctly:
+ - In 2D, a [CanvasItemMaterial] will need to be created and configured to use the [constant CanvasItemMaterial.BLEND_MODE_PREMULT_ALPHA] blend mode on [CanvasItem]s that use this texture.
+ - In 3D, there is no support for premultiplied alpha blend mode yet, so this option is only suited for 2D.
+ </member>
+ <member name="process/size_limit" type="int" setter="" getter="" default="0">
+ If set to a value greater than [code]0[/code], the size of the texture is limited on import to a value smaller than or equal to the value specified here. For non-square textures, the size limit affects the longer dimension, with the shorter dimension scaled to preserve aspect ratio. Resizing is performed using cubic interpolation.
+ This can be used to reduce memory usage without affecting the source images, or avoid issues with textures not displaying on mobile/web platforms (as these usually can't display textures larger than 4096×4096).
+ </member>
+ <member name="roughness/mode" type="int" setter="" getter="" default="0">
+ The color channel to consider as a roughness map in this texture. Only effective if Roughness &gt; Src Normal is not empty.
+ </member>
+ <member name="roughness/src_normal" type="String" setter="" getter="" default="&quot;&quot;">
+ The path to the texture to consider as a normal map for roughness filtering on import. Specifying this can help decrease specular aliasing slightly in 3D.
+ Roughness filtering on import is only used in 3D rendering, not 2D.
+ </member>
+ <member name="svg/scale" type="float" setter="" getter="" default="1.0">
+ The scale the SVG should be rendered at, with [code]1.0[/code] being the original design size. Higher values result in a larger image. Note that unlike font oversampling, this affects the size the SVG is rendered at in 2D. See also [member editor/scale_with_editor_scale].
+ [b]Note:[/b] Only available for SVG images.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterTextureAtlas.xml b/doc/classes/ResourceImporterTextureAtlas.xml
new file mode 100644
index 0000000000..9f3f642869
--- /dev/null
+++ b/doc/classes/ResourceImporterTextureAtlas.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterTextureAtlas" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports a collection of textures from a PNG image into an optimized [AtlasTexture] for 2D rendering.
+ </brief_description>
+ <description>
+ This imports a collection of textures from a PNG image into an [AtlasTexture] or 2D [ArrayMesh]. This can be used to save memory when importing 2D animations from spritesheets. Texture atlases are only supported in 2D rendering, not 3D. See also [ResourceImporterTexture] and [ResourceImporterLayeredTexture].
+ [b]Note:[/b] [ResourceImporterTextureAtlas] does not handle importing [TileSetAtlasSource], which is created using the [TileSet] editor instead.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="atlas_file" type="String" setter="" getter="" default="&quot;&quot;">
+ Path to the atlas spritesheet. This [i]must[/i] be set to valid path to a PNG image. Otherwise, the atlas will fail to import.
+ </member>
+ <member name="crop_to_region" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], discards empty areas from the atlas. This only affects final sprite positioning, not storage. See also [member trim_alpha_border_from_region].
+ [b]Note:[/b] Only effective if [member import_mode] is [b]Region[/b].
+ </member>
+ <member name="import_mode" type="int" setter="" getter="" default="0">
+ [b]Region:[/b] Imports the atlas in an [AtlasTexture] resource, which is rendered as a rectangle. This is fast to render, but transparent areas still have to be rendered if they can't be trimmed effectively by [member trim_alpha_border_from_region]. This can reduce performance when rendering large sprites on screen.
+ [b]Mesh:[/b] Imports the atlas as an [ArrayMesh] resource, keeping the original bitmap visible (but rendered as a polygon). This can be used to reduce fill rate when rendering large transparent sprites, at the cost of slower rendering if there are little to no transparent areas in the sprite.
+ </member>
+ <member name="trim_alpha_border_from_region" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], trims the region to exclude fully transparent pixels using a clipping rectangle (which is never rotated). This can be used to save memory. See also [member trim_alpha_border_from_region].
+ [b]Note:[/b] Only effective if [member import_mode] is [b]Region[/b].
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceImporterWAV.xml b/doc/classes/ResourceImporterWAV.xml
new file mode 100644
index 0000000000..5336c98d0f
--- /dev/null
+++ b/doc/classes/ResourceImporterWAV.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterWAV" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Imports a WAV audio file for playback.
+ </brief_description>
+ <description>
+ WAV is an uncompressed format, which can provide higher quality compared to Ogg Vorbis and MP3. It also has the lowest CPU cost to decode. This means high numbers of WAV sounds can be played at the same time, even on low-end deviceS.
+ </description>
+ <tutorials>
+ <link title="Importing audio samples">$DOCS_URL/tutorials/assets_pipeline/importing_audio_samples.html</link>
+ </tutorials>
+ <members>
+ <member name="compress/mode" type="int" setter="" getter="" default="0">
+ The compression mode to use on import.
+ [b]Disabled:[/b] Imports audio data without any compression. This results in the highest possible quality.
+ [b]RAM (Ima-ADPCM):[/b] Performs fast lossy compression on import. Low CPU cost, but quality is noticeably decreased compared to Ogg Vorbis or even MP3.
+ </member>
+ <member name="edit/loop_begin" type="int" setter="" getter="" default="0">
+ The begin loop point to use when [member edit/loop_mode] is [b]Forward[/b], [b]Ping-Pong[/b] or [b]Backward[/b]. This is set in seconds after the beginning of the audio file.
+ </member>
+ <member name="edit/loop_end" type="int" setter="" getter="" default="-1">
+ The end loop point to use when [member edit/loop_mode] is [b]Forward[/b], [b]Ping-Pong[/b] or [b]Backward[/b]. This is set in seconds after the beginning of the audio file. A value of [code]-1[/code] uses the end of the audio file as the end loop point.
+ </member>
+ <member name="edit/loop_mode" type="int" setter="" getter="" default="0">
+ Controls how audio should loop. This is automatically read from the WAV metadata on import.
+ [b]Disabled:[/b] Don't loop audio, even if metadata indicates the file should be played back looping.
+ [b]Forward:[/b] Standard audio looping.
+ [b]Ping-Pong:[/b] Play audio forward until it's done playing, then play it backward and repeat. This is similar to mirrored texture repeat, but for audio.
+ [b]Backward:[/b] Play audio in reverse and loop back to the end when done playing.
+ [b]Note:[/b] In [AudioStreamPlayer], the [signal AudioStreamPlayer.finished] signal won't be emitted for looping audio when it reaches the end of the audio file, as the audio will keep playing indefinitely.
+ </member>
+ <member name="edit/normalize" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], normalize the audio volume so that its peak volume is equal to 0 dB. When enabled, normalization will make audio sound louder depending on its original peak volume.
+ </member>
+ <member name="edit/trim" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], automatically trim the beginning and end of the audio if it's lower than -50 dB after normalization (see [member edit/normalize]). This prevents having files with silence at the beginning or end, which increases their size unnecessarily and adds latency to the moment they are played back. A fade-in/fade-out period of 500 samples is also used during trimming to avoid audible pops.
+ </member>
+ <member name="force/8_bit" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], forces the imported audio to use 8-bit quantization if the source file is 16-bit or higher.
+ Enabling this is generally not recommended, as 8-bit quantization decreases audio quality significantly. If you need smaller file sizes, consider using Ogg Vorbis or MP3 audio instead.
+ </member>
+ <member name="force/max_rate" type="bool" setter="" getter="" default="false">
+ If set to a value greater than [code]0[/code], forces the audio's sample rate to be reduced to a value lower than or equal to the value specified in [member force/max_rate_hz].
+ This can decrease file size noticeably on certain sounds, without impacting quality depending on the actual sound's contents. See [url=$DOCS_URL/tutorials/assets_pipeline/importing_audio_samples.html#doc-importing-audio-samples-best-practices]Best practices[/url] for more information.
+ </member>
+ <member name="force/max_rate_hz" type="float" setter="" getter="" default="44100">
+ The frequency to limit the imported audio sample to (in Hz). Only effective if [member force/max_rate] is [code]true[/code].
+ </member>
+ <member name="force/mono" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], forces the imported audio to be mono if the source file is stereo. This decreases the file size by 50% by merging the two channels into one.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml
index cf52f5017c..267594edcb 100644
--- a/doc/classes/ResourceLoader.xml
+++ b/doc/classes/ResourceLoader.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceLoader" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ResourceLoader" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton for loading resource files.
</brief_description>
@@ -35,6 +35,12 @@
<param index="0" name="path" type="String" />
<description>
Returns the dependencies for the resource at the given [param path].
+ [b]Note:[/b] The dependencies are returned with slices separated by [code]::[/code]. You can use [method String.get_slice] to get their components.
+ [codeblock]
+ for dep in ResourceLoader.get_dependencies(path):
+ print(dep.get_slice("::", 0)) # Prints UID.
+ print(dep.get_slice("::", 2)) # Prints path.
+ [/codeblock]
</description>
</method>
<method name="get_recognized_extensions_for_type">
diff --git a/doc/classes/ResourcePreloader.xml b/doc/classes/ResourcePreloader.xml
index 16b2c13b47..2d4dcf09af 100644
--- a/doc/classes/ResourcePreloader.xml
+++ b/doc/classes/ResourcePreloader.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourcePreloader" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ResourcePreloader" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node used to preload sub-resources inside a scene.
</brief_description>
diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml
index 9d19d81f05..7b90781fc5 100644
--- a/doc/classes/ResourceSaver.xml
+++ b/doc/classes/ResourceSaver.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceSaver" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ResourceSaver" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton for saving [Resource]s to the filesystem.
</brief_description>
diff --git a/doc/classes/ResourceUID.xml b/doc/classes/ResourceUID.xml
index e3e18512ac..8b990b132a 100644
--- a/doc/classes/ResourceUID.xml
+++ b/doc/classes/ResourceUID.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceUID" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ResourceUID" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton that manages the unique identifiers of all resources within a project.
</brief_description>
diff --git a/doc/classes/RibbonTrailMesh.xml b/doc/classes/RibbonTrailMesh.xml
index c049570310..74523f3c39 100644
--- a/doc/classes/RibbonTrailMesh.xml
+++ b/doc/classes/RibbonTrailMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RibbonTrailMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RibbonTrailMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a straight ribbon-shaped [PrimitiveMesh] with variable width.
</brief_description>
diff --git a/doc/classes/RichTextEffect.xml b/doc/classes/RichTextEffect.xml
index 7d91987e7f..0f429c31fa 100644
--- a/doc/classes/RichTextEffect.xml
+++ b/doc/classes/RichTextEffect.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RichTextEffect" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RichTextEffect" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A custom effect for a [RichTextLabel].
</brief_description>
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index 6fbdb4faad..e2030f5927 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RichTextLabel" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RichTextLabel" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control for displaying text that can contain different font styles, images, and basic formatting.
</brief_description>
@@ -266,6 +266,18 @@
Terminates the current tag. Use after [code]push_*[/code] methods to close BBCodes manually. Does not need to follow [code]add_*[/code] methods.
</description>
</method>
+ <method name="pop_all">
+ <return type="void" />
+ <description>
+ Terminates all tags opened by [code]push_*[/code] methods.
+ </description>
+ </method>
+ <method name="pop_context">
+ <return type="void" />
+ <description>
+ Terminates tags opened after the last [method push_context] call (including context marker), or all tags if there's no context marker on the stack.
+ </description>
+ </method>
<method name="push_bgcolor">
<return type="void" />
<param index="0" name="bgcolor" type="Color" />
@@ -298,6 +310,12 @@
Adds a [code][color][/code] tag to the tag stack.
</description>
</method>
+ <method name="push_context">
+ <return type="void" />
+ <description>
+ Adds a context marker to the tag stack. See [method pop_context].
+ </description>
+ </method>
<method name="push_customfx">
<return type="void" />
<param index="0" name="effect" type="RichTextEffect" />
@@ -329,9 +347,10 @@
<method name="push_font">
<return type="void" />
<param index="0" name="font" type="Font" />
- <param index="1" name="font_size" type="int" />
+ <param index="1" name="font_size" type="int" default="0" />
<description>
Adds a [code][font][/code] tag to the tag stack. Overrides default fonts for its duration.
+ Passing [code]0[/code] to [param font_size] will use the existing default font size.
</description>
</method>
<method name="push_font_size">
@@ -506,7 +525,7 @@
<return type="void" />
<param index="0" name="column" type="int" />
<param index="1" name="expand" type="bool" />
- <param index="2" name="ratio" type="int" />
+ <param index="2" name="ratio" type="int" default="1" />
<description>
Edits the selected column's expansion options. If [param expand] is [code]true[/code], the column expands in proportion to its expansion ratio versus the other columns' ratios.
For example, 2 columns with ratios 3 and 4 plus 70 pixels in available width would expand 30 and 40 pixels, respectively.
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index d9f0229359..269ead1298 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RigidBody2D" inherits="PhysicsBody2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RigidBody2D" inherits="PhysicsBody2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D physics body that is moved by a physics simulation.
</brief_description>
@@ -151,7 +151,7 @@
See [method add_constant_torque].
</member>
<member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false">
- If [code]true[/code], the RigidBody2D will emit signals when it collides with another RigidBody2D.
+ If [code]true[/code], the RigidBody2D will emit signals when it collides with another body.
[b]Note:[/b] By default the maximum contacts reported is set to 0, meaning nothing will be recorded, see [member max_contacts_reported].
</member>
<member name="continuous_cd" type="int" setter="set_continuous_collision_detection_mode" getter="get_continuous_collision_detection_mode" enum="RigidBody2D.CCDMode" default="0">
diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml
index ee0648cd8b..69cfd2bb07 100644
--- a/doc/classes/RigidBody3D.xml
+++ b/doc/classes/RigidBody3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RigidBody3D" inherits="PhysicsBody3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RigidBody3D" inherits="PhysicsBody3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D physics body that is moved by a physics simulation.
</brief_description>
@@ -158,7 +158,7 @@
See [method add_constant_torque].
</member>
<member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false">
- If [code]true[/code], the RigidBody3D will emit signals when it collides with another RigidBody3D.
+ If [code]true[/code], the RigidBody3D will emit signals when it collides with another body.
[b]Note:[/b] By default the maximum contacts reported is set to 0, meaning nothing will be recorded, see [member max_contacts_reported].
</member>
<member name="continuous_cd" type="bool" setter="set_use_continuous_collision_detection" getter="is_using_continuous_collision_detection" default="false">
diff --git a/doc/classes/RootMotionView.xml b/doc/classes/RootMotionView.xml
index 677c99c112..20485ed08f 100644
--- a/doc/classes/RootMotionView.xml
+++ b/doc/classes/RootMotionView.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RootMotionView" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RootMotionView" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Editor-only helper for setting up root motion in [AnimationTree].
</brief_description>
diff --git a/doc/classes/SceneState.xml b/doc/classes/SceneState.xml
index 52586be162..b7c8931af4 100644
--- a/doc/classes/SceneState.xml
+++ b/doc/classes/SceneState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SceneState" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SceneState" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides access to a scene file's information.
</brief_description>
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 7b8eca2229..c0d98ef921 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SceneTree" inherits="MainLoop" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SceneTree" inherits="MainLoop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Manages the game loop via a hierarchy of nodes.
</brief_description>
@@ -42,7 +42,7 @@
<description>
Changes the running scene to the one at the given [param path], after loading it into a [PackedScene] and creating a new instance.
Returns [constant OK] on success, [constant ERR_CANT_OPEN] if the [param path] cannot be loaded into a [PackedScene], or [constant ERR_CANT_CREATE] if that scene cannot be instantiated.
- [b]Note:[/b] The scene change is deferred, which means that the new scene node is added to the tree at the end of the frame. This ensures that both scenes aren't running at the same time, while still freeing the previous scene in a safe way similar to [method Node.queue_free]. As such, you won't be able to access the loaded scene immediately after the [method change_scene_to_file] call.
+ [b]Note:[/b] The new scene node is added to the tree at the end of the frame. This ensures that both scenes aren't running at the same time, while still freeing the previous scene in a safe way similar to [method Node.queue_free]. As such, you won't be able to access the loaded scene immediately after the [method change_scene_to_file] call.
</description>
</method>
<method name="change_scene_to_packed">
@@ -51,7 +51,7 @@
<description>
Changes the running scene to a new instance of the given [PackedScene] (which must be valid).
Returns [constant OK] on success, [constant ERR_CANT_CREATE] if the scene cannot be instantiated, or [constant ERR_INVALID_PARAMETER] if the scene is invalid.
- [b]Note:[/b] The scene change is deferred, which means that the new scene node is added to the tree at the end of the frame. You won't be able to access it immediately after the [method change_scene_to_packed] call.
+ [b]Note:[/b] The new scene node is added to the tree at the end of the frame. You won't be able to access it immediately after the [method change_scene_to_packed] call.
</description>
</method>
<method name="create_timer">
diff --git a/doc/classes/SceneTreeTimer.xml b/doc/classes/SceneTreeTimer.xml
index f97c262261..b4b7d646d9 100644
--- a/doc/classes/SceneTreeTimer.xml
+++ b/doc/classes/SceneTreeTimer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SceneTreeTimer" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SceneTreeTimer" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
One-shot timer.
</brief_description>
diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml
index d677bee53b..054399f989 100644
--- a/doc/classes/Script.xml
+++ b/doc/classes/Script.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Script" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Script" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A class stored as a resource.
</brief_description>
diff --git a/doc/classes/ScriptCreateDialog.xml b/doc/classes/ScriptCreateDialog.xml
index b64e770dbc..c4c17c2379 100644
--- a/doc/classes/ScriptCreateDialog.xml
+++ b/doc/classes/ScriptCreateDialog.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ScriptCreateDialog" inherits="ConfirmationDialog" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ScriptCreateDialog" inherits="ConfirmationDialog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Godot editor's popup dialog for creating new [Script] files.
</brief_description>
diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml
index 98e6cf202b..2c88ecd675 100644
--- a/doc/classes/ScriptEditor.xml
+++ b/doc/classes/ScriptEditor.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ScriptEditor" inherits="PanelContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ScriptEditor" inherits="PanelContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Godot editor's script editor.
</brief_description>
diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml
index c1c12d366a..dca4fe9276 100644
--- a/doc/classes/ScriptEditorBase.xml
+++ b/doc/classes/ScriptEditorBase.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ScriptEditorBase" inherits="VBoxContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ScriptEditorBase" inherits="VBoxContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base editor for editing scripts in the [ScriptEditor].
</brief_description>
diff --git a/doc/classes/ScriptExtension.xml b/doc/classes/ScriptExtension.xml
index ffab49d2c9..934cbf5a26 100644
--- a/doc/classes/ScriptExtension.xml
+++ b/doc/classes/ScriptExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ScriptExtension" inherits="Script" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ScriptExtension" inherits="Script" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/ScriptLanguage.xml b/doc/classes/ScriptLanguage.xml
index 1aa6de69ce..51134012c7 100644
--- a/doc/classes/ScriptLanguage.xml
+++ b/doc/classes/ScriptLanguage.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ScriptLanguage" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ScriptLanguage" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/ScriptLanguageExtension.xml b/doc/classes/ScriptLanguageExtension.xml
index 43388554b3..a05d243b0a 100644
--- a/doc/classes/ScriptLanguageExtension.xml
+++ b/doc/classes/ScriptLanguageExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ScriptLanguageExtension" inherits="ScriptLanguage" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ScriptLanguageExtension" inherits="ScriptLanguage" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/ScrollBar.xml b/doc/classes/ScrollBar.xml
index 3437f0e941..0cbb60198b 100644
--- a/doc/classes/ScrollBar.xml
+++ b/doc/classes/ScrollBar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ScrollBar" inherits="Range" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ScrollBar" inherits="Range" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for scrollbars.
</brief_description>
diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml
index 9026f4a5d0..15a2f2cabf 100644
--- a/doc/classes/ScrollContainer.xml
+++ b/doc/classes/ScrollContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ScrollContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ScrollContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container used to provide scrollbars to a child control when needed.
</brief_description>
diff --git a/doc/classes/SegmentShape2D.xml b/doc/classes/SegmentShape2D.xml
index 661235a177..51c9f3b448 100644
--- a/doc/classes/SegmentShape2D.xml
+++ b/doc/classes/SegmentShape2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SegmentShape2D" inherits="Shape2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SegmentShape2D" inherits="Shape2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D line segment shape used for physics collision.
</brief_description>
diff --git a/doc/classes/Semaphore.xml b/doc/classes/Semaphore.xml
index 48a5da30f9..d0db24dfb7 100644
--- a/doc/classes/Semaphore.xml
+++ b/doc/classes/Semaphore.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Semaphore" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Semaphore" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A synchronization mechanism used to control access to a shared resource by [Thread]s.
</brief_description>
diff --git a/doc/classes/SeparationRayShape2D.xml b/doc/classes/SeparationRayShape2D.xml
index a8440b5289..6237584056 100644
--- a/doc/classes/SeparationRayShape2D.xml
+++ b/doc/classes/SeparationRayShape2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SeparationRayShape2D" inherits="Shape2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SeparationRayShape2D" inherits="Shape2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D ray shape used for physics collision that tries to separate itself from any collider.
</brief_description>
diff --git a/doc/classes/SeparationRayShape3D.xml b/doc/classes/SeparationRayShape3D.xml
index d8670e40d7..aaf8791224 100644
--- a/doc/classes/SeparationRayShape3D.xml
+++ b/doc/classes/SeparationRayShape3D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SeparationRayShape3D" inherits="Shape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SeparationRayShape3D" inherits="Shape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D ray shape used for physics collision that tries to separate itself from any collider.
</brief_description>
<description>
- A 3D ray shape, intended for use in physics. Usually used to provide a shape for a [CollisionShape2D]. When a [SeparationRayShape3D] collides with an object, it tries to separate itself from it by moving its endpoint to the collision point. It can for example be used for spears falling from the sky.
+ A 3D ray shape, intended for use in physics. Usually used to provide a shape for a [CollisionShape3D]. When a [SeparationRayShape3D] collides with an object, it tries to separate itself from it by moving its endpoint to the collision point. It can for example be used for spears falling from the sky.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Separator.xml b/doc/classes/Separator.xml
index 4c393d1787..fe6f6858b7 100644
--- a/doc/classes/Separator.xml
+++ b/doc/classes/Separator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Separator" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Separator" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for separators.
</brief_description>
diff --git a/doc/classes/Shader.xml b/doc/classes/Shader.xml
index 2ae3dcc9dd..b71f9ca1b0 100644
--- a/doc/classes/Shader.xml
+++ b/doc/classes/Shader.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Shader" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Shader" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A shader implemented in the Godot shading language.
</brief_description>
diff --git a/doc/classes/ShaderGlobalsOverride.xml b/doc/classes/ShaderGlobalsOverride.xml
index bfa3b9fbcd..afd6ee527e 100644
--- a/doc/classes/ShaderGlobalsOverride.xml
+++ b/doc/classes/ShaderGlobalsOverride.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ShaderGlobalsOverride" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ShaderGlobalsOverride" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Overrides global shader parameters' values in a specific scene.
</brief_description>
diff --git a/doc/classes/ShaderInclude.xml b/doc/classes/ShaderInclude.xml
index 28537ef9bb..ec9f1459b2 100644
--- a/doc/classes/ShaderInclude.xml
+++ b/doc/classes/ShaderInclude.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ShaderInclude" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ShaderInclude" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A snippet of shader code to be included in a [Shader] with [code]#include[/code].
</brief_description>
diff --git a/doc/classes/ShaderMaterial.xml b/doc/classes/ShaderMaterial.xml
index 6c42363c8f..e2d0696a4b 100644
--- a/doc/classes/ShaderMaterial.xml
+++ b/doc/classes/ShaderMaterial.xml
@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ShaderMaterial" inherits="Material" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ShaderMaterial" inherits="Material" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A material that uses a custom [Shader] program.
</brief_description>
<description>
A material that uses a custom [Shader] program to render either items to screen or process particles. You can create multiple materials for the same shader but configure different values for the uniforms defined in the shader.
+ [b]Note:[/b] For performance reasons the [signal Resource.changed] signal is only emitted when the [member Resource.resource_name] is changed. Only in editor, is also emitted for [member shader] changes.
</description>
<tutorials>
<link title="Shaders documentation index">$DOCS_URL/tutorials/shaders/index.html</link>
diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml
index c1070b9cdd..07c014f223 100644
--- a/doc/classes/Shape2D.xml
+++ b/doc/classes/Shape2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Shape2D" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Shape2D" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for 2D shapes used for physics collision.
</brief_description>
diff --git a/doc/classes/Shape3D.xml b/doc/classes/Shape3D.xml
index cc9d77a581..b82620139a 100644
--- a/doc/classes/Shape3D.xml
+++ b/doc/classes/Shape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Shape3D" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Shape3D" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for 3D shapes used for physics collision.
</brief_description>
diff --git a/doc/classes/ShapeCast2D.xml b/doc/classes/ShapeCast2D.xml
index 6be5a39da1..a04ffe3881 100644
--- a/doc/classes/ShapeCast2D.xml
+++ b/doc/classes/ShapeCast2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ShapeCast2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ShapeCast2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D shape that sweeps a region of space to detect [CollisionObject2D]s.
</brief_description>
diff --git a/doc/classes/ShapeCast3D.xml b/doc/classes/ShapeCast3D.xml
index e9b5877ed8..ce72944098 100644
--- a/doc/classes/ShapeCast3D.xml
+++ b/doc/classes/ShapeCast3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ShapeCast3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ShapeCast3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D shape that sweeps a region of space to detect [CollisionObject3D]s.
</brief_description>
@@ -119,11 +119,11 @@
Removes a collision exception so the shape does report collisions with the specified [RID].
</description>
</method>
- <method name="resource_changed">
+ <method name="resource_changed" is_deprecated="true">
<return type="void" />
<param index="0" name="resource" type="Resource" />
<description>
- This method is used internally to update the debug gizmo in the editor. Any code placed in this function will be called whenever the [member shape] resource is modified.
+ [i]Obsoleted.[/i] Use [signal Resource.changed] instead.
</description>
</method>
<method name="set_collision_mask_value">
diff --git a/doc/classes/Shortcut.xml b/doc/classes/Shortcut.xml
index b5667a6eb9..4343a789fd 100644
--- a/doc/classes/Shortcut.xml
+++ b/doc/classes/Shortcut.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Shortcut" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Shortcut" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A shortcut for binding input.
</brief_description>
diff --git a/doc/classes/Signal.xml b/doc/classes/Signal.xml
index ada533153c..07e15d0b23 100644
--- a/doc/classes/Signal.xml
+++ b/doc/classes/Signal.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Signal" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Signal" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A built-in type representing a signal of an [Object].
</brief_description>
diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml
index e4b157c7ca..7ff55dfcc5 100644
--- a/doc/classes/Skeleton2D.xml
+++ b/doc/classes/Skeleton2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Skeleton2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Skeleton2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
The parent of a hierarchy of [Bone2D]s, used to create a 2D skeletal animation.
</brief_description>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index a3f0a6c734..b4c42ea399 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Skeleton3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Skeleton3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node containing a bone hierarchy, used to create a 3D skeletal animation.
</brief_description>
diff --git a/doc/classes/SkeletonIK3D.xml b/doc/classes/SkeletonIK3D.xml
index 9973c1818b..c72383c84f 100644
--- a/doc/classes/SkeletonIK3D.xml
+++ b/doc/classes/SkeletonIK3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonIK3D" inherits="Node" is_deprecated="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonIK3D" inherits="Node" is_deprecated="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node used to rotate all bones of a [Skeleton3D] bone chain a way that places the end bone at a desired 3D position.
</brief_description>
diff --git a/doc/classes/SkeletonModification2D.xml b/doc/classes/SkeletonModification2D.xml
index f5fa3f8bb9..c1eee9cb5c 100644
--- a/doc/classes/SkeletonModification2D.xml
+++ b/doc/classes/SkeletonModification2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2D" inherits="Resource" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2D" inherits="Resource" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for resources that operate on [Bone2D]s in a [Skeleton2D].
</brief_description>
diff --git a/doc/classes/SkeletonModification2DCCDIK.xml b/doc/classes/SkeletonModification2DCCDIK.xml
index 165152a415..af71ae809c 100644
--- a/doc/classes/SkeletonModification2DCCDIK.xml
+++ b/doc/classes/SkeletonModification2DCCDIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DCCDIK" inherits="SkeletonModification2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DCCDIK" inherits="SkeletonModification2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses CCDIK to manipulate a series of bones to reach a target in 2D.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DFABRIK.xml b/doc/classes/SkeletonModification2DFABRIK.xml
index 1b6e52f705..a31c908082 100644
--- a/doc/classes/SkeletonModification2DFABRIK.xml
+++ b/doc/classes/SkeletonModification2DFABRIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DFABRIK" inherits="SkeletonModification2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DFABRIK" inherits="SkeletonModification2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses FABRIK to manipulate a series of [Bone2D] nodes to reach a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DJiggle.xml b/doc/classes/SkeletonModification2DJiggle.xml
index e7b1bd5e84..7683d29d1c 100644
--- a/doc/classes/SkeletonModification2DJiggle.xml
+++ b/doc/classes/SkeletonModification2DJiggle.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DJiggle" inherits="SkeletonModification2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DJiggle" inherits="SkeletonModification2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that jiggles [Bone2D] nodes as they move towards a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DLookAt.xml b/doc/classes/SkeletonModification2DLookAt.xml
index 190ba7b432..797722eb86 100644
--- a/doc/classes/SkeletonModification2DLookAt.xml
+++ b/doc/classes/SkeletonModification2DLookAt.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DLookAt" inherits="SkeletonModification2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DLookAt" inherits="SkeletonModification2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that rotates a [Bone2D] node to look at a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DPhysicalBones.xml b/doc/classes/SkeletonModification2DPhysicalBones.xml
index ed7bf946dc..930f201ad5 100644
--- a/doc/classes/SkeletonModification2DPhysicalBones.xml
+++ b/doc/classes/SkeletonModification2DPhysicalBones.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DPhysicalBones" inherits="SkeletonModification2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DPhysicalBones" inherits="SkeletonModification2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that applies the transforms of [PhysicalBone2D] nodes to [Bone2D] nodes.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DStackHolder.xml b/doc/classes/SkeletonModification2DStackHolder.xml
index 2b94c42583..60fba86d32 100644
--- a/doc/classes/SkeletonModification2DStackHolder.xml
+++ b/doc/classes/SkeletonModification2DStackHolder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DStackHolder" inherits="SkeletonModification2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DStackHolder" inherits="SkeletonModification2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that holds and executes a [SkeletonModificationStack2D].
</brief_description>
diff --git a/doc/classes/SkeletonModification2DTwoBoneIK.xml b/doc/classes/SkeletonModification2DTwoBoneIK.xml
index 254a8df046..2206aa5719 100644
--- a/doc/classes/SkeletonModification2DTwoBoneIK.xml
+++ b/doc/classes/SkeletonModification2DTwoBoneIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DTwoBoneIK" inherits="SkeletonModification2D" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DTwoBoneIK" inherits="SkeletonModification2D" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that rotates two bones using the law of cosines to reach the target.
</brief_description>
diff --git a/doc/classes/SkeletonModificationStack2D.xml b/doc/classes/SkeletonModificationStack2D.xml
index cd27f2ab79..391771d1d3 100644
--- a/doc/classes/SkeletonModificationStack2D.xml
+++ b/doc/classes/SkeletonModificationStack2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModificationStack2D" inherits="Resource" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModificationStack2D" inherits="Resource" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that holds a stack of [SkeletonModification2D]s.
</brief_description>
diff --git a/doc/classes/SkeletonProfile.xml b/doc/classes/SkeletonProfile.xml
index 1796dabcfd..3ed29668e4 100644
--- a/doc/classes/SkeletonProfile.xml
+++ b/doc/classes/SkeletonProfile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonProfile" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonProfile" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for a profile of a virtual skeleton used as a target for retargeting.
</brief_description>
diff --git a/doc/classes/SkeletonProfileHumanoid.xml b/doc/classes/SkeletonProfileHumanoid.xml
index 465aa4a9af..fe9eded7a9 100644
--- a/doc/classes/SkeletonProfileHumanoid.xml
+++ b/doc/classes/SkeletonProfileHumanoid.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonProfileHumanoid" inherits="SkeletonProfile" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonProfileHumanoid" inherits="SkeletonProfile" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A humanoid [SkeletonProfile] preset.
</brief_description>
diff --git a/doc/classes/Skin.xml b/doc/classes/Skin.xml
index 6b0cf60dda..0e801de8d5 100644
--- a/doc/classes/Skin.xml
+++ b/doc/classes/Skin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Skin" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Skin" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/SkinReference.xml b/doc/classes/SkinReference.xml
index 678c8acaec..466dbe2500 100644
--- a/doc/classes/SkinReference.xml
+++ b/doc/classes/SkinReference.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkinReference" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkinReference" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/Sky.xml b/doc/classes/Sky.xml
index 4adf4737a1..d52fd6ce40 100644
--- a/doc/classes/Sky.xml
+++ b/doc/classes/Sky.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Sky" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Sky" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Background that uses a [Material] to draw a sky.
</brief_description>
diff --git a/doc/classes/Slider.xml b/doc/classes/Slider.xml
index fa5cdeb5c5..b946b6cedb 100644
--- a/doc/classes/Slider.xml
+++ b/doc/classes/Slider.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Slider" inherits="Range" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Slider" inherits="Range" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for sliders.
</brief_description>
diff --git a/doc/classes/SliderJoint3D.xml b/doc/classes/SliderJoint3D.xml
index 11e38878e9..49b362041b 100644
--- a/doc/classes/SliderJoint3D.xml
+++ b/doc/classes/SliderJoint3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SliderJoint3D" inherits="Joint3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SliderJoint3D" inherits="Joint3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics joint that restricts the movement of a 3D physics body along an axis relative to another physics body.
</brief_description>
@@ -105,7 +105,7 @@
A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
</constant>
<constant name="PARAM_LINEAR_LIMIT_RESTITUTION" value="3" enum="Param">
- The amount of restitution once the limits are surpassed. The lower, the more velocityenergy gets lost.
+ The amount of restitution once the limits are surpassed. The lower, the more velocity-energy gets lost.
</constant>
<constant name="PARAM_LINEAR_LIMIT_DAMPING" value="4" enum="Param">
The amount of damping once the slider limits are surpassed.
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
index ee390995a9..1d227241ad 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SoftBody3D" inherits="MeshInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SoftBody3D" inherits="MeshInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A deformable 3D physics mesh.
</brief_description>
diff --git a/doc/classes/SphereMesh.xml b/doc/classes/SphereMesh.xml
index 6077654b90..8f815bebbf 100644
--- a/doc/classes/SphereMesh.xml
+++ b/doc/classes/SphereMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SphereMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SphereMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Class representing a spherical [PrimitiveMesh].
</brief_description>
diff --git a/doc/classes/SphereOccluder3D.xml b/doc/classes/SphereOccluder3D.xml
index 174ee54f17..a154b2742c 100644
--- a/doc/classes/SphereOccluder3D.xml
+++ b/doc/classes/SphereOccluder3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SphereOccluder3D" inherits="Occluder3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SphereOccluder3D" inherits="Occluder3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Spherical shape for use with occlusion culling in [OccluderInstance3D].
</brief_description>
diff --git a/doc/classes/SphereShape3D.xml b/doc/classes/SphereShape3D.xml
index 69ddb4fb5e..313b05dff4 100644
--- a/doc/classes/SphereShape3D.xml
+++ b/doc/classes/SphereShape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SphereShape3D" inherits="Shape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SphereShape3D" inherits="Shape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D sphere shape used for physics collision.
</brief_description>
diff --git a/doc/classes/SpinBox.xml b/doc/classes/SpinBox.xml
index e276ca6903..217d0947db 100644
--- a/doc/classes/SpinBox.xml
+++ b/doc/classes/SpinBox.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpinBox" inherits="Range" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SpinBox" inherits="Range" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An input field for numbers.
</brief_description>
diff --git a/doc/classes/SplitContainer.xml b/doc/classes/SplitContainer.xml
index a75203c8e3..5078685cce 100644
--- a/doc/classes/SplitContainer.xml
+++ b/doc/classes/SplitContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SplitContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SplitContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that splits two child controls horizontally or vertically and provides a grabber for adjusting the split ratio.
</brief_description>
diff --git a/doc/classes/SpotLight3D.xml b/doc/classes/SpotLight3D.xml
index 4c4ce43527..06d3dfcef7 100644
--- a/doc/classes/SpotLight3D.xml
+++ b/doc/classes/SpotLight3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpotLight3D" inherits="Light3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SpotLight3D" inherits="Light3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A spotlight, such as a reflector spotlight or a lantern.
</brief_description>
diff --git a/doc/classes/SpringArm3D.xml b/doc/classes/SpringArm3D.xml
index 61135fc9d0..6e12d9a613 100644
--- a/doc/classes/SpringArm3D.xml
+++ b/doc/classes/SpringArm3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpringArm3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SpringArm3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D raycast that dynamically moves its children near the collision point.
</brief_description>
diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml
index fbebf4ef97..8eb9e26a83 100644
--- a/doc/classes/Sprite2D.xml
+++ b/doc/classes/Sprite2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Sprite2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Sprite2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
General-purpose sprite node.
</brief_description>
diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml
index 8ceba7f513..9733c5f48a 100644
--- a/doc/classes/Sprite3D.xml
+++ b/doc/classes/Sprite3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Sprite3D" inherits="SpriteBase3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Sprite3D" inherits="SpriteBase3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
2D sprite node in a 3D world.
</brief_description>
diff --git a/doc/classes/SpriteBase3D.xml b/doc/classes/SpriteBase3D.xml
index ca108e664f..a87608bb72 100644
--- a/doc/classes/SpriteBase3D.xml
+++ b/doc/classes/SpriteBase3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpriteBase3D" inherits="GeometryInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SpriteBase3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
2D sprite node in 3D environment.
</brief_description>
diff --git a/doc/classes/SpriteFrames.xml b/doc/classes/SpriteFrames.xml
index 291515558f..93c4a6e8de 100644
--- a/doc/classes/SpriteFrames.xml
+++ b/doc/classes/SpriteFrames.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpriteFrames" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SpriteFrames" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Sprite frame library for AnimatedSprite2D and AnimatedSprite3D.
</brief_description>
diff --git a/doc/classes/StandardMaterial3D.xml b/doc/classes/StandardMaterial3D.xml
index e2bad93575..8814169d1d 100644
--- a/doc/classes/StandardMaterial3D.xml
+++ b/doc/classes/StandardMaterial3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StandardMaterial3D" inherits="BaseMaterial3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StandardMaterial3D" inherits="BaseMaterial3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Physically based rendering (PBR) material that can be applied to 3D objects.
</brief_description>
diff --git a/doc/classes/StaticBody2D.xml b/doc/classes/StaticBody2D.xml
index 571b9e4307..185a2cdda4 100644
--- a/doc/classes/StaticBody2D.xml
+++ b/doc/classes/StaticBody2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StaticBody2D" inherits="PhysicsBody2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StaticBody2D" inherits="PhysicsBody2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D physics body that can't be moved by external forces. When moved manually, it doesn't affect other bodies in its path.
</brief_description>
diff --git a/doc/classes/StaticBody3D.xml b/doc/classes/StaticBody3D.xml
index 7b2d15a5e4..093fe4c926 100644
--- a/doc/classes/StaticBody3D.xml
+++ b/doc/classes/StaticBody3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StaticBody3D" inherits="PhysicsBody3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StaticBody3D" inherits="PhysicsBody3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D physics body that can't be moved by external forces. When moved manually, it doesn't affect other bodies in its path.
</brief_description>
diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml
index d754c9c73c..ad5c5472b8 100644
--- a/doc/classes/StreamPeer.xml
+++ b/doc/classes/StreamPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeer" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StreamPeer" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for interacting with streams.
</brief_description>
diff --git a/doc/classes/StreamPeerBuffer.xml b/doc/classes/StreamPeerBuffer.xml
index a947edea81..3fd0642b18 100644
--- a/doc/classes/StreamPeerBuffer.xml
+++ b/doc/classes/StreamPeerBuffer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeerBuffer" inherits="StreamPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StreamPeerBuffer" inherits="StreamPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A stream peer used to handle binary data streams.
</brief_description>
diff --git a/doc/classes/StreamPeerExtension.xml b/doc/classes/StreamPeerExtension.xml
index 70f131e553..84a5f1716a 100644
--- a/doc/classes/StreamPeerExtension.xml
+++ b/doc/classes/StreamPeerExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeerExtension" inherits="StreamPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StreamPeerExtension" inherits="StreamPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/StreamPeerGZIP.xml b/doc/classes/StreamPeerGZIP.xml
index 7166b57f58..fc22f72df9 100644
--- a/doc/classes/StreamPeerGZIP.xml
+++ b/doc/classes/StreamPeerGZIP.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeerGZIP" inherits="StreamPeer" is_experimental="true" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StreamPeerGZIP" inherits="StreamPeer" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A stream peer that handles GZIP and deflate compression/decompression.
</brief_description>
diff --git a/doc/classes/StreamPeerTCP.xml b/doc/classes/StreamPeerTCP.xml
index 209e178df2..a7880fb484 100644
--- a/doc/classes/StreamPeerTCP.xml
+++ b/doc/classes/StreamPeerTCP.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeerTCP" inherits="StreamPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StreamPeerTCP" inherits="StreamPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A stream peer that handles TCP connections.
</brief_description>
diff --git a/doc/classes/StreamPeerTLS.xml b/doc/classes/StreamPeerTLS.xml
index ca402f7caa..ace060f709 100644
--- a/doc/classes/StreamPeerTLS.xml
+++ b/doc/classes/StreamPeerTLS.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeerTLS" inherits="StreamPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StreamPeerTLS" inherits="StreamPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A stream peer that handles TLS connections.
</brief_description>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index ca8d1d5255..913f2f2654 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="String" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="String" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A built-in type for strings.
</brief_description>
@@ -920,11 +920,11 @@
<description>
Converts the string representing a decimal number into a [float]. This method stops on the first non-number character, except the first decimal point ([code].[/code]) and the exponent letter ([code]e[/code]). See also [method is_valid_float].
[codeblock]
- var a = "12.35".to_float() # a is 12.35
- var b = "1.2.3".to_float() # b is 1.2
- var c = "12xy3".to_float() # c is 12.0
- var d = "1e3".to_float() # d is 1000.0
- var e = "Hello!".to_int() # e is 0.0
+ var a = "12.35".to_float() # a is 12.35
+ var b = "1.2.3".to_float() # b is 1.2
+ var c = "12xy3".to_float() # c is 12.0
+ var d = "1e3".to_float() # d is 1000.0
+ var e = "Hello!".to_float() # e is 0.0
[/codeblock]
</description>
</method>
@@ -1054,7 +1054,7 @@
<method name="validate_node_name" qualifiers="const">
<return type="String" />
<description>
- Returns a copy of the string with all characters that are not allowed in [member Node.name] removed ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code] [code]%[/code]).
+ Returns a copy of the string with all characters that are not allowed in [member Node.name] ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code] [code]%[/code]) replaced with underscores.
</description>
</method>
<method name="xml_escape" qualifiers="const">
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index 557f94b84a..0814a30a8d 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StringName" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StringName" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A built-in type for unique strings.
</brief_description>
@@ -961,7 +961,7 @@
<method name="validate_node_name" qualifiers="const">
<return type="String" />
<description>
- Returns a copy of the string with all characters that are not allowed in [member Node.name] removed ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code] [code]%[/code]).
+ Returns a copy of the string with all characters that are not allowed in [member Node.name] ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code] [code]%[/code]) replaced with underscores.
</description>
</method>
<method name="xml_escape" qualifiers="const">
diff --git a/doc/classes/StyleBox.xml b/doc/classes/StyleBox.xml
index c4aeb59f22..75fbb03dd6 100644
--- a/doc/classes/StyleBox.xml
+++ b/doc/classes/StyleBox.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StyleBox" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StyleBox" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for defining stylized boxes for UI elements.
</brief_description>
diff --git a/doc/classes/StyleBoxEmpty.xml b/doc/classes/StyleBoxEmpty.xml
index 253cf7b4af..bd04ca56f6 100644
--- a/doc/classes/StyleBoxEmpty.xml
+++ b/doc/classes/StyleBoxEmpty.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StyleBoxEmpty" inherits="StyleBox" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StyleBoxEmpty" inherits="StyleBox" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An empty [StyleBox] (does not display anything).
</brief_description>
diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml
index be026b9ff2..2c3908a72c 100644
--- a/doc/classes/StyleBoxFlat.xml
+++ b/doc/classes/StyleBoxFlat.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StyleBoxFlat" inherits="StyleBox" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StyleBoxFlat" inherits="StyleBox" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A customizable [StyleBox] that doesn't use a texture.
</brief_description>
diff --git a/doc/classes/StyleBoxLine.xml b/doc/classes/StyleBoxLine.xml
index e2351b948f..8958cf9fc8 100644
--- a/doc/classes/StyleBoxLine.xml
+++ b/doc/classes/StyleBoxLine.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StyleBoxLine" inherits="StyleBox" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StyleBoxLine" inherits="StyleBox" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [StyleBox] that displays a single line of a given color and thickness.
</brief_description>
diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml
index 8b8598df9f..14bceb4d4c 100644
--- a/doc/classes/StyleBoxTexture.xml
+++ b/doc/classes/StyleBoxTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StyleBoxTexture" inherits="StyleBox" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StyleBoxTexture" inherits="StyleBox" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A texture-based nine-patch [StyleBox].
</brief_description>
diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml
index b6fded5621..1a7a4f6e96 100644
--- a/doc/classes/SubViewport.xml
+++ b/doc/classes/SubViewport.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SubViewport" inherits="Viewport" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SubViewport" inherits="Viewport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An interface to a game world that doesn't create a window or draw to the screen directly.
</brief_description>
diff --git a/doc/classes/SubViewportContainer.xml b/doc/classes/SubViewportContainer.xml
index 64f62d53d8..08e7ca23f7 100644
--- a/doc/classes/SubViewportContainer.xml
+++ b/doc/classes/SubViewportContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SubViewportContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SubViewportContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container used for displaying the contents of a [SubViewport].
</brief_description>
@@ -11,6 +11,7 @@
<tutorials>
</tutorials>
<members>
+ <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="1" />
<member name="stretch" type="bool" setter="set_stretch" getter="is_stretch_enabled" default="false">
If [code]true[/code], the sub-viewport will be automatically resized to the control's size.
[b]Note:[/b] If [code]true[/code], this will prohibit changing [member SubViewport.size] of its children manually.
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index aa486a1843..4f752ec417 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SurfaceTool" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SurfaceTool" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Helper tool to create geometry.
</brief_description>
diff --git a/doc/classes/SyntaxHighlighter.xml b/doc/classes/SyntaxHighlighter.xml
index 3815d6d2fe..27cee26c50 100644
--- a/doc/classes/SyntaxHighlighter.xml
+++ b/doc/classes/SyntaxHighlighter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SyntaxHighlighter" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SyntaxHighlighter" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for syntax highlighters. Provides syntax highlighting data to a [TextEdit].
</brief_description>
diff --git a/doc/classes/SystemFont.xml b/doc/classes/SystemFont.xml
index f4bf6678d1..ea3dd0acd2 100644
--- a/doc/classes/SystemFont.xml
+++ b/doc/classes/SystemFont.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SystemFont" inherits="Font" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SystemFont" inherits="Font" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A font loaded from a system font. Falls back to a default theme font if not implemented on the host OS.
</brief_description>
diff --git a/doc/classes/TCPServer.xml b/doc/classes/TCPServer.xml
index 8b4011fdee..f84983de49 100644
--- a/doc/classes/TCPServer.xml
+++ b/doc/classes/TCPServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TCPServer" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TCPServer" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A TCP server.
</brief_description>
diff --git a/doc/classes/TLSOptions.xml b/doc/classes/TLSOptions.xml
index a95e9a6123..125c730e27 100644
--- a/doc/classes/TLSOptions.xml
+++ b/doc/classes/TLSOptions.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TLSOptions" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TLSOptions" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
TLS configuration for clients and servers.
</brief_description>
@@ -29,15 +29,15 @@
<description>
Creates a TLS client configuration which validates certificates and their common names (fully qualified domain names).
You can specify a custom [param trusted_chain] of certification authorities (the default CA list will be used if [code]null[/code]), and optionally provide a [param common_name_override] if you expect the certificate to have a common name other then the server FQDN.
- Note: On the Web plafrom, TLS verification is always enforced against the CA list of the web browser. This is considered a security feature.
+ [b]Note:[/b] On the Web platform, TLS verification is always enforced against the CA list of the web browser. This is considered a security feature.
</description>
</method>
<method name="client_unsafe" qualifiers="static">
<return type="TLSOptions" />
<param index="0" name="trusted_chain" type="X509Certificate" default="null" />
<description>
- Creates an [b]unsafe[/b] TLS client configuration where certificate validation is optional. You can optionally provide a valid [param trusted_chain], but the common name of the certififcates will never be checked. Using this configuration for purposes other than testing [b]is not recommended[/b].
- Note: On the Web plafrom, TLS verification is always enforced against the CA list of the web browser. This is considered a security feature.
+ Creates an [b]unsafe[/b] TLS client configuration where certificate validation is optional. You can optionally provide a valid [param trusted_chain], but the common name of the certificates will never be checked. Using this configuration for purposes other than testing [b]is not recommended[/b].
+ [b]Note:[/b] On the Web platform, TLS verification is always enforced against the CA list of the web browser. This is considered a security feature.
</description>
</method>
<method name="server" qualifiers="static">
@@ -46,7 +46,7 @@
<param index="1" name="certificate" type="X509Certificate" />
<description>
Creates a TLS server configuration using the provided [param key] and [param certificate].
- Note: The [param certificate] should include the full certificate chain up to the signing CA (certificates file can be concatenated using a general purpose text editor).
+ [b]Note:[/b] The [param certificate] should include the full certificate chain up to the signing CA (certificates file can be concatenated using a general purpose text editor).
</description>
</method>
</methods>
diff --git a/doc/classes/TabBar.xml b/doc/classes/TabBar.xml
index cdbe9d933a..8b3bac456a 100644
--- a/doc/classes/TabBar.xml
+++ b/doc/classes/TabBar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TabBar" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TabBar" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control that provides a horizontal bar with tabs.
</brief_description>
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index ebf9bb2584..940eb89dab 100644
--- a/doc/classes/TabContainer.xml
+++ b/doc/classes/TabContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TabContainer" inherits="Container" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TabContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that creates a tab for each child control, displaying only the active tab's control.
</brief_description>
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 55a5ea18f2..e611b7e3fa 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextEdit" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextEdit" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A multiline text editor.
</brief_description>
@@ -1234,7 +1234,7 @@
<param index="1" name="to_line" type="int" />
<description>
Emitted immediately when the text changes.
- When text is added [param from_line] will be less then [param to_line]. On a remove [param to_line] will be less then [param from_line].
+ When text is added [param from_line] will be less than [param to_line]. On a remove [param to_line] will be less than [param from_line].
</description>
</signal>
<signal name="text_changed">
diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml
index e9bdd67167..e65006716d 100644
--- a/doc/classes/TextLine.xml
+++ b/doc/classes/TextLine.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextLine" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextLine" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds a line of text.
</brief_description>
diff --git a/doc/classes/TextMesh.xml b/doc/classes/TextMesh.xml
index e1999c5f6a..1814b474a4 100644
--- a/doc/classes/TextMesh.xml
+++ b/doc/classes/TextMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Generate an [PrimitiveMesh] from the text.
</brief_description>
diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml
index 2452c9d262..a8a4c3a764 100644
--- a/doc/classes/TextParagraph.xml
+++ b/doc/classes/TextParagraph.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextParagraph" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextParagraph" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds a paragraph of text.
</brief_description>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 17805f259c..e3afe6f65d 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextServer" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextServer" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A server interface for font management and text rendering.
</brief_description>
diff --git a/doc/classes/TextServerDummy.xml b/doc/classes/TextServerDummy.xml
index 4e72b3c5f8..bd50678694 100644
--- a/doc/classes/TextServerDummy.xml
+++ b/doc/classes/TextServerDummy.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextServerDummy" inherits="TextServerExtension" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextServerDummy" inherits="TextServerExtension" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A dummy text server that can't render text or manage fonts.
</brief_description>
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 3240b025bf..fc0a424187 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextServerExtension" inherits="TextServer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextServerExtension" inherits="TextServer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for custom [TextServer] implementations (plugins).
</brief_description>
diff --git a/doc/classes/TextServerManager.xml b/doc/classes/TextServerManager.xml
index 129b367cf4..c0194655e5 100644
--- a/doc/classes/TextServerManager.xml
+++ b/doc/classes/TextServerManager.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextServerManager" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextServerManager" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton for managing [TextServer] implementations.
</brief_description>
diff --git a/doc/classes/Texture.xml b/doc/classes/Texture.xml
index c749bedcfd..ae282319f5 100644
--- a/doc/classes/Texture.xml
+++ b/doc/classes/Texture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Texture" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Texture" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for all texture types.
</brief_description>
diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml
index 2648317341..087f3a70f8 100644
--- a/doc/classes/Texture2D.xml
+++ b/doc/classes/Texture2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Texture2D" inherits="Texture" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Texture2D" inherits="Texture" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture for 2D and 3D.
</brief_description>
diff --git a/doc/classes/Texture2DArray.xml b/doc/classes/Texture2DArray.xml
index ec25a90cc9..f1c76d14e4 100644
--- a/doc/classes/Texture2DArray.xml
+++ b/doc/classes/Texture2DArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Texture2DArray" inherits="ImageTextureLayered" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Texture2DArray" inherits="ImageTextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A single texture resource which consists of multiple, separate images. Each image has the same dimensions and number of mipmap levels.
</brief_description>
diff --git a/doc/classes/Texture2DArrayRD.xml b/doc/classes/Texture2DArrayRD.xml
new file mode 100644
index 0000000000..b28cdd436c
--- /dev/null
+++ b/doc/classes/Texture2DArrayRD.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Texture2DArrayRD" inherits="TextureLayeredRD" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Texture Array for 2D that is bound to a texture created on the [RenderingDevice].
+ </brief_description>
+ <description>
+ This texture array class allows you to use a 2D array texture created directly on the [RenderingDevice] as a texture for materials, meshes, etc.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/Texture2DRD.xml b/doc/classes/Texture2DRD.xml
new file mode 100644
index 0000000000..b935a7763b
--- /dev/null
+++ b/doc/classes/Texture2DRD.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Texture2DRD" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Texture for 2D that is bound to a texture created on the [RenderingDevice].
+ </brief_description>
+ <description>
+ This texture class allows you to use a 2D texture created directly on the [RenderingDevice] as a texture for materials, meshes, etc.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
+ <member name="texture_rd_rid" type="RID" setter="set_texture_rd_rid" getter="get_texture_rd_rid" default="RID()">
+ The RID of the texture object created on the [RenderingDevice].
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/Texture3D.xml b/doc/classes/Texture3D.xml
index 7f5daaf15d..6f054a8e0d 100644
--- a/doc/classes/Texture3D.xml
+++ b/doc/classes/Texture3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Texture3D" inherits="Texture" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Texture3D" inherits="Texture" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for 3-dimensionnal textures.
</brief_description>
diff --git a/doc/classes/Texture3DRD.xml b/doc/classes/Texture3DRD.xml
new file mode 100644
index 0000000000..f9d72b7a0f
--- /dev/null
+++ b/doc/classes/Texture3DRD.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Texture3DRD" inherits="Texture3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Texture for 3D that is bound to a texture created on the [RenderingDevice].
+ </brief_description>
+ <description>
+ This texture class allows you to use a 3D texture created directly on the [RenderingDevice] as a texture for materials, meshes, etc.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="texture_rd_rid" type="RID" setter="set_texture_rd_rid" getter="get_texture_rd_rid" default="RID()">
+ The RID of the texture object created on the [RenderingDevice].
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/TextureButton.xml b/doc/classes/TextureButton.xml
index bb95040d34..6c0d56af05 100644
--- a/doc/classes/TextureButton.xml
+++ b/doc/classes/TextureButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextureButton" inherits="BaseButton" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextureButton" inherits="BaseButton" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture-based button. Supports Pressed, Hover, Disabled and Focused states.
</brief_description>
diff --git a/doc/classes/TextureCubemapArrayRD.xml b/doc/classes/TextureCubemapArrayRD.xml
new file mode 100644
index 0000000000..38d5010ee7
--- /dev/null
+++ b/doc/classes/TextureCubemapArrayRD.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TextureCubemapArrayRD" inherits="TextureLayeredRD" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Texture Array for Cubemaps that is bound to a texture created on the [RenderingDevice].
+ </brief_description>
+ <description>
+ This texture class allows you to use a cubemap array texture created directly on the [RenderingDevice] as a texture for materials, meshes, etc.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/TextureCubemapRD.xml b/doc/classes/TextureCubemapRD.xml
new file mode 100644
index 0000000000..bd7c897ad3
--- /dev/null
+++ b/doc/classes/TextureCubemapRD.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TextureCubemapRD" inherits="TextureLayeredRD" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Texture for Cubemap that is bound to a texture created on the [RenderingDevice].
+ </brief_description>
+ <description>
+ This texture class allows you to use a cubemap texture created directly on the [RenderingDevice] as a texture for materials, meshes, etc.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/TextureLayered.xml b/doc/classes/TextureLayered.xml
index eea5e13557..05443f809f 100644
--- a/doc/classes/TextureLayered.xml
+++ b/doc/classes/TextureLayered.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextureLayered" inherits="Texture" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextureLayered" inherits="Texture" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for texture types which contain the data of multiple [Image]s. Each image is of the same size and format.
</brief_description>
diff --git a/doc/classes/TextureLayeredRD.xml b/doc/classes/TextureLayeredRD.xml
new file mode 100644
index 0000000000..65f2d87624
--- /dev/null
+++ b/doc/classes/TextureLayeredRD.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TextureLayeredRD" inherits="TextureLayered" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Abstract base class for layered texture RD types.
+ </brief_description>
+ <description>
+ Base class for [Texture2DArrayRD], [TextureCubemapRD] and [TextureCubemapArrayRD]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="texture_rd_rid" type="RID" setter="set_texture_rd_rid" getter="get_texture_rd_rid" default="RID()">
+ The RID of the texture object created on the [RenderingDevice].
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml
index 5fd90e6b4d..23cacf481f 100644
--- a/doc/classes/TextureProgressBar.xml
+++ b/doc/classes/TextureProgressBar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextureProgressBar" inherits="Range" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextureProgressBar" inherits="Range" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Texture-based progress bar. Useful for loading screens and life or stamina bars.
</brief_description>
diff --git a/doc/classes/TextureRect.xml b/doc/classes/TextureRect.xml
index 79ee8e44ab..d5f60839b9 100644
--- a/doc/classes/TextureRect.xml
+++ b/doc/classes/TextureRect.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextureRect" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TextureRect" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control that displays a texture.
</brief_description>
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml
index f01a6da36b..eb3c170583 100644
--- a/doc/classes/Theme.xml
+++ b/doc/classes/Theme.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Theme" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Theme" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource used for styling/skinning [Control]s and [Window]s.
</brief_description>
diff --git a/doc/classes/ThemeDB.xml b/doc/classes/ThemeDB.xml
index 9eb694467b..106d011c43 100644
--- a/doc/classes/ThemeDB.xml
+++ b/doc/classes/ThemeDB.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ThemeDB" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ThemeDB" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton that provides access to static information about [Theme] resources used by the engine and by your project.
</brief_description>
diff --git a/doc/classes/Thread.xml b/doc/classes/Thread.xml
index b212391d2a..dbf63c0852 100644
--- a/doc/classes/Thread.xml
+++ b/doc/classes/Thread.xml
@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Thread" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Thread" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A unit of execution in a process.
</brief_description>
<description>
A unit of execution in a process. Can run methods on [Object]s simultaneously. The use of synchronization via [Mutex] or [Semaphore] is advised if working with shared objects.
- [b]Note:[/b] Breakpoints won't break on code if it's running in a thread. This is a current limitation of the GDScript debugger.
[b]Warning:[/b]
To ensure proper cleanup without crashes or deadlocks, when a [Thread]'s reference count reaches zero and it is therefore destroyed, the following conditions must be met:
- It must not have any [Mutex] objects locked.
diff --git a/doc/classes/TileData.xml b/doc/classes/TileData.xml
index cfbd5a3d06..8aa5f1398a 100644
--- a/doc/classes/TileData.xml
+++ b/doc/classes/TileData.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TileData" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TileData" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Settings for a single tile in a [TileSet].
</brief_description>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index d4ba3ebb1f..4ed831c213 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TileMap" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TileMap" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Node for 2D tile-based maps.
</brief_description>
@@ -55,6 +55,7 @@
<param index="0" name="layer" type="int" />
<description>
Clears all cells on the given layer.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="erase_cell">
@@ -63,6 +64,7 @@
<param index="1" name="coords" type="Vector2i" />
<description>
Erases the cell on layer [param layer] at coordinates [param coords].
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="fix_invalid_tiles">
@@ -75,7 +77,7 @@
<return type="void" />
<param index="0" name="layer" type="int" default="-1" />
<description>
- Triggers an update of the TileMap. If [param layer] is provided, only updates the given layer.
+ Triggers an update of the TileMap. If [param layer] is provided and is positive, only updates the given layer.
[b]Note:[/b] The TileMap node updates automatically when one of its properties is modified. A manual update is only needed if runtime modifications (implemented in [method _tile_data_runtime_update]) need to be applied.
[b]Warning:[/b] Updating the TileMap is computationally expensive and may impact performance. Try to limit the number of updates and the tiles they impact (by placing frequently updated tiles in a dedicated layer for example).
</description>
@@ -87,6 +89,7 @@
<param index="2" name="use_proxies" type="bool" default="false" />
<description>
Returns the tile alternative ID of the cell on layer [param layer] at [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="get_cell_atlas_coords" qualifiers="const">
@@ -96,6 +99,7 @@
<param index="2" name="use_proxies" type="bool" default="false" />
<description>
Returns the tile atlas coordinates ID of the cell on layer [param layer] at coordinates [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="get_cell_source_id" qualifiers="const">
@@ -106,6 +110,7 @@
<description>
Returns the tile source ID of the cell on layer [param layer] at coordinates [param coords]. Returns [code]-1[/code] if the cell does not exist.
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="get_cell_tile_data" qualifiers="const">
@@ -115,6 +120,7 @@
<param index="2" name="use_proxies" type="bool" default="false" />
<description>
Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell does not exist or is not a [TileSetAtlasSource].
+ If [param layer] is negative, the layers are accessed from the last one.
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
[codeblock]
func get_clicked_tile_power():
@@ -146,6 +152,7 @@
<param index="0" name="layer" type="int" />
<description>
Returns a TileMap layer's modulate.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="get_layer_name" qualifiers="const">
@@ -153,6 +160,17 @@
<param index="0" name="layer" type="int" />
<description>
Returns a TileMap layer's name.
+ If [param layer] is negative, the layers are accessed from the last one.
+ </description>
+ </method>
+ <method name="get_layer_navigation_map" qualifiers="const">
+ <return type="RID" />
+ <param index="0" name="layer" type="int" />
+ <description>
+ Returns the [NavigationServer2D] navigation map [RID] currently assigned to the specified TileMap [param layer].
+ By default the TileMap uses the default [World2D] navigation map for the first TileMap layer. For each additional TileMap layer a new navigation map is created for the additional layer.
+ In order to make [NavigationAgent2D] switch between TileMap layer navigation maps use [method NavigationAgent2D.set_navigation_map] with the navigation map received from [method get_layer_navigation_map].
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="get_layer_y_sort_origin" qualifiers="const">
@@ -160,6 +178,7 @@
<param index="0" name="layer" type="int" />
<description>
Returns a TileMap layer's Y sort origin.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="get_layer_z_index" qualifiers="const">
@@ -167,6 +186,7 @@
<param index="0" name="layer" type="int" />
<description>
Returns a TileMap layer's Z-index value.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="get_layers_count" qualifiers="const">
@@ -175,13 +195,11 @@
Returns the number of layers in the TileMap.
</description>
</method>
- <method name="get_navigation_map" qualifiers="const">
+ <method name="get_navigation_map" qualifiers="const" is_deprecated="true">
<return type="RID" />
<param index="0" name="layer" type="int" />
<description>
- Returns the [NavigationServer2D] navigation map [RID] currently assigned to the specified TileMap [param layer].
- By default the TileMap uses the default [World2D] navigation map for the first TileMap layer. For each additional TileMap layer a new navigation map is created for the additional layer.
- In order to make [NavigationAgent2D] switch between TileMap layer navigation maps use [method NavigationAgent2D.set_navigation_map] with the navigation map received from [method get_navigation_map].
+ See [method get_layer_navigation_map].
</description>
</method>
<method name="get_neighbor_cell" qualifiers="const">
@@ -198,6 +216,7 @@
<param index="1" name="coords_array" type="Vector2i[]" />
<description>
Creates a new [TileMapPattern] from the given layer and set of cells.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="get_surrounding_cells">
@@ -212,6 +231,7 @@
<param index="0" name="layer" type="int" />
<description>
Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="get_used_cells_by_id" qualifiers="const">
@@ -224,9 +244,10 @@
Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. Tiles may be filtered according to their source ([param source_id]), their atlas coordinates ([param atlas_coords]) or alternative id ([param alternative_tile]).
If a parameter has it's value set to the default one, this parameter is not used to filter a cell. Thus, if all parameters have their respective default value, this method returns the same result as [method get_used_cells].
A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
- <method name="get_used_rect">
+ <method name="get_used_rect" qualifiers="const">
<return type="Rect2i" />
<description>
Returns a rectangle enclosing the used (non-empty) tiles of the map, including all layers.
@@ -237,6 +258,7 @@
<param index="0" name="layer" type="int" />
<description>
Returns if a layer is enabled.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="is_layer_y_sort_enabled" qualifiers="const">
@@ -244,6 +266,7 @@
<param index="0" name="layer" type="int" />
<description>
Returns if a layer Y-sorts its tiles.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="local_to_map" qualifiers="const">
@@ -298,6 +321,7 @@
- The atlas coordinates identifier [param atlas_coords] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]). For [TileSetScenesCollectionSource] it should always be [code]Vector2i(0, 0)[/code]),
- The alternative tile identifier [param alternative_tile] identifies a tile alternative in the atlas (if the source is a [TileSetAtlasSource]), and the scene for a [TileSetScenesCollectionSource].
If [param source_id] is set to [code]-1[/code], [param atlas_coords] to [code]Vector2i(-1, -1)[/code] or [param alternative_tile] to [code]-1[/code], the cell will be erased. An erased cell gets [b]all[/b] its identifiers automatically set to their respective invalid values, namely [code]-1[/code], [code]Vector2i(-1, -1)[/code] and [code]-1[/code].
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="set_cells_terrain_connect">
@@ -310,6 +334,7 @@
<description>
Update all the cells in the [param cells] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. If an updated cell has the same terrain as one of its neighboring cells, this function tries to join the two. This function might update neighboring tiles if needed to create correct terrain transitions.
If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
+ If [param layer] is negative, the layers are accessed from the last one.
[b]Note:[/b] To work correctly, this method requires the TileMap's TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results.
</description>
</method>
@@ -323,6 +348,7 @@
<description>
Update all the cells in the [param path] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. The function will also connect two successive cell in the path with the same terrain. This function might update neighboring tiles if needed to create correct terrain transitions.
If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
+ If [param layer] is negative, the layers are accessed from the last one.
[b]Note:[/b] To work correctly, this method requires the TileMap's TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results.
</description>
</method>
@@ -353,6 +379,17 @@
If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
+ <method name="set_layer_navigation_map">
+ <return type="void" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="map" type="RID" />
+ <description>
+ Assigns a [NavigationServer2D] navigation map [RID] to the specified TileMap [param layer].
+ By default the TileMap uses the default [World2D] navigation map for the first TileMap layer. For each additional TileMap layer a new navigation map is created for the additional layer.
+ In order to make [NavigationAgent2D] switch between TileMap layer navigation maps use [method NavigationAgent2D.set_navigation_map] with the navigation map received from [method get_layer_navigation_map].
+ If [param layer] is negative, the layers are accessed from the last one.
+ </description>
+ </method>
<method name="set_layer_y_sort_enabled">
<return type="void" />
<param index="0" name="layer" type="int" />
@@ -382,14 +419,12 @@
If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
- <method name="set_navigation_map">
+ <method name="set_navigation_map" is_deprecated="true">
<return type="void" />
<param index="0" name="layer" type="int" />
<param index="1" name="map" type="RID" />
<description>
- Assigns a [NavigationServer2D] navigation map [RID] to the specified TileMap [param layer].
- By default the TileMap uses the default [World2D] navigation map for the first TileMap layer. For each additional TileMap layer a new navigation map is created for the additional layer.
- In order to make [NavigationAgent2D] switch between TileMap layer navigation maps use [method NavigationAgent2D.set_navigation_map] with the navigation map received from [method get_navigation_map].
+ See [method set_layer_navigation_map].
</description>
</method>
<method name="set_pattern">
@@ -399,6 +434,7 @@
<param index="2" name="pattern" type="TileMapPattern" />
<description>
Paste the given [TileMapPattern] at the given [param position] and [param layer] in the tile map.
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
</methods>
diff --git a/doc/classes/TileMapPattern.xml b/doc/classes/TileMapPattern.xml
index 5d0433696d..b1b7720810 100644
--- a/doc/classes/TileMapPattern.xml
+++ b/doc/classes/TileMapPattern.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TileMapPattern" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TileMapPattern" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds a pattern to be copied from or pasted into [TileMap]s.
</brief_description>
diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml
index 7cfab52888..1193855d7c 100644
--- a/doc/classes/TileSet.xml
+++ b/doc/classes/TileSet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TileSet" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TileSet" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Tile library for tilemaps.
</brief_description>
diff --git a/doc/classes/TileSetAtlasSource.xml b/doc/classes/TileSetAtlasSource.xml
index 60861e6c86..7daabcbfee 100644
--- a/doc/classes/TileSetAtlasSource.xml
+++ b/doc/classes/TileSetAtlasSource.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TileSetAtlasSource" inherits="TileSetSource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TileSetAtlasSource" inherits="TileSetSource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exposes a 2D atlas texture as a set of tiles for a [TileSet] resource.
</brief_description>
@@ -80,6 +80,13 @@
Returns how many animation frames has the tile at coordinates [param atlas_coords].
</description>
</method>
+ <method name="get_tile_animation_mode" qualifiers="const">
+ <return type="int" enum="TileSetAtlasSource.TileAnimationMode" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <description>
+ Returns the [enum TileAnimationMode] of the tile at [param atlas_coords]. See also [method set_tile_animation_mode].
+ </description>
+ </method>
<method name="get_tile_animation_separation" qualifiers="const">
<return type="Vector2i" />
<param index="0" name="atlas_coords" type="Vector2i" />
@@ -215,6 +222,14 @@
Sets how many animation frames the tile at coordinates [param atlas_coords] has.
</description>
</method>
+ <method name="set_tile_animation_mode">
+ <return type="void" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="mode" type="int" enum="TileSetAtlasSource.TileAnimationMode" />
+ <description>
+ Sets the [enum TileAnimationMode] of the tile at [param atlas_coords] to [param mode]. See also [method get_tile_animation_mode].
+ </description>
+ </method>
<method name="set_tile_animation_separation">
<return type="void" />
<param index="0" name="atlas_coords" type="Vector2i" />
@@ -250,4 +265,15 @@
Disabling this setting might lead a small performance improvement, as generating the internal texture requires both memory and processing time when the TileSetAtlasSource resource is modified.
</member>
</members>
+ <constants>
+ <constant name="TILE_ANIMATION_MODE_DEFAULT" value="0" enum="TileAnimationMode">
+ Tile animations start at same time, looking identical.
+ </constant>
+ <constant name="TILE_ANIMATION_MODE_RANDOM_START_TIMES" value="1" enum="TileAnimationMode">
+ Tile animations start at random times, looking varied.
+ </constant>
+ <constant name="TILE_ANIMATION_MODE_MAX" value="2" enum="TileAnimationMode">
+ Represents the size of the [enum TileAnimationMode] enum.
+ </constant>
+ </constants>
</class>
diff --git a/doc/classes/TileSetScenesCollectionSource.xml b/doc/classes/TileSetScenesCollectionSource.xml
index e1a3b3e788..9d2742b844 100644
--- a/doc/classes/TileSetScenesCollectionSource.xml
+++ b/doc/classes/TileSetScenesCollectionSource.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TileSetScenesCollectionSource" inherits="TileSetSource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TileSetScenesCollectionSource" inherits="TileSetSource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exposes a set of scenes as tiles for a [TileSet] resource.
</brief_description>
diff --git a/doc/classes/TileSetSource.xml b/doc/classes/TileSetSource.xml
index 3a54584ca5..70df23324c 100644
--- a/doc/classes/TileSetSource.xml
+++ b/doc/classes/TileSetSource.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TileSetSource" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TileSetSource" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exposes a set of tiles for a [TileSet] resource.
</brief_description>
diff --git a/doc/classes/Time.xml b/doc/classes/Time.xml
index c5c505652e..8ed17f6d8a 100644
--- a/doc/classes/Time.xml
+++ b/doc/classes/Time.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Time" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Time" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton for working with time data.
</brief_description>
diff --git a/doc/classes/Timer.xml b/doc/classes/Timer.xml
index 51368d5623..03a651ad9a 100644
--- a/doc/classes/Timer.xml
+++ b/doc/classes/Timer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Timer" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Timer" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A countdown timer.
</brief_description>
diff --git a/doc/classes/TorusMesh.xml b/doc/classes/TorusMesh.xml
index f923ce263d..77aee1e07a 100644
--- a/doc/classes/TorusMesh.xml
+++ b/doc/classes/TorusMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TorusMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TorusMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Class representing a torus [PrimitiveMesh].
</brief_description>
diff --git a/doc/classes/TouchScreenButton.xml b/doc/classes/TouchScreenButton.xml
index 3af0743965..5052518583 100644
--- a/doc/classes/TouchScreenButton.xml
+++ b/doc/classes/TouchScreenButton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TouchScreenButton" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TouchScreenButton" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Button for touch screen devices for gameplay use.
</brief_description>
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index 4fde29641b..cd79987ce9 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Transform2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Transform2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2×3 matrix representing a 2D transformation.
</brief_description>
diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml
index 4134d1335f..7bca99d697 100644
--- a/doc/classes/Transform3D.xml
+++ b/doc/classes/Transform3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Transform3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Transform3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3×4 matrix representing a 3D transformation.
</brief_description>
diff --git a/doc/classes/Translation.xml b/doc/classes/Translation.xml
index 661af9dc38..194b3be854 100644
--- a/doc/classes/Translation.xml
+++ b/doc/classes/Translation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Translation" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Translation" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A language translation that maps a collection of strings to their individual translations.
</brief_description>
diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml
index 459831a4dc..3a4cd06013 100644
--- a/doc/classes/TranslationServer.xml
+++ b/doc/classes/TranslationServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TranslationServer" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TranslationServer" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
The server responsible for language translations.
</brief_description>
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index 48171349b2..a1932ba5b6 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Tree" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Tree" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control used to show a set of internal [TreeItem]s in a hierarchical structure.
</brief_description>
@@ -542,6 +542,18 @@
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
The maximum allowed width of the icon in item's cells. This limit is applied on top of the default size of the icon, but before the value set with [method TreeItem.set_icon_max_width]. The height is adjusted according to the icon's ratio.
</theme_item>
+ <theme_item name="inner_item_margin_bottom" data_type="constant" type="int" default="0">
+ The inner bottom margin of an item.
+ </theme_item>
+ <theme_item name="inner_item_margin_left" data_type="constant" type="int" default="0">
+ The inner left margin of an item.
+ </theme_item>
+ <theme_item name="inner_item_margin_right" data_type="constant" type="int" default="0">
+ The inner right margin of an item.
+ </theme_item>
+ <theme_item name="inner_item_margin_top" data_type="constant" type="int" default="0">
+ The inner top margin of an item.
+ </theme_item>
<theme_item name="item_margin" data_type="constant" type="int" default="16">
The horizontal margin at the start of an item. This is used when folding is enabled for the item.
</theme_item>
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index 559d38e5cc..865571263e 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TreeItem" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TreeItem" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An internal control for a single item inside [Tree].
</brief_description>
@@ -490,6 +490,15 @@
If [code]true[/code], disables the button at index [param button_index] in the given [param column].
</description>
</method>
+ <method name="set_button_tooltip_text">
+ <return type="void" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button_index" type="int" />
+ <param index="2" name="tooltip" type="String" />
+ <description>
+ Sets the tooltip text for the button at index [param button_index] in the given [param column].
+ </description>
+ </method>
<method name="set_cell_mode">
<return type="void" />
<param index="0" name="column" type="int" />
diff --git a/doc/classes/TriangleMesh.xml b/doc/classes/TriangleMesh.xml
index f9e62110bd..79bab0ece6 100644
--- a/doc/classes/TriangleMesh.xml
+++ b/doc/classes/TriangleMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TriangleMesh" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TriangleMesh" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Internal mesh type.
</brief_description>
diff --git a/doc/classes/TubeTrailMesh.xml b/doc/classes/TubeTrailMesh.xml
index e6d446bd60..bf16b3d16a 100644
--- a/doc/classes/TubeTrailMesh.xml
+++ b/doc/classes/TubeTrailMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TubeTrailMesh" inherits="PrimitiveMesh" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="TubeTrailMesh" inherits="PrimitiveMesh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a straight tube-shaped [PrimitiveMesh] with variable width.
</brief_description>
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index 86084716b8..f104c5f107 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Tween" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Tween" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Lightweight object used for general-purpose animation via script, using [Tweener]s.
</brief_description>
@@ -206,6 +206,7 @@
<return type="void" />
<description>
Pauses the tweening. The animation can be resumed by using [method play].
+ [b]Note:[/b] If a Tween is paused and not bound to any node, it will exist indefinitely until manually started or invalidated. If you lose a reference to such Tween, you can retrieve it using [method SceneTree.get_processed_tweens].
</description>
</method>
<method name="play">
@@ -273,6 +274,7 @@
<return type="void" />
<description>
Stops the tweening and resets the [Tween] to its initial state. This will not remove any appended [Tweener]s.
+ [b]Note:[/b] If a Tween is stopped and not bound to any node, it will exist indefinitely until manually started or invalidated. If you lose a reference to such Tween, you can retrieve it using [method SceneTree.get_processed_tweens].
</description>
</method>
<method name="tween_callback">
diff --git a/doc/classes/Tweener.xml b/doc/classes/Tweener.xml
index 6427345f59..65148e875d 100644
--- a/doc/classes/Tweener.xml
+++ b/doc/classes/Tweener.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Tweener" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Tweener" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract class for all Tweeners used by [Tween].
</brief_description>
diff --git a/doc/classes/UDPServer.xml b/doc/classes/UDPServer.xml
index 91277ee5fd..123ae399b3 100644
--- a/doc/classes/UDPServer.xml
+++ b/doc/classes/UDPServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="UDPServer" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="UDPServer" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Helper class to implement a UDP server.
</brief_description>
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index d2b0bbb0ca..50414d2580 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="UndoRedo" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="UndoRedo" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides a high-level interface for implementing undo and redo operations.
</brief_description>
diff --git a/doc/classes/VBoxContainer.xml b/doc/classes/VBoxContainer.xml
index b746a29bd0..38541859a6 100644
--- a/doc/classes/VBoxContainer.xml
+++ b/doc/classes/VBoxContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VBoxContainer" inherits="BoxContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VBoxContainer" inherits="BoxContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that arranges its child controls vertically.
</brief_description>
diff --git a/doc/classes/VFlowContainer.xml b/doc/classes/VFlowContainer.xml
index 21a8ed71ce..dcec1a58d9 100644
--- a/doc/classes/VFlowContainer.xml
+++ b/doc/classes/VFlowContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VFlowContainer" inherits="FlowContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VFlowContainer" inherits="FlowContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that arranges its child controls vertically and wraps them around at the borders.
</brief_description>
diff --git a/doc/classes/VScrollBar.xml b/doc/classes/VScrollBar.xml
index 9ecbcdef8a..7cb1a3d16d 100644
--- a/doc/classes/VScrollBar.xml
+++ b/doc/classes/VScrollBar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VScrollBar" inherits="ScrollBar" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VScrollBar" inherits="ScrollBar" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A vertical scrollbar that goes from top (min) to bottom (max).
</brief_description>
diff --git a/doc/classes/VSeparator.xml b/doc/classes/VSeparator.xml
index fcd33d7c7f..ffb4e76df8 100644
--- a/doc/classes/VSeparator.xml
+++ b/doc/classes/VSeparator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VSeparator" inherits="Separator" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VSeparator" inherits="Separator" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A vertical line used for separating other controls.
</brief_description>
diff --git a/doc/classes/VSlider.xml b/doc/classes/VSlider.xml
index 964facc45c..7475e5ff7e 100644
--- a/doc/classes/VSlider.xml
+++ b/doc/classes/VSlider.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VSlider" inherits="Slider" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VSlider" inherits="Slider" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A vertical slider that goes from bottom (min) to top (max).
</brief_description>
diff --git a/doc/classes/VSplitContainer.xml b/doc/classes/VSplitContainer.xml
index 45aba9736c..1e363d987c 100644
--- a/doc/classes/VSplitContainer.xml
+++ b/doc/classes/VSplitContainer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VSplitContainer" inherits="SplitContainer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VSplitContainer" inherits="SplitContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A container that splits two child controls vertically and provides a grabber for adjusting the split ratio.
</brief_description>
diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml
index 4f237b5c2e..dc3e25fa9b 100644
--- a/doc/classes/Variant.xml
+++ b/doc/classes/Variant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Variant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Variant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
The most important data type in Godot.
</brief_description>
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index cc406d9067..b4718d96a3 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Vector2" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Vector2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D vector using floating point coordinates.
</brief_description>
diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml
index 7f7f420afe..ccb5bb7815 100644
--- a/doc/classes/Vector2i.xml
+++ b/doc/classes/Vector2i.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Vector2i" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Vector2i" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D vector using integer coordinates.
</brief_description>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 659707987d..840e2ba61a 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Vector3" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Vector3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D vector using floating point coordinates.
</brief_description>
diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml
index b01e5bd486..90cb70f347 100644
--- a/doc/classes/Vector3i.xml
+++ b/doc/classes/Vector3i.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Vector3i" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Vector3i" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D vector using integer coordinates.
</brief_description>
diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml
index daeda011da..6f99234991 100644
--- a/doc/classes/Vector4.xml
+++ b/doc/classes/Vector4.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Vector4" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Vector4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 4D vector using floating point coordinates.
</brief_description>
diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml
index e6aa9ed720..f2eb353b5a 100644
--- a/doc/classes/Vector4i.xml
+++ b/doc/classes/Vector4i.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Vector4i" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Vector4i" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 4D vector using integer coordinates.
</brief_description>
diff --git a/doc/classes/VehicleBody3D.xml b/doc/classes/VehicleBody3D.xml
index e5e5386d81..359e84c3da 100644
--- a/doc/classes/VehicleBody3D.xml
+++ b/doc/classes/VehicleBody3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VehicleBody3D" inherits="RigidBody3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VehicleBody3D" inherits="RigidBody3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D physics body that simulates the behavior of a car.
</brief_description>
diff --git a/doc/classes/VehicleWheel3D.xml b/doc/classes/VehicleWheel3D.xml
index c4ebed84c5..9c7ba58534 100644
--- a/doc/classes/VehicleWheel3D.xml
+++ b/doc/classes/VehicleWheel3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VehicleWheel3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VehicleWheel3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D physics body for a [VehicleBody3D] that simulates the behavior of a wheel.
</brief_description>
diff --git a/doc/classes/VideoStream.xml b/doc/classes/VideoStream.xml
index 9460f819f5..600cc3f67e 100644
--- a/doc/classes/VideoStream.xml
+++ b/doc/classes/VideoStream.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStream" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VideoStream" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base resource for video streams.
</brief_description>
diff --git a/doc/classes/VideoStreamPlayback.xml b/doc/classes/VideoStreamPlayback.xml
index be3b0d4950..8b4a7f8d29 100644
--- a/doc/classes/VideoStreamPlayback.xml
+++ b/doc/classes/VideoStreamPlayback.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStreamPlayback" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VideoStreamPlayback" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Internal class used by [VideoStream] to manage playback state when played from a [VideoStreamPlayer].
</brief_description>
diff --git a/doc/classes/VideoStreamPlayer.xml b/doc/classes/VideoStreamPlayer.xml
index 6ba2e42557..19b1e20e5b 100644
--- a/doc/classes/VideoStreamPlayer.xml
+++ b/doc/classes/VideoStreamPlayer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStreamPlayer" inherits="Control" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VideoStreamPlayer" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A control used for video playback.
</brief_description>
@@ -12,6 +12,13 @@
<tutorials>
</tutorials>
<methods>
+ <method name="get_stream_length" qualifiers="const">
+ <return type="float" />
+ <description>
+ The length of the current stream, in seconds.
+ [b]Note:[/b] For [VideoStreamTheora] streams (the built-in format supported by Godot), this value will always be zero, as getting the stream length is not implemented yet. The feature may be supported by video formats implemented by a GDExtension add-on.
+ </description>
+ </method>
<method name="get_stream_name" qualifiers="const">
<return type="String" />
<description>
@@ -61,6 +68,9 @@
<member name="expand" type="bool" setter="set_expand" getter="has_expand" default="false">
If [code]true[/code], the video scales to the control size. Otherwise, the control minimum size will be automatically adjusted to match the video stream's dimensions.
</member>
+ <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false">
+ If [code]true[/code], the video restarts when it reaches its end.
+ </member>
<member name="paused" type="bool" setter="set_paused" getter="is_paused" default="false">
If [code]true[/code], the video is paused.
</member>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index e784042507..9a5e7ed6f6 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Viewport" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Viewport" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Abstract base class for viewports. Encapsulates drawing and interaction with a game world.
</brief_description>
@@ -160,8 +160,8 @@
- [method Node._input]
- [method Control._gui_input] for [Control] nodes
- [method Node._shortcut_input]
- - [method Node._unhandled_input]
- [method Node._unhandled_key_input]
+ - [method Node._unhandled_input]
If an earlier method marks the input as handled via [method set_input_as_handled], any later method in this list will not be called.
If none of the methods handle the event and [member physics_object_picking] is [code]true[/code], the event is used for physics object picking.
</description>
@@ -183,8 +183,8 @@
While this method serves a similar purpose as [method Input.parse_input_event], it does not remap the specified [param event] based on project settings like [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse].
Calling this method will propagate calls to child nodes for following methods in the given order:
- [method Node._shortcut_input]
- - [method Node._unhandled_input]
- [method Node._unhandled_key_input]
+ - [method Node._unhandled_input]
If an earlier method marks the input as handled via [method set_input_as_handled], any later method in this list will not be called.
If none of the methods handle the event and [member physics_object_picking] is [code]true[/code], the event is used for physics object picking.
[b]Note:[/b] This method doesn't propagate input events to embedded [Window]s or [SubViewport]s.
diff --git a/doc/classes/ViewportTexture.xml b/doc/classes/ViewportTexture.xml
index c7a0223f3a..ede9688ea8 100644
--- a/doc/classes/ViewportTexture.xml
+++ b/doc/classes/ViewportTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ViewportTexture" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ViewportTexture" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides the content of a [Viewport] as a dynamic texture.
</brief_description>
diff --git a/doc/classes/VisibleOnScreenEnabler2D.xml b/doc/classes/VisibleOnScreenEnabler2D.xml
index 5b70061833..9f8b07261e 100644
--- a/doc/classes/VisibleOnScreenEnabler2D.xml
+++ b/doc/classes/VisibleOnScreenEnabler2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisibleOnScreenEnabler2D" inherits="VisibleOnScreenNotifier2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisibleOnScreenEnabler2D" inherits="VisibleOnScreenNotifier2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Automatically disables another node if not visible on screen.
</brief_description>
diff --git a/doc/classes/VisibleOnScreenEnabler3D.xml b/doc/classes/VisibleOnScreenEnabler3D.xml
index c0ac2efb0d..1808953fcc 100644
--- a/doc/classes/VisibleOnScreenEnabler3D.xml
+++ b/doc/classes/VisibleOnScreenEnabler3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisibleOnScreenEnabler3D" inherits="VisibleOnScreenNotifier3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisibleOnScreenEnabler3D" inherits="VisibleOnScreenNotifier3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Enables certain nodes only when approximately visible.
</brief_description>
diff --git a/doc/classes/VisibleOnScreenNotifier2D.xml b/doc/classes/VisibleOnScreenNotifier2D.xml
index ab1661fad1..dc36e25003 100644
--- a/doc/classes/VisibleOnScreenNotifier2D.xml
+++ b/doc/classes/VisibleOnScreenNotifier2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisibleOnScreenNotifier2D" inherits="Node2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisibleOnScreenNotifier2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Detects when the node extents are visible on screen.
</brief_description>
diff --git a/doc/classes/VisibleOnScreenNotifier3D.xml b/doc/classes/VisibleOnScreenNotifier3D.xml
index 91c2423c21..ba1fa763d3 100644
--- a/doc/classes/VisibleOnScreenNotifier3D.xml
+++ b/doc/classes/VisibleOnScreenNotifier3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisibleOnScreenNotifier3D" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisibleOnScreenNotifier3D" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Detects approximately when the node is visible on screen.
</brief_description>
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
index 46454d4ecc..e67934f5c9 100644
--- a/doc/classes/VisualInstance3D.xml
+++ b/doc/classes/VisualInstance3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualInstance3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualInstance3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Parent of all visual 3D nodes.
</brief_description>
diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml
index 1feed6b8ae..bf48d80c66 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShader" inherits="Shader" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShader" inherits="Shader" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A custom shader program with a visual editor.
</brief_description>
diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml
index de8360d75c..5d147bd542 100644
--- a/doc/classes/VisualShaderNode.xml
+++ b/doc/classes/VisualShaderNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNode" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNode" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for nodes in a visual shader graph.
</brief_description>
@@ -16,6 +16,13 @@
Clears the default input ports value.
</description>
</method>
+ <method name="get_default_input_port" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="type" type="int" enum="VisualShaderNode.PortType" />
+ <description>
+ Returns the input port which should be connected by default when this node is created as a result of dragging a connection from an existing node to the empty space on the graph.
+ </description>
+ </method>
<method name="get_default_input_values" qualifiers="const">
<return type="Array" />
<description>
diff --git a/doc/classes/VisualShaderNodeBillboard.xml b/doc/classes/VisualShaderNodeBillboard.xml
index bfb2c598af..2fd31c78cb 100644
--- a/doc/classes/VisualShaderNodeBillboard.xml
+++ b/doc/classes/VisualShaderNodeBillboard.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeBillboard" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeBillboard" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A node that controls how the object faces the camera to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeBooleanConstant.xml b/doc/classes/VisualShaderNodeBooleanConstant.xml
index dcc71831ab..d32af17940 100644
--- a/doc/classes/VisualShaderNodeBooleanConstant.xml
+++ b/doc/classes/VisualShaderNodeBooleanConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeBooleanConstant" inherits="VisualShaderNodeConstant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeBooleanConstant" inherits="VisualShaderNodeConstant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A boolean constant to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeBooleanParameter.xml b/doc/classes/VisualShaderNodeBooleanParameter.xml
index 262fffb5f7..ef64c0948f 100644
--- a/doc/classes/VisualShaderNodeBooleanParameter.xml
+++ b/doc/classes/VisualShaderNodeBooleanParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeBooleanParameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeBooleanParameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A boolean parameter to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeClamp.xml b/doc/classes/VisualShaderNodeClamp.xml
index 1f30318b6a..56100f17d7 100644
--- a/doc/classes/VisualShaderNodeClamp.xml
+++ b/doc/classes/VisualShaderNodeClamp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeClamp" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeClamp" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Clamps a value within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeColorConstant.xml b/doc/classes/VisualShaderNodeColorConstant.xml
index 47dde00aee..3ed754ccda 100644
--- a/doc/classes/VisualShaderNodeColorConstant.xml
+++ b/doc/classes/VisualShaderNodeColorConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeColorConstant" inherits="VisualShaderNodeConstant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeColorConstant" inherits="VisualShaderNodeConstant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Color] constant to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeColorFunc.xml b/doc/classes/VisualShaderNodeColorFunc.xml
index 5e16fc69de..edb5238325 100644
--- a/doc/classes/VisualShaderNodeColorFunc.xml
+++ b/doc/classes/VisualShaderNodeColorFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeColorFunc" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeColorFunc" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Color] function to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeColorOp.xml b/doc/classes/VisualShaderNodeColorOp.xml
index 3eea7a62a8..b5454da1f9 100644
--- a/doc/classes/VisualShaderNodeColorOp.xml
+++ b/doc/classes/VisualShaderNodeColorOp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeColorOp" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeColorOp" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Color] operator to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeColorParameter.xml b/doc/classes/VisualShaderNodeColorParameter.xml
index 9f9ad535c4..49ceec2648 100644
--- a/doc/classes/VisualShaderNodeColorParameter.xml
+++ b/doc/classes/VisualShaderNodeColorParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeColorParameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeColorParameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Color] parameter to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeComment.xml b/doc/classes/VisualShaderNodeComment.xml
index 064b90464e..b4063409b9 100644
--- a/doc/classes/VisualShaderNodeComment.xml
+++ b/doc/classes/VisualShaderNodeComment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeComment" inherits="VisualShaderNodeResizableBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeComment" inherits="VisualShaderNodeResizableBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A comment node to be placed on visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeCompare.xml b/doc/classes/VisualShaderNodeCompare.xml
index 855a40778d..b566ca62f3 100644
--- a/doc/classes/VisualShaderNodeCompare.xml
+++ b/doc/classes/VisualShaderNodeCompare.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeCompare" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeCompare" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A comparison function for common types within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeConstant.xml b/doc/classes/VisualShaderNodeConstant.xml
index 883fa16c89..1fa6a53f9b 100644
--- a/doc/classes/VisualShaderNodeConstant.xml
+++ b/doc/classes/VisualShaderNodeConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeConstant" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeConstant" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A base type for the constants within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeCubemap.xml b/doc/classes/VisualShaderNodeCubemap.xml
index 413fa622ec..8fc98e24cc 100644
--- a/doc/classes/VisualShaderNodeCubemap.xml
+++ b/doc/classes/VisualShaderNodeCubemap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeCubemap" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeCubemap" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Cubemap] sampling node to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeCubemapParameter.xml b/doc/classes/VisualShaderNodeCubemapParameter.xml
index 8ff0d05c3e..0b2d87c13d 100644
--- a/doc/classes/VisualShaderNodeCubemapParameter.xml
+++ b/doc/classes/VisualShaderNodeCubemapParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeCubemapParameter" inherits="VisualShaderNodeTextureParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeCubemapParameter" inherits="VisualShaderNodeTextureParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Cubemap] parameter node to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeCurveTexture.xml b/doc/classes/VisualShaderNodeCurveTexture.xml
index ad21452202..d2012750b5 100644
--- a/doc/classes/VisualShaderNodeCurveTexture.xml
+++ b/doc/classes/VisualShaderNodeCurveTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeCurveTexture" inherits="VisualShaderNodeResizableBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeCurveTexture" inherits="VisualShaderNodeResizableBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs a [CurveTexture] lookup within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeCurveXYZTexture.xml b/doc/classes/VisualShaderNodeCurveXYZTexture.xml
index 780e3a78a2..83e3240d3a 100644
--- a/doc/classes/VisualShaderNodeCurveXYZTexture.xml
+++ b/doc/classes/VisualShaderNodeCurveXYZTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeCurveXYZTexture" inherits="VisualShaderNodeResizableBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeCurveXYZTexture" inherits="VisualShaderNodeResizableBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs a [CurveXYZTexture] lookup within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeCustom.xml b/doc/classes/VisualShaderNodeCustom.xml
index 67023c475d..8a90d5dd0f 100644
--- a/doc/classes/VisualShaderNodeCustom.xml
+++ b/doc/classes/VisualShaderNodeCustom.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeCustom" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeCustom" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Virtual class to define custom [VisualShaderNode]s for use in the Visual Shader Editor.
</brief_description>
@@ -37,6 +37,14 @@
Defining this method is [b]required[/b].
</description>
</method>
+ <method name="_get_default_input_port" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="type" type="int" enum="VisualShaderNode.PortType" />
+ <description>
+ Override this method to define the input port which should be connected by default when this node is created as a result of dragging a connection from an existing node to the empty space on the graph.
+ Defining this method is [b]optional[/b]. If not overridden, the connection will be created to the first valid port.
+ </description>
+ </method>
<method name="_get_description" qualifiers="virtual const">
<return type="String" />
<description>
diff --git a/doc/classes/VisualShaderNodeDerivativeFunc.xml b/doc/classes/VisualShaderNodeDerivativeFunc.xml
index 520314d733..6dc38a00ac 100644
--- a/doc/classes/VisualShaderNodeDerivativeFunc.xml
+++ b/doc/classes/VisualShaderNodeDerivativeFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeDerivativeFunc" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeDerivativeFunc" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Calculates a derivative within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeDeterminant.xml b/doc/classes/VisualShaderNodeDeterminant.xml
index a26370223e..cbb43edfef 100644
--- a/doc/classes/VisualShaderNodeDeterminant.xml
+++ b/doc/classes/VisualShaderNodeDeterminant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeDeterminant" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeDeterminant" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Calculates the determinant of a [Transform3D] within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeDistanceFade.xml b/doc/classes/VisualShaderNodeDistanceFade.xml
index 4d1b33ecd7..69381c0f0f 100644
--- a/doc/classes/VisualShaderNodeDistanceFade.xml
+++ b/doc/classes/VisualShaderNodeDistanceFade.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeDistanceFade" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeDistanceFade" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node representing distance fade effect.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeDotProduct.xml b/doc/classes/VisualShaderNodeDotProduct.xml
index 27c2871e1c..f9c93831fc 100644
--- a/doc/classes/VisualShaderNodeDotProduct.xml
+++ b/doc/classes/VisualShaderNodeDotProduct.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeDotProduct" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeDotProduct" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Calculates a dot product of two vectors within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeExpression.xml b/doc/classes/VisualShaderNodeExpression.xml
index 94e9cd91c9..c916aecc50 100644
--- a/doc/classes/VisualShaderNodeExpression.xml
+++ b/doc/classes/VisualShaderNodeExpression.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeExpression" inherits="VisualShaderNodeGroupBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeExpression" inherits="VisualShaderNodeGroupBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A custom visual shader graph expression written in Godot Shading Language.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeFaceForward.xml b/doc/classes/VisualShaderNodeFaceForward.xml
index 60b8ab8de0..b63602e388 100644
--- a/doc/classes/VisualShaderNodeFaceForward.xml
+++ b/doc/classes/VisualShaderNodeFaceForward.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeFaceForward" inherits="VisualShaderNodeVectorBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeFaceForward" inherits="VisualShaderNodeVectorBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Returns the vector that points in the same direction as a reference vector within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeFloatConstant.xml b/doc/classes/VisualShaderNodeFloatConstant.xml
index ae7a006977..9b57a9a240 100644
--- a/doc/classes/VisualShaderNodeFloatConstant.xml
+++ b/doc/classes/VisualShaderNodeFloatConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeFloatConstant" inherits="VisualShaderNodeConstant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeFloatConstant" inherits="VisualShaderNodeConstant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A scalar floating-point constant to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeFloatFunc.xml b/doc/classes/VisualShaderNodeFloatFunc.xml
index cbaccebc1d..8cde07bfcc 100644
--- a/doc/classes/VisualShaderNodeFloatFunc.xml
+++ b/doc/classes/VisualShaderNodeFloatFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeFloatFunc" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeFloatFunc" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A scalar floating-point function to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeFloatOp.xml b/doc/classes/VisualShaderNodeFloatOp.xml
index 1f26471f7e..de95a3f174 100644
--- a/doc/classes/VisualShaderNodeFloatOp.xml
+++ b/doc/classes/VisualShaderNodeFloatOp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeFloatOp" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeFloatOp" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A floating-point scalar operator to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeFloatParameter.xml b/doc/classes/VisualShaderNodeFloatParameter.xml
index 933e12d84d..a4a76644a6 100644
--- a/doc/classes/VisualShaderNodeFloatParameter.xml
+++ b/doc/classes/VisualShaderNodeFloatParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeFloatParameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeFloatParameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A scalar float parameter to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeFresnel.xml b/doc/classes/VisualShaderNodeFresnel.xml
index 4bfbc126d6..4d050faeb3 100644
--- a/doc/classes/VisualShaderNodeFresnel.xml
+++ b/doc/classes/VisualShaderNodeFresnel.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeFresnel" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeFresnel" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A Fresnel effect to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeGlobalExpression.xml b/doc/classes/VisualShaderNodeGlobalExpression.xml
index 50df5abfb5..69204373c2 100644
--- a/doc/classes/VisualShaderNodeGlobalExpression.xml
+++ b/doc/classes/VisualShaderNodeGlobalExpression.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeGlobalExpression" inherits="VisualShaderNodeExpression" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeGlobalExpression" inherits="VisualShaderNodeExpression" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A custom global visual shader graph expression written in Godot Shading Language.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeGroupBase.xml b/doc/classes/VisualShaderNodeGroupBase.xml
index 22f6150207..a1cee7193e 100644
--- a/doc/classes/VisualShaderNodeGroupBase.xml
+++ b/doc/classes/VisualShaderNodeGroupBase.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeGroupBase" inherits="VisualShaderNodeResizableBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeGroupBase" inherits="VisualShaderNodeResizableBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for a family of nodes with variable number of input and output ports within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeIf.xml b/doc/classes/VisualShaderNodeIf.xml
index 71f2c4e567..5fc9a0cdf4 100644
--- a/doc/classes/VisualShaderNodeIf.xml
+++ b/doc/classes/VisualShaderNodeIf.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeIf" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeIf" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Compares two floating-point numbers in order to return a required vector within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeInput.xml b/doc/classes/VisualShaderNodeInput.xml
index b4e2f22c54..79ed8dde9e 100644
--- a/doc/classes/VisualShaderNodeInput.xml
+++ b/doc/classes/VisualShaderNodeInput.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeInput" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeInput" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents the input shader parameter within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeIntConstant.xml b/doc/classes/VisualShaderNodeIntConstant.xml
index 47604e411c..bde1aaab5d 100644
--- a/doc/classes/VisualShaderNodeIntConstant.xml
+++ b/doc/classes/VisualShaderNodeIntConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeIntConstant" inherits="VisualShaderNodeConstant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeIntConstant" inherits="VisualShaderNodeConstant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A scalar integer constant to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeIntFunc.xml b/doc/classes/VisualShaderNodeIntFunc.xml
index 6064465ea3..51e3faecd3 100644
--- a/doc/classes/VisualShaderNodeIntFunc.xml
+++ b/doc/classes/VisualShaderNodeIntFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeIntFunc" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeIntFunc" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A scalar integer function to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeIntOp.xml b/doc/classes/VisualShaderNodeIntOp.xml
index b2d147def0..1aef337e01 100644
--- a/doc/classes/VisualShaderNodeIntOp.xml
+++ b/doc/classes/VisualShaderNodeIntOp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeIntOp" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeIntOp" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An integer scalar operator to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeIntParameter.xml b/doc/classes/VisualShaderNodeIntParameter.xml
index 4cfcc3b229..ed72584b1b 100644
--- a/doc/classes/VisualShaderNodeIntParameter.xml
+++ b/doc/classes/VisualShaderNodeIntParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeIntParameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeIntParameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node for shader parameter (uniform) of type [int].
</brief_description>
diff --git a/doc/classes/VisualShaderNodeIs.xml b/doc/classes/VisualShaderNodeIs.xml
index a43fcf9fcb..35832f448f 100644
--- a/doc/classes/VisualShaderNodeIs.xml
+++ b/doc/classes/VisualShaderNodeIs.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeIs" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeIs" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A boolean comparison operator to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeLinearSceneDepth.xml b/doc/classes/VisualShaderNodeLinearSceneDepth.xml
index 3f554dfbc0..f035ba7898 100644
--- a/doc/classes/VisualShaderNodeLinearSceneDepth.xml
+++ b/doc/classes/VisualShaderNodeLinearSceneDepth.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeLinearSceneDepth" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeLinearSceneDepth" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that returns the depth value of the DEPTH_TEXTURE node in a linear space.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeMix.xml b/doc/classes/VisualShaderNodeMix.xml
index 05a3df868a..d4444c888d 100644
--- a/doc/classes/VisualShaderNodeMix.xml
+++ b/doc/classes/VisualShaderNodeMix.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeMix" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeMix" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Linearly interpolates between two values within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeMultiplyAdd.xml b/doc/classes/VisualShaderNodeMultiplyAdd.xml
index d93d8d5c81..9f622acb87 100644
--- a/doc/classes/VisualShaderNodeMultiplyAdd.xml
+++ b/doc/classes/VisualShaderNodeMultiplyAdd.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeMultiplyAdd" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeMultiplyAdd" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs a fused multiply-add operation within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeOuterProduct.xml b/doc/classes/VisualShaderNodeOuterProduct.xml
index f42f9b35b7..1e8d2579a2 100644
--- a/doc/classes/VisualShaderNodeOuterProduct.xml
+++ b/doc/classes/VisualShaderNodeOuterProduct.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeOuterProduct" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeOuterProduct" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Calculates an outer product of two vectors within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeOutput.xml b/doc/classes/VisualShaderNodeOutput.xml
index ebc2997a57..6730f96d73 100644
--- a/doc/classes/VisualShaderNodeOutput.xml
+++ b/doc/classes/VisualShaderNodeOutput.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeOutput" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeOutput" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents the output shader parameters within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParameter.xml b/doc/classes/VisualShaderNodeParameter.xml
index 3bf8701bd6..cc1c82b408 100644
--- a/doc/classes/VisualShaderNodeParameter.xml
+++ b/doc/classes/VisualShaderNodeParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParameter" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParameter" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A base type for the parameters within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParameterRef.xml b/doc/classes/VisualShaderNodeParameterRef.xml
index d9efcae1f1..ffd8ce68aa 100644
--- a/doc/classes/VisualShaderNodeParameterRef.xml
+++ b/doc/classes/VisualShaderNodeParameterRef.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParameterRef" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParameterRef" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A reference to an existing [VisualShaderNodeParameter].
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleAccelerator.xml b/doc/classes/VisualShaderNodeParticleAccelerator.xml
index 6525d8deaa..0907525535 100644
--- a/doc/classes/VisualShaderNodeParticleAccelerator.xml
+++ b/doc/classes/VisualShaderNodeParticleAccelerator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleAccelerator" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleAccelerator" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that accelerates particles.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleBoxEmitter.xml b/doc/classes/VisualShaderNodeParticleBoxEmitter.xml
index db861984a6..8d986969dd 100644
--- a/doc/classes/VisualShaderNodeParticleBoxEmitter.xml
+++ b/doc/classes/VisualShaderNodeParticleBoxEmitter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleBoxEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleBoxEmitter" inherits="VisualShaderNodeParticleEmitter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that makes particles emitted in a box shape.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleConeVelocity.xml b/doc/classes/VisualShaderNodeParticleConeVelocity.xml
index c3af17cfee..a49316e314 100644
--- a/doc/classes/VisualShaderNodeParticleConeVelocity.xml
+++ b/doc/classes/VisualShaderNodeParticleConeVelocity.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleConeVelocity" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleConeVelocity" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that makes particles move in a cone shape.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleEmit.xml b/doc/classes/VisualShaderNodeParticleEmit.xml
index 73b3b9bae0..c8ad642795 100644
--- a/doc/classes/VisualShaderNodeParticleEmit.xml
+++ b/doc/classes/VisualShaderNodeParticleEmit.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleEmit" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleEmit" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that forces to emit a particle from a sub-emitter.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleEmitter.xml b/doc/classes/VisualShaderNodeParticleEmitter.xml
index aa708f1b7e..a56e15074f 100644
--- a/doc/classes/VisualShaderNodeParticleEmitter.xml
+++ b/doc/classes/VisualShaderNodeParticleEmitter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleEmitter" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleEmitter" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A base class for particle emitters.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleMeshEmitter.xml b/doc/classes/VisualShaderNodeParticleMeshEmitter.xml
index fe3c3c8d95..e5f34bbc73 100644
--- a/doc/classes/VisualShaderNodeParticleMeshEmitter.xml
+++ b/doc/classes/VisualShaderNodeParticleMeshEmitter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleMeshEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleMeshEmitter" inherits="VisualShaderNodeParticleEmitter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that makes particles emitted in a shape defined by a [Mesh].
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml b/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml
index 02690941ba..5e7d3f3dd2 100644
--- a/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml
+++ b/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleMultiplyByAxisAngle" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleMultiplyByAxisAngle" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader helper node for multiplying position and rotation of particles.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleOutput.xml b/doc/classes/VisualShaderNodeParticleOutput.xml
index a9dcc0da50..d6dc88ba33 100644
--- a/doc/classes/VisualShaderNodeParticleOutput.xml
+++ b/doc/classes/VisualShaderNodeParticleOutput.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleOutput" inherits="VisualShaderNodeOutput" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleOutput" inherits="VisualShaderNodeOutput" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Visual shader node that defines output values for particle emitting.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleRandomness.xml b/doc/classes/VisualShaderNodeParticleRandomness.xml
index 2b95ee9f46..406b1944de 100644
--- a/doc/classes/VisualShaderNodeParticleRandomness.xml
+++ b/doc/classes/VisualShaderNodeParticleRandomness.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleRandomness" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleRandomness" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Visual shader node for randomizing particle values.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleRingEmitter.xml b/doc/classes/VisualShaderNodeParticleRingEmitter.xml
index d634272226..623f153f73 100644
--- a/doc/classes/VisualShaderNodeParticleRingEmitter.xml
+++ b/doc/classes/VisualShaderNodeParticleRingEmitter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleRingEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleRingEmitter" inherits="VisualShaderNodeParticleEmitter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that makes particles emitted in a ring shape.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeParticleSphereEmitter.xml b/doc/classes/VisualShaderNodeParticleSphereEmitter.xml
index 9eb9d7f8e2..dea99a1322 100644
--- a/doc/classes/VisualShaderNodeParticleSphereEmitter.xml
+++ b/doc/classes/VisualShaderNodeParticleSphereEmitter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeParticleSphereEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeParticleSphereEmitter" inherits="VisualShaderNodeParticleEmitter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that makes particles emitted in a sphere shape.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeProximityFade.xml b/doc/classes/VisualShaderNodeProximityFade.xml
index 6f9edb6778..70ae8e7ea3 100644
--- a/doc/classes/VisualShaderNodeProximityFade.xml
+++ b/doc/classes/VisualShaderNodeProximityFade.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeProximityFade" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeProximityFade" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node representing proximity fade effect.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeRandomRange.xml b/doc/classes/VisualShaderNodeRandomRange.xml
index 41b16157d9..c848d9ba78 100644
--- a/doc/classes/VisualShaderNodeRandomRange.xml
+++ b/doc/classes/VisualShaderNodeRandomRange.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeRandomRange" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeRandomRange" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that generates a pseudo-random scalar.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeRemap.xml b/doc/classes/VisualShaderNodeRemap.xml
index 5517b60f5e..102672ff60 100644
--- a/doc/classes/VisualShaderNodeRemap.xml
+++ b/doc/classes/VisualShaderNodeRemap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeRemap" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeRemap" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node for remap function.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeResizableBase.xml b/doc/classes/VisualShaderNodeResizableBase.xml
index c3fb7cb535..14058d1ade 100644
--- a/doc/classes/VisualShaderNodeResizableBase.xml
+++ b/doc/classes/VisualShaderNodeResizableBase.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeResizableBase" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeResizableBase" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for resizable nodes in a visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeRotationByAxis.xml b/doc/classes/VisualShaderNodeRotationByAxis.xml
new file mode 100644
index 0000000000..8a4fbc89d8
--- /dev/null
+++ b/doc/classes/VisualShaderNodeRotationByAxis.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeRotationByAxis" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ A visual shader node that modifies the rotation of the object using a rotation matrix.
+ </brief_description>
+ <description>
+ RotationByAxis node will transform the vertices of a mesh with specified axis and angle in radians. It can be used to rotate an object in an arbitrary axis.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeSDFRaymarch.xml b/doc/classes/VisualShaderNodeSDFRaymarch.xml
index c92fdc3587..ad202320d5 100644
--- a/doc/classes/VisualShaderNodeSDFRaymarch.xml
+++ b/doc/classes/VisualShaderNodeSDFRaymarch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeSDFRaymarch" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeSDFRaymarch" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
SDF raymarching algorithm to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeSDFToScreenUV.xml b/doc/classes/VisualShaderNodeSDFToScreenUV.xml
index 7cc45d79cb..54df82ef4c 100644
--- a/doc/classes/VisualShaderNodeSDFToScreenUV.xml
+++ b/doc/classes/VisualShaderNodeSDFToScreenUV.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeSDFToScreenUV" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeSDFToScreenUV" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A function to convert an SDF (signed-distance field) to screen UV, to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeSample3D.xml b/doc/classes/VisualShaderNodeSample3D.xml
index e0424fd7e2..de76b02557 100644
--- a/doc/classes/VisualShaderNodeSample3D.xml
+++ b/doc/classes/VisualShaderNodeSample3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeSample3D" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeSample3D" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A base node for nodes which samples 3D textures in the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeScreenNormalWorldSpace.xml b/doc/classes/VisualShaderNodeScreenNormalWorldSpace.xml
new file mode 100644
index 0000000000..ccffb62138
--- /dev/null
+++ b/doc/classes/VisualShaderNodeScreenNormalWorldSpace.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeScreenNormalWorldSpace" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ A visual shader node that unpacks the screen normal texture in World Space.
+ </brief_description>
+ <description>
+ The ScreenNormalWorldSpace node allows to create outline effects.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeScreenUVToSDF.xml b/doc/classes/VisualShaderNodeScreenUVToSDF.xml
index 5bc4fa8c78..81be77178a 100644
--- a/doc/classes/VisualShaderNodeScreenUVToSDF.xml
+++ b/doc/classes/VisualShaderNodeScreenUVToSDF.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeScreenUVToSDF" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeScreenUVToSDF" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A function to convert screen UV to an SDF (signed-distance field), to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeSmoothStep.xml b/doc/classes/VisualShaderNodeSmoothStep.xml
index 5fd3b1a242..ec1303ce95 100644
--- a/doc/classes/VisualShaderNodeSmoothStep.xml
+++ b/doc/classes/VisualShaderNodeSmoothStep.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeSmoothStep" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeSmoothStep" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Calculates a SmoothStep function within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeStep.xml b/doc/classes/VisualShaderNodeStep.xml
index a721c49daf..febc960b8c 100644
--- a/doc/classes/VisualShaderNodeStep.xml
+++ b/doc/classes/VisualShaderNodeStep.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeStep" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeStep" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Calculates a Step function within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeSwitch.xml b/doc/classes/VisualShaderNodeSwitch.xml
index 1d29a332f7..9b9266c478 100644
--- a/doc/classes/VisualShaderNodeSwitch.xml
+++ b/doc/classes/VisualShaderNodeSwitch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeSwitch" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeSwitch" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A selector function for use within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTexture.xml b/doc/classes/VisualShaderNodeTexture.xml
index 6e379d52e7..5b38683eba 100644
--- a/doc/classes/VisualShaderNodeTexture.xml
+++ b/doc/classes/VisualShaderNodeTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTexture" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTexture" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs a 2D texture lookup within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTexture2DArray.xml b/doc/classes/VisualShaderNodeTexture2DArray.xml
index ec3711ac66..8852cb7cb4 100644
--- a/doc/classes/VisualShaderNodeTexture2DArray.xml
+++ b/doc/classes/VisualShaderNodeTexture2DArray.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTexture2DArray" inherits="VisualShaderNodeSample3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTexture2DArray" inherits="VisualShaderNodeSample3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D texture uniform array to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTexture2DArrayParameter.xml b/doc/classes/VisualShaderNodeTexture2DArrayParameter.xml
index 1f6068b6b4..8da859958a 100644
--- a/doc/classes/VisualShaderNodeTexture2DArrayParameter.xml
+++ b/doc/classes/VisualShaderNodeTexture2DArrayParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTexture2DArrayParameter" inherits="VisualShaderNodeTextureParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTexture2DArrayParameter" inherits="VisualShaderNodeTextureParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node for shader parameter (uniform) of type [Texture2DArray].
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTexture2DParameter.xml b/doc/classes/VisualShaderNodeTexture2DParameter.xml
index 316e672d80..39290e6b2a 100644
--- a/doc/classes/VisualShaderNodeTexture2DParameter.xml
+++ b/doc/classes/VisualShaderNodeTexture2DParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTexture2DParameter" inherits="VisualShaderNodeTextureParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTexture2DParameter" inherits="VisualShaderNodeTextureParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides a 2D texture parameter within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTexture3D.xml b/doc/classes/VisualShaderNodeTexture3D.xml
index 2cbd54fb4e..b6cf18e868 100644
--- a/doc/classes/VisualShaderNodeTexture3D.xml
+++ b/doc/classes/VisualShaderNodeTexture3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTexture3D" inherits="VisualShaderNodeSample3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTexture3D" inherits="VisualShaderNodeSample3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs a 3D texture lookup within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTexture3DParameter.xml b/doc/classes/VisualShaderNodeTexture3DParameter.xml
index 6caffaece2..ceab1834d5 100644
--- a/doc/classes/VisualShaderNodeTexture3DParameter.xml
+++ b/doc/classes/VisualShaderNodeTexture3DParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTexture3DParameter" inherits="VisualShaderNodeTextureParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTexture3DParameter" inherits="VisualShaderNodeTextureParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides a 3D texture parameter within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTextureParameter.xml b/doc/classes/VisualShaderNodeTextureParameter.xml
index 412c1b4745..79a0657156 100644
--- a/doc/classes/VisualShaderNodeTextureParameter.xml
+++ b/doc/classes/VisualShaderNodeTextureParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTextureParameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTextureParameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs a uniform texture lookup within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTextureParameterTriplanar.xml b/doc/classes/VisualShaderNodeTextureParameterTriplanar.xml
index ff045b190a..95f2f01652 100644
--- a/doc/classes/VisualShaderNodeTextureParameterTriplanar.xml
+++ b/doc/classes/VisualShaderNodeTextureParameterTriplanar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTextureParameterTriplanar" inherits="VisualShaderNodeTextureParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTextureParameterTriplanar" inherits="VisualShaderNodeTextureParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs a uniform texture lookup with triplanar within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTextureSDF.xml b/doc/classes/VisualShaderNodeTextureSDF.xml
index 676f9e01a7..ead987e172 100644
--- a/doc/classes/VisualShaderNodeTextureSDF.xml
+++ b/doc/classes/VisualShaderNodeTextureSDF.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTextureSDF" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTextureSDF" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs an SDF (signed-distance field) texture lookup within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTextureSDFNormal.xml b/doc/classes/VisualShaderNodeTextureSDFNormal.xml
index 5b999ff191..70ce525dba 100644
--- a/doc/classes/VisualShaderNodeTextureSDFNormal.xml
+++ b/doc/classes/VisualShaderNodeTextureSDFNormal.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTextureSDFNormal" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTextureSDFNormal" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs an SDF (signed-distance field) normal texture lookup within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTransformCompose.xml b/doc/classes/VisualShaderNodeTransformCompose.xml
index 7955210fab..f2250544a4 100644
--- a/doc/classes/VisualShaderNodeTransformCompose.xml
+++ b/doc/classes/VisualShaderNodeTransformCompose.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTransformCompose" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTransformCompose" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Composes a [Transform3D] from four [Vector3]s within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTransformConstant.xml b/doc/classes/VisualShaderNodeTransformConstant.xml
index c6ea1c5cc6..ed3f039a83 100644
--- a/doc/classes/VisualShaderNodeTransformConstant.xml
+++ b/doc/classes/VisualShaderNodeTransformConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTransformConstant" inherits="VisualShaderNodeConstant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTransformConstant" inherits="VisualShaderNodeConstant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Transform3D] constant for use within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTransformDecompose.xml b/doc/classes/VisualShaderNodeTransformDecompose.xml
index 8f5647807b..fc4e3151da 100644
--- a/doc/classes/VisualShaderNodeTransformDecompose.xml
+++ b/doc/classes/VisualShaderNodeTransformDecompose.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTransformDecompose" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTransformDecompose" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Decomposes a [Transform3D] into four [Vector3]s within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTransformFunc.xml b/doc/classes/VisualShaderNodeTransformFunc.xml
index 8b48ecfeba..50070c8725 100644
--- a/doc/classes/VisualShaderNodeTransformFunc.xml
+++ b/doc/classes/VisualShaderNodeTransformFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTransformFunc" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTransformFunc" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Computes a [Transform3D] function within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTransformOp.xml b/doc/classes/VisualShaderNodeTransformOp.xml
index 22895a671d..a6ada4b07e 100644
--- a/doc/classes/VisualShaderNodeTransformOp.xml
+++ b/doc/classes/VisualShaderNodeTransformOp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTransformOp" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTransformOp" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Transform3D] operator to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTransformParameter.xml b/doc/classes/VisualShaderNodeTransformParameter.xml
index e629582472..9927ec30fe 100644
--- a/doc/classes/VisualShaderNodeTransformParameter.xml
+++ b/doc/classes/VisualShaderNodeTransformParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTransformParameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTransformParameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Transform3D] parameter for use within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTransformVecMult.xml b/doc/classes/VisualShaderNodeTransformVecMult.xml
index 262b15fc02..100bc6645e 100644
--- a/doc/classes/VisualShaderNodeTransformVecMult.xml
+++ b/doc/classes/VisualShaderNodeTransformVecMult.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTransformVecMult" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTransformVecMult" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Multiplies a [Transform3D] and a [Vector3] within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeUIntConstant.xml b/doc/classes/VisualShaderNodeUIntConstant.xml
index 889b0e9a8a..a5b82ea5a9 100644
--- a/doc/classes/VisualShaderNodeUIntConstant.xml
+++ b/doc/classes/VisualShaderNodeUIntConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeUIntConstant" inherits="VisualShaderNodeConstant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeUIntConstant" inherits="VisualShaderNodeConstant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An unsigned scalar integer constant to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeUIntFunc.xml b/doc/classes/VisualShaderNodeUIntFunc.xml
index 71d1dc7fba..8f26060a46 100644
--- a/doc/classes/VisualShaderNodeUIntFunc.xml
+++ b/doc/classes/VisualShaderNodeUIntFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeUIntFunc" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeUIntFunc" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An unsigned scalar integer function to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeUIntOp.xml b/doc/classes/VisualShaderNodeUIntOp.xml
index bdecf722d9..a8c3586cc8 100644
--- a/doc/classes/VisualShaderNodeUIntOp.xml
+++ b/doc/classes/VisualShaderNodeUIntOp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeUIntOp" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeUIntOp" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An unsigned integer scalar operator to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeUIntParameter.xml b/doc/classes/VisualShaderNodeUIntParameter.xml
index 11e32a3b3a..ebdfe032f0 100644
--- a/doc/classes/VisualShaderNodeUIntParameter.xml
+++ b/doc/classes/VisualShaderNodeUIntParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeUIntParameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeUIntParameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node for shader parameter (uniform) of type unsigned [int].
</brief_description>
diff --git a/doc/classes/VisualShaderNodeUVFunc.xml b/doc/classes/VisualShaderNodeUVFunc.xml
index f79f55d67a..8ba4b3a1d8 100644
--- a/doc/classes/VisualShaderNodeUVFunc.xml
+++ b/doc/classes/VisualShaderNodeUVFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeUVFunc" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeUVFunc" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Contains functions to modify texture coordinates ([code]uv[/code]) to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeUVPolarCoord.xml b/doc/classes/VisualShaderNodeUVPolarCoord.xml
index d6b617c5b2..8edb3ec51f 100644
--- a/doc/classes/VisualShaderNodeUVPolarCoord.xml
+++ b/doc/classes/VisualShaderNodeUVPolarCoord.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeUVPolarCoord" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeUVPolarCoord" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that modifies the texture UV using polar coordinates.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVarying.xml b/doc/classes/VisualShaderNodeVarying.xml
index d6a90cbf8f..20f15b417e 100644
--- a/doc/classes/VisualShaderNodeVarying.xml
+++ b/doc/classes/VisualShaderNodeVarying.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVarying" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVarying" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that represents a "varying" shader value.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVaryingGetter.xml b/doc/classes/VisualShaderNodeVaryingGetter.xml
index 6304389c45..5e050fb04c 100644
--- a/doc/classes/VisualShaderNodeVaryingGetter.xml
+++ b/doc/classes/VisualShaderNodeVaryingGetter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVaryingGetter" inherits="VisualShaderNodeVarying" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVaryingGetter" inherits="VisualShaderNodeVarying" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that gets a value of a varying.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVaryingSetter.xml b/doc/classes/VisualShaderNodeVaryingSetter.xml
index 3d6be0fae0..fbb620ccbd 100644
--- a/doc/classes/VisualShaderNodeVaryingSetter.xml
+++ b/doc/classes/VisualShaderNodeVaryingSetter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVaryingSetter" inherits="VisualShaderNodeVarying" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVaryingSetter" inherits="VisualShaderNodeVarying" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A visual shader node that sets a value of a varying.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVec2Constant.xml b/doc/classes/VisualShaderNodeVec2Constant.xml
index 9292e61279..d2e7dc9c1d 100644
--- a/doc/classes/VisualShaderNodeVec2Constant.xml
+++ b/doc/classes/VisualShaderNodeVec2Constant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVec2Constant" inherits="VisualShaderNodeConstant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVec2Constant" inherits="VisualShaderNodeConstant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Vector2] constant to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVec2Parameter.xml b/doc/classes/VisualShaderNodeVec2Parameter.xml
index ac81a58531..2e939d3823 100644
--- a/doc/classes/VisualShaderNodeVec2Parameter.xml
+++ b/doc/classes/VisualShaderNodeVec2Parameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVec2Parameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVec2Parameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Vector2] parameter to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVec3Constant.xml b/doc/classes/VisualShaderNodeVec3Constant.xml
index d6792b3b3e..d8e0c3f664 100644
--- a/doc/classes/VisualShaderNodeVec3Constant.xml
+++ b/doc/classes/VisualShaderNodeVec3Constant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVec3Constant" inherits="VisualShaderNodeConstant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVec3Constant" inherits="VisualShaderNodeConstant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Vector3] constant to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVec3Parameter.xml b/doc/classes/VisualShaderNodeVec3Parameter.xml
index e7455ccb22..f94ce329c7 100644
--- a/doc/classes/VisualShaderNodeVec3Parameter.xml
+++ b/doc/classes/VisualShaderNodeVec3Parameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVec3Parameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVec3Parameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [Vector3] parameter to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVec4Constant.xml b/doc/classes/VisualShaderNodeVec4Constant.xml
index f5505db27b..93d8c89b34 100644
--- a/doc/classes/VisualShaderNodeVec4Constant.xml
+++ b/doc/classes/VisualShaderNodeVec4Constant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVec4Constant" inherits="VisualShaderNodeConstant" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVec4Constant" inherits="VisualShaderNodeConstant" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 4D vector constant to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVec4Parameter.xml b/doc/classes/VisualShaderNodeVec4Parameter.xml
index 26d75fbd0e..e4153beab6 100644
--- a/doc/classes/VisualShaderNodeVec4Parameter.xml
+++ b/doc/classes/VisualShaderNodeVec4Parameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVec4Parameter" inherits="VisualShaderNodeParameter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVec4Parameter" inherits="VisualShaderNodeParameter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 4D vector parameter to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVectorBase.xml b/doc/classes/VisualShaderNodeVectorBase.xml
index 6a4d1f5d44..dee05a9729 100644
--- a/doc/classes/VisualShaderNodeVectorBase.xml
+++ b/doc/classes/VisualShaderNodeVectorBase.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVectorBase" inherits="VisualShaderNode" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVectorBase" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A base type for the nodes that perform vector operations within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVectorCompose.xml b/doc/classes/VisualShaderNodeVectorCompose.xml
index feba717055..8f25c8f3c2 100644
--- a/doc/classes/VisualShaderNodeVectorCompose.xml
+++ b/doc/classes/VisualShaderNodeVectorCompose.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVectorCompose" inherits="VisualShaderNodeVectorBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVectorCompose" inherits="VisualShaderNodeVectorBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Composes a [Vector2], [Vector3] or 4D vector (represented as a [Quaternion]) from scalars within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVectorDecompose.xml b/doc/classes/VisualShaderNodeVectorDecompose.xml
index ce8ef443e0..7a9e977150 100644
--- a/doc/classes/VisualShaderNodeVectorDecompose.xml
+++ b/doc/classes/VisualShaderNodeVectorDecompose.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVectorDecompose" inherits="VisualShaderNodeVectorBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVectorDecompose" inherits="VisualShaderNodeVectorBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Decomposes a [Vector2], [Vector3] or 4D vector (represented as a [Quaternion]) into scalars within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVectorDistance.xml b/doc/classes/VisualShaderNodeVectorDistance.xml
index abbd8b783a..dad2e0366f 100644
--- a/doc/classes/VisualShaderNodeVectorDistance.xml
+++ b/doc/classes/VisualShaderNodeVectorDistance.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVectorDistance" inherits="VisualShaderNodeVectorBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVectorDistance" inherits="VisualShaderNodeVectorBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Returns the distance between two points. To be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVectorFunc.xml b/doc/classes/VisualShaderNodeVectorFunc.xml
index c20e8126d8..47691bd442 100644
--- a/doc/classes/VisualShaderNodeVectorFunc.xml
+++ b/doc/classes/VisualShaderNodeVectorFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVectorFunc" inherits="VisualShaderNodeVectorBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVectorFunc" inherits="VisualShaderNodeVectorBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A vector function to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVectorLen.xml b/doc/classes/VisualShaderNodeVectorLen.xml
index d74e2087f7..a458b0b616 100644
--- a/doc/classes/VisualShaderNodeVectorLen.xml
+++ b/doc/classes/VisualShaderNodeVectorLen.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVectorLen" inherits="VisualShaderNodeVectorBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVectorLen" inherits="VisualShaderNodeVectorBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Returns the length of a [Vector3] within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVectorOp.xml b/doc/classes/VisualShaderNodeVectorOp.xml
index 1ce2325384..d31460787d 100644
--- a/doc/classes/VisualShaderNodeVectorOp.xml
+++ b/doc/classes/VisualShaderNodeVectorOp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVectorOp" inherits="VisualShaderNodeVectorBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVectorOp" inherits="VisualShaderNodeVectorBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A vector operator to be used within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeVectorRefract.xml b/doc/classes/VisualShaderNodeVectorRefract.xml
index 9333bf50b1..384175e8d7 100644
--- a/doc/classes/VisualShaderNodeVectorRefract.xml
+++ b/doc/classes/VisualShaderNodeVectorRefract.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVectorRefract" inherits="VisualShaderNodeVectorBase" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVectorRefract" inherits="VisualShaderNodeVectorBase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Returns the vector that points in the direction of refraction. For use within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeWorldPositionFromDepth.xml b/doc/classes/VisualShaderNodeWorldPositionFromDepth.xml
new file mode 100644
index 0000000000..9c9016e889
--- /dev/null
+++ b/doc/classes/VisualShaderNodeWorldPositionFromDepth.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeWorldPositionFromDepth" inherits="VisualShaderNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ A visual shader node that calculates the position of the pixel in world space using the depth texture.
+ </brief_description>
+ <description>
+ The WorldPositionFromDepth node reconstructs the depth position of the pixel in world space. This can be used to obtain world space UVs for projection mapping like Caustics.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VoxelGI.xml b/doc/classes/VoxelGI.xml
index a019eac910..f5fd51bef7 100644
--- a/doc/classes/VoxelGI.xml
+++ b/doc/classes/VoxelGI.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VoxelGI" inherits="VisualInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VoxelGI" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Real-time global illumination (GI) probe.
</brief_description>
diff --git a/doc/classes/VoxelGIData.xml b/doc/classes/VoxelGIData.xml
index 34ba4d2c8b..088854e8f4 100644
--- a/doc/classes/VoxelGIData.xml
+++ b/doc/classes/VoxelGIData.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VoxelGIData" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VoxelGIData" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Contains baked voxel global illumination data for use in a [VoxelGI] node.
</brief_description>
diff --git a/doc/classes/WeakRef.xml b/doc/classes/WeakRef.xml
index 24685e7f53..c775dbe6ec 100644
--- a/doc/classes/WeakRef.xml
+++ b/doc/classes/WeakRef.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WeakRef" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="WeakRef" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Holds an [Object]. If the object is [RefCounted], it doesn't update the reference count.
</brief_description>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 725ac92117..4114a83584 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Window" inherits="Viewport" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Window" inherits="Viewport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for all windows, dialogs, and popups.
</brief_description>
@@ -903,5 +903,8 @@
The background style used when the [Window] is embedded. Note that this is drawn only under the window's content, excluding the title. For proper borders and title bar style, you can use [code]expand_margin_*[/code] properties of [StyleBoxFlat].
[b]Note:[/b] The content background will not be visible unless [member transparent] is enabled.
</theme_item>
+ <theme_item name="embedded_unfocused_border" data_type="style" type="StyleBox">
+ The background style used when the [Window] is embedded and unfocused.
+ </theme_item>
</theme_items>
</class>
diff --git a/doc/classes/WorkerThreadPool.xml b/doc/classes/WorkerThreadPool.xml
index 136c6279d7..d6751d31ce 100644
--- a/doc/classes/WorkerThreadPool.xml
+++ b/doc/classes/WorkerThreadPool.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WorkerThreadPool" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="WorkerThreadPool" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A singleton that allocates some [Thread]s on startup, used to offload tasks to these threads.
</brief_description>
diff --git a/doc/classes/World2D.xml b/doc/classes/World2D.xml
index c06fc48f12..c2e617d6e9 100644
--- a/doc/classes/World2D.xml
+++ b/doc/classes/World2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="World2D" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="World2D" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that holds all components of a 2D world, such as a canvas and a physics space.
</brief_description>
diff --git a/doc/classes/World3D.xml b/doc/classes/World3D.xml
index ce5f3d082d..8cdc2c3522 100644
--- a/doc/classes/World3D.xml
+++ b/doc/classes/World3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="World3D" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="World3D" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that holds all components of a 3D world, such as a visual scenario and a physics space.
</brief_description>
diff --git a/doc/classes/WorldBoundaryShape2D.xml b/doc/classes/WorldBoundaryShape2D.xml
index 9de10a531f..018e6289a3 100644
--- a/doc/classes/WorldBoundaryShape2D.xml
+++ b/doc/classes/WorldBoundaryShape2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WorldBoundaryShape2D" inherits="Shape2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="WorldBoundaryShape2D" inherits="Shape2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D world boundary (half-plane) shape used for physics collision.
</brief_description>
diff --git a/doc/classes/WorldBoundaryShape3D.xml b/doc/classes/WorldBoundaryShape3D.xml
index e8ebe96d38..33609916a3 100644
--- a/doc/classes/WorldBoundaryShape3D.xml
+++ b/doc/classes/WorldBoundaryShape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WorldBoundaryShape3D" inherits="Shape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="WorldBoundaryShape3D" inherits="Shape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 3D world boundary (half-space) shape used for physics collision.
</brief_description>
diff --git a/doc/classes/WorldEnvironment.xml b/doc/classes/WorldEnvironment.xml
index 652d2b548c..bceb91ab68 100644
--- a/doc/classes/WorldEnvironment.xml
+++ b/doc/classes/WorldEnvironment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WorldEnvironment" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="WorldEnvironment" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Default environment properties for the entire scene (post-processing effects, lighting and background settings).
</brief_description>
diff --git a/doc/classes/X509Certificate.xml b/doc/classes/X509Certificate.xml
index 05a9d522f0..9cc4060852 100644
--- a/doc/classes/X509Certificate.xml
+++ b/doc/classes/X509Certificate.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="X509Certificate" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="X509Certificate" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An X509 certificate (e.g. for TLS).
</brief_description>
diff --git a/doc/classes/XMLParser.xml b/doc/classes/XMLParser.xml
index 86732391e4..6812e83b8f 100644
--- a/doc/classes/XMLParser.xml
+++ b/doc/classes/XMLParser.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XMLParser" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XMLParser" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides a low-level interface for creating parsers for XML files.
Low-level class for creating parsers for [url=https://en.wikipedia.org/wiki/XML]XML[/url] files.
diff --git a/doc/classes/XRAnchor3D.xml b/doc/classes/XRAnchor3D.xml
index 9b7ed38c80..e9d9798de8 100644
--- a/doc/classes/XRAnchor3D.xml
+++ b/doc/classes/XRAnchor3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRAnchor3D" inherits="XRNode3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XRAnchor3D" inherits="XRNode3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
An anchor point in AR space.
</brief_description>
diff --git a/doc/classes/XRCamera3D.xml b/doc/classes/XRCamera3D.xml
index 58fac656c1..a7904b3ada 100644
--- a/doc/classes/XRCamera3D.xml
+++ b/doc/classes/XRCamera3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRCamera3D" inherits="Camera3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XRCamera3D" inherits="Camera3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A camera node with a few overrules for AR/VR applied, such as location tracking.
</brief_description>
diff --git a/doc/classes/XRController3D.xml b/doc/classes/XRController3D.xml
index 050ef6bc0e..ee67477eb0 100644
--- a/doc/classes/XRController3D.xml
+++ b/doc/classes/XRController3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRController3D" inherits="XRNode3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XRController3D" inherits="XRNode3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A spatial node representing a spatially-tracked controller.
</brief_description>
diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml
index 18c4562f33..7b741b43d8 100644
--- a/doc/classes/XRInterface.xml
+++ b/doc/classes/XRInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRInterface" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XRInterface" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for an XR interface implementation.
</brief_description>
diff --git a/doc/classes/XRInterfaceExtension.xml b/doc/classes/XRInterfaceExtension.xml
index 0a29e91f67..9059a5a465 100644
--- a/doc/classes/XRInterfaceExtension.xml
+++ b/doc/classes/XRInterfaceExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRInterfaceExtension" inherits="XRInterface" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XRInterfaceExtension" inherits="XRInterface" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for XR interface extensions (plugins).
</brief_description>
diff --git a/doc/classes/XRNode3D.xml b/doc/classes/XRNode3D.xml
index 0b51edada5..9c0955b0b1 100644
--- a/doc/classes/XRNode3D.xml
+++ b/doc/classes/XRNode3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRNode3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XRNode3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A spatial node that has its position automatically updated by the [XRServer].
</brief_description>
diff --git a/doc/classes/XROrigin3D.xml b/doc/classes/XROrigin3D.xml
index b7fc3a2752..b35d27ab12 100644
--- a/doc/classes/XROrigin3D.xml
+++ b/doc/classes/XROrigin3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XROrigin3D" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XROrigin3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
The origin point in AR/VR.
</brief_description>
diff --git a/doc/classes/XRPose.xml b/doc/classes/XRPose.xml
index cf7091f966..51f7253a17 100644
--- a/doc/classes/XRPose.xml
+++ b/doc/classes/XRPose.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRPose" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XRPose" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
This object contains all data related to a pose on a tracked object.
</brief_description>
diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml
index 6a913dd96e..958be92072 100644
--- a/doc/classes/XRPositionalTracker.xml
+++ b/doc/classes/XRPositionalTracker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRPositionalTracker" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XRPositionalTracker" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A tracked object.
</brief_description>
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index 802d7ef2a9..4ef5d3473b 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRServer" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="XRServer" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Server for AR and VR features.
</brief_description>
diff --git a/doc/classes/bool.xml b/doc/classes/bool.xml
index af54c58f82..9e7d1fc965 100644
--- a/doc/classes/bool.xml
+++ b/doc/classes/bool.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="bool" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="bool" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A built-in boolean type.
</brief_description>
diff --git a/doc/classes/float.xml b/doc/classes/float.xml
index 293ba2eaf9..14e30b69a5 100644
--- a/doc/classes/float.xml
+++ b/doc/classes/float.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="float" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="float" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A built-in type for floating point numbers.
</brief_description>
diff --git a/doc/classes/int.xml b/doc/classes/int.xml
index 1bf318fe8e..bc0da03e98 100644
--- a/doc/classes/int.xml
+++ b/doc/classes/int.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="int" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="int" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A built-in type for integers.
</brief_description>
diff --git a/doc/tools/doc_status.py b/doc/tools/doc_status.py
index 376addcff0..717a468b36 100755
--- a/doc/tools/doc_status.py
+++ b/doc/tools/doc_status.py
@@ -383,12 +383,6 @@ for file in input_file_list:
tree = ET.parse(file)
doc = tree.getroot()
- if "version" not in doc.attrib:
- print('Version missing from "doc"')
- sys.exit(255)
-
- version = doc.attrib["version"]
-
if doc.attrib["name"] in class_names:
continue
class_names.append(doc.attrib["name"])
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index 0649a0bb62..54bad7cf05 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -66,6 +66,15 @@ BASE_STRINGS = [
"This method doesn't need an instance to be called, so it can be called directly using the class name.",
"This method describes a valid operator to use with this type as left-hand operand.",
"This value is an integer composed as a bitmask of the following flags.",
+ "There is currently no description for this class. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!",
+ "There is currently no description for this signal. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!",
+ "There is currently no description for this annotation. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!",
+ "There is currently no description for this property. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!",
+ "There is currently no description for this constructor. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!",
+ "There is currently no description for this method. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!",
+ "There is currently no description for this operator. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!",
+ "There is currently no description for this theme property. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!",
+ "There are notable differences when using this API with C#. See :ref:`doc_c_sharp_differences` for more information.",
]
strings_l10n: Dict[str, str] = {}
@@ -92,6 +101,36 @@ EDITOR_CLASSES: List[str] = [
"ScriptEditor",
"ScriptEditorBase",
]
+# Sync with the types mentioned in https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/c_sharp_differences.html
+CLASSES_WITH_CSHARP_DIFFERENCES: List[str] = [
+ "@GlobalScope",
+ "String",
+ "NodePath",
+ "Signal",
+ "Callable",
+ "RID",
+ "Basis",
+ "Transform2D",
+ "Transform3D",
+ "Rect2",
+ "Rect2i",
+ "AABB",
+ "Quaternion",
+ "Projection",
+ "Color",
+ "Array",
+ "Dictionary",
+ "PackedByteArray",
+ "PackedColorArray",
+ "PackedFloat32Array",
+ "PackedFloat64Array",
+ "PackedInt32Array",
+ "PackedInt64Array",
+ "PackedStringArray",
+ "PackedVector2Array",
+ "PackedVector3Array",
+ "Variant",
+]
class State:
@@ -607,10 +646,6 @@ def main() -> None:
continue
doc = tree.getroot()
- if "version" not in doc.attrib:
- print_error(f'{cur_file}: "version" attribute missing from "doc".', state)
- continue
-
name = doc.attrib["name"]
if name in classes:
print_error(f'{cur_file}: Duplicate class "{name}".', state)
@@ -846,6 +881,15 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
+ "\n\n"
)
+ if class_def.name in CLASSES_WITH_CSHARP_DIFFERENCES:
+ f.write(".. note::\n\n\t")
+ f.write(
+ translate(
+ "There are notable differences when using this API with C#. See :ref:`doc_c_sharp_differences` for more information."
+ )
+ + "\n\n"
+ )
+
# Online tutorials
if len(class_def.tutorials) > 0:
f.write(".. rst-class:: classref-introduction-group\n\n")
diff --git a/doc/translations/es.po b/doc/translations/es.po
index c3b87f20bf..dd4730de16 100644
--- a/doc/translations/es.po
+++ b/doc/translations/es.po
@@ -51,12 +51,16 @@
# Luis Ortiz <luisortiz66@hotmail.com>, 2023.
# Biel Serrano Sanchez <bielsesa@gmail.com>, 2023.
# Скотт Сторм <sors.inanis.immanis@gmail.com>, 2023.
+# Alvaro Tejada <santi_evil@yahoo.com>, 2023.
+# Abrahams Rubí <kingsrubix2023@gmail.com>, 2023.
+# Braulio León Madrid Escobar <brauliomadrid.developer@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2023-05-23 04:18+0000\n"
-"Last-Translator: Скотт Сторм <sors.inanis.immanis@gmail.com>\n"
+"PO-Revision-Date: 2023-07-05 13:48+0000\n"
+"Last-Translator: Braulio León Madrid Escobar <brauliomadrid.developer@gmail."
+"com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/es/>\n"
"Language: es\n"
@@ -64,7 +68,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.18-dev\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Description"
msgstr "Descripción"
@@ -168,6 +172,14 @@ msgstr ""
"Este método describe un operador válido para usar con este tipo como "
"operando izquierdo."
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr ""
+"Este valor es un entero compuesto como una máscara de bits de los siguientes "
+"indicadores."
+
+msgid "Built-in GDScript constants, functions, and annotations."
+msgstr "Constantes, funciones y anotaciones de GDScript integradas."
+
msgid ""
"A list of GDScript-specific utility functions and annotations accessible "
"from any script.\n"
@@ -181,6 +193,41 @@ msgid "GDScript exports"
msgstr "Exportaciones de Scripts GD"
msgid ""
+"Returns a [Color] constructed from red ([param r8]), green ([param g8]), "
+"blue ([param b8]), and optionally alpha ([param a8]) integer channels, each "
+"divided by [code]255.0[/code] for their final value. Using [method Color8] "
+"instead of the standard [Color] constructor is useful when you need to match "
+"exact color values in an [Image].\n"
+"[codeblock]\n"
+"var red = Color8(255, 0, 0) # Same as Color(1, 0, 0).\n"
+"var dark_blue = Color8(0, 0, 51) # Same as Color(0, 0, 0.2).\n"
+"var my_color = Color8(306, 255, 0, 102) # Same as Color(1.2, 1, 0, 0.4).\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Due to the lower precision of [method Color8] compared to the "
+"standard [Color] constructor, a color created with [method Color8] will "
+"generally not be equal to the same color created with the standard [Color] "
+"constructor. Use [method Color.is_equal_approx] for comparisons to avoid "
+"issues with floating-point precision error."
+msgstr ""
+"Devuelve un [Color] construido a partir de rojo ([param r8]), verde ([param "
+"g8]), azul ([param b8]) y opcionalmente alfa ([param a8]), cada uno dividido "
+"entre [code]255.0[/code] para obtener su valor final. Usar [method Color8] "
+"en vez del constructor estándar [Color] es útil cuando necesita hacer "
+"coincidir exactamente los valores de color en una [Image].\n"
+"[codeblock]\n"
+"var red = Color8(255, 0, 0) # Igual que Color(1, "
+"0, 0)\n"
+"var dark_blue = Color8(0, 0, 51) # Igual que Color(0, 0, "
+"0.2).\n"
+"var my_color = Color8(306, 255, 0, 102) # Igual que Color(1.2, 1, 0, 0.4).\n"
+"[/codeblock]\n"
+"[b]Nota:[/b] Debido a la baja precisión de [method Color8] comparado con el "
+"constructor estándar [Color], un color creado con [method Color8], "
+"generalmente, no será igual al mismo color creado con el constructor "
+"estándar [Color]. Utilice [method Color.is_equal_approx] para hacer "
+"comparaciones y evitar problemas con errores de precisión de coma flotante."
+
+msgid ""
"Asserts that the [param condition] is [code]true[/code]. If the [param "
"condition] is [code]false[/code], an error is generated. When running from "
"the editor, the running project will also be paused until you resume it. "
@@ -21136,6 +21183,13 @@ msgstr "Derivado en [code]x[/code] utilizando la diferenciación local."
msgid "Derivative in [code]y[/code] using local differencing."
msgstr "Derivado en [code]y[/code] utilizando la diferenciación local."
+msgid ""
+"The distance fade effect fades out each pixel based on its distance to "
+"another object."
+msgstr ""
+"El efecto de atenuación de distancia desvanece cada píxel en función de su "
+"distancia a otro objeto."
+
msgid "Calculates a dot product of two vectors within the visual shader graph."
msgstr ""
"Calcula un producto escalar de dos vectores dentro del gráfico shader visual."
@@ -21360,6 +21414,13 @@ msgstr ""
"Este nodo shader visual está presente en todos los gráficos shader en forma "
"de bloque de \"Salida\" con múltiples puertos de valor de salida."
+msgid ""
+"The proximity fade effect fades out each pixel based on its distance to "
+"another object."
+msgstr ""
+"El efecto de atenuación de proximidad desvanece cada píxel en función de su "
+"distancia a otro objeto."
+
msgid "The size of the node in the visual shader graph."
msgstr "El tamaño del nodo en el gráfico shader visual."
diff --git a/doc/translations/zh_CN.po b/doc/translations/zh_CN.po
index 05388452a5..6ec026bb71 100644
--- a/doc/translations/zh_CN.po
+++ b/doc/translations/zh_CN.po
@@ -77,12 +77,13 @@
# yisui <hechugetqiufrost@outlook.com>, 2023.
# penghao123456 <phao0724@163.com>, 2023.
# Zae Chao <zaevi@live.com>, 2023.
+# SamBillon <sambillon1234+hosted.weblate@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2023-06-26 09:54+0000\n"
-"Last-Translator: 风青山 <idleman@yeah.net>\n"
+"PO-Revision-Date: 2023-07-04 00:53+0000\n"
+"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot-class-reference/zh_Hans/>\n"
"Language: zh_CN\n"
@@ -90,7 +91,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Description"
msgstr "描述"
@@ -184,6 +185,9 @@ msgid ""
"operand."
msgstr "本方法描述的是使用本类型作为左操作数的有效操作符。"
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr "这个值是由下列标志构成的位掩码整数。"
+
msgid "Built-in GDScript constants, functions, and annotations."
msgstr "内置 GDScript 常量、函数、注解。"
@@ -2446,6 +2450,27 @@ msgstr ""
"[/codeblock]"
msgid ""
+"Moves [param from] toward [param to] by the [param delta] amount. Will not "
+"go past [param to].\n"
+"Use a negative [param delta] value to move away.\n"
+"[codeblock]\n"
+"move_toward(5, 10, 4) # Returns 9\n"
+"move_toward(10, 5, 4) # Returns 6\n"
+"move_toward(5, 10, 9) # Returns 10\n"
+"move_toward(10, 5, -1.5) # Returns 11.5\n"
+"[/codeblock]"
+msgstr ""
+"将 [param from] 向 [param to] 移动,移动的长度是 [param delta]。不会超过 "
+"[param to]。\n"
+"使用负的 [param delta] 值则向远离的方向移动。\n"
+"[codeblock]\n"
+"move_toward(5, 10, 4) # Returns 9\n"
+"move_toward(10, 5, 4) # Returns 6\n"
+"move_toward(5, 10, 9) # Returns 10\n"
+"move_toward(10, 5, -1.5) # Returns 11.5\n"
+"[/codeblock]"
+
+msgid ""
"Returns the nearest equal or larger power of 2 for the integer [param "
"value].\n"
"In other words, returns the smallest value [code]a[/code] where [code]a = "
@@ -3484,6 +3509,51 @@ msgstr ""
"反序列化可以使用 [method bytes_to_var_with_objects] 来完成。"
msgid ""
+"Converts a [Variant] [param variable] to a formatted [String] that can then "
+"be parsed using [method str_to_var].\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"var a = { \"a\": 1, \"b\": 2 }\n"
+"print(var_to_str(a))\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"var a = new Godot.Collections.Dictionary { [\"a\"] = 1, [\"b\"] = 2 };\n"
+"GD.Print(GD.VarToStr(a));\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"Prints:\n"
+"[codeblock]\n"
+"{\n"
+" \"a\": 1,\n"
+" \"b\": 2\n"
+"}\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Converting [Signal] or [Callable] is not supported and will "
+"result in an empty value for these types, regardless of their data."
+msgstr ""
+"将 [Variant] [param variable] 转换为格式化的 [String],后续可以使用 [method "
+"str_to_var] 对其进行解析。\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"var a = { \"a\": 1, \"b\": 2 }\n"
+"print(var_to_str(a))\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"var a = new Godot.Collections.Dictionary { [\"a\"] = 1, [\"b\"] = 2 };\n"
+"GD.Print(GD.VarToStr(a));\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"输出:\n"
+"[codeblock]\n"
+"{\n"
+" \"a\": 1,\n"
+" \"b\": 2\n"
+"}\n"
+"[/codeblock]\n"
+"[b]注意:[/b]不支持转换 [Signal] 和 [Callable],这些类型无论有什么数据,转换"
+"后都是空值。"
+
+msgid ""
"Returns a weak reference to an object, or [code]null[/code] if [param obj] "
"is invalid.\n"
"A weak reference to an object is not enough to keep the object alive: when "
@@ -3651,6 +3721,9 @@ msgstr "[NavigationMeshGenerator] 单例。"
msgid "The [NavigationServer2D] singleton."
msgstr "[NavigationServer2D] 单例。"
+msgid "The [NavigationServer3D] singleton."
+msgstr "[NavigationServer3D] 单例。"
+
msgid "The [OS] singleton."
msgstr "[OS] 单例。"
@@ -5196,6 +5269,175 @@ msgstr ""
"提示一个 [Color] 属性在编辑时不能影响其透明度([member Color.a] 不可编辑)。"
msgid ""
+"If a property is [String], hints that the property represents a particular "
+"type (class). This allows to select a type from the create dialog. The "
+"property will store the selected type as a string.\n"
+"If a property is [Array], hints the editor how to show elements. The "
+"[code]hint_string[/code] must encode nested types using [code]\":\"[/code] "
+"and [code]\"/\"[/code].\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"# Array of elem_type.\n"
+"hint_string = \"%d:\" % [elem_type]\n"
+"hint_string = \"%d/%d:%s\" % [elem_type, elem_hint, elem_hint_string]\n"
+"# Two-dimensional array of elem_type (array of arrays of elem_type).\n"
+"hint_string = \"%d:%d:\" % [TYPE_ARRAY, elem_type]\n"
+"hint_string = \"%d:%d/%d:%s\" % [TYPE_ARRAY, elem_type, elem_hint, "
+"elem_hint_string]\n"
+"# Three-dimensional array of elem_type (array of arrays of arrays of "
+"elem_type).\n"
+"hint_string = \"%d:%d:%d:\" % [TYPE_ARRAY, TYPE_ARRAY, elem_type]\n"
+"hint_string = \"%d:%d:%d/%d:%s\" % [TYPE_ARRAY, TYPE_ARRAY, elem_type, "
+"elem_hint, elem_hint_string]\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"// Array of elemType.\n"
+"hintString = $\"{elemType:D}:\";\n"
+"hintString = $\"{elemType:}/{elemHint:D}:{elemHintString}\";\n"
+"// Two-dimensional array of elemType (array of arrays of elemType).\n"
+"hintString = $\"{Variant.Type.Array:D}:{elemType:D}:\";\n"
+"hintString = $\"{Variant.Type.Array:D}:{elemType:D}/{elemHint:D}:"
+"{elemHintString}\";\n"
+"// Three-dimensional array of elemType (array of arrays of arrays of "
+"elemType).\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Array:D}:{elemType:D}:"
+"\";\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Array:D}:{elemType:D}/"
+"{elemHint:D}:{elemHintString}\";\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"Examples:\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"hint_string = \"%d:\" % [TYPE_INT] # Array of integers.\n"
+"hint_string = \"%d/%d:1,10,1\" % [TYPE_INT, PROPERTY_HINT_RANGE] # Array of "
+"integers (in range from 1 to 10).\n"
+"hint_string = \"%d/%d:Zero,One,Two\" % [TYPE_INT, PROPERTY_HINT_ENUM] # "
+"Array of integers (an enum).\n"
+"hint_string = \"%d/%d:Zero,One,Three:3,Six:6\" % [TYPE_INT, "
+"PROPERTY_HINT_ENUM] # Array of integers (an enum).\n"
+"hint_string = \"%d/%d:*.png\" % [TYPE_STRING, PROPERTY_HINT_FILE] # Array of "
+"strings (file paths).\n"
+"hint_string = \"%d/%d:Texture2D\" % [TYPE_OBJECT, "
+"PROPERTY_HINT_RESOURCE_TYPE] # Array of textures.\n"
+"\n"
+"hint_string = \"%d:%d:\" % [TYPE_ARRAY, TYPE_FLOAT] # Two-dimensional array "
+"of floats.\n"
+"hint_string = \"%d:%d/%d:\" % [TYPE_ARRAY, TYPE_STRING, "
+"PROPERTY_HINT_MULTILINE_TEXT] # Two-dimensional array of multiline strings.\n"
+"hint_string = \"%d:%d/%d:-1,1,0.1\" % [TYPE_ARRAY, TYPE_FLOAT, "
+"PROPERTY_HINT_RANGE] # Two-dimensional array of floats (in range from -1 to "
+"1).\n"
+"hint_string = \"%d:%d/%d:Texture2D\" % [TYPE_ARRAY, TYPE_OBJECT, "
+"PROPERTY_HINT_RESOURCE_TYPE] # Two-dimensional array of textures.\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"hintString = $\"{Variant.Type.Int:D}/{PropertyHint.Range:D}:1,10,1\"; // "
+"Array of integers (in range from 1 to 10).\n"
+"hintString = $\"{Variant.Type.Int:D}/{PropertyHint.Enum:D}:Zero,One,"
+"Two\"; // Array of integers (an enum).\n"
+"hintString = $\"{Variant.Type.Int:D}/{PropertyHint.Enum:D}:Zero,One,Three:3,"
+"Six:6\"; // Array of integers (an enum).\n"
+"hintString = $\"{Variant.Type.String:D}/{PropertyHint.File:D}:*.png\"; // "
+"Array of strings (file paths).\n"
+"hintString = $\"{Variant.Type.Object:D}/{PropertyHint.ResourceType:D}:"
+"Texture2D\"; // Array of textures.\n"
+"\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Float:D}:\"; // Two-"
+"dimensional array of floats.\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.String:D}/{PropertyHint."
+"MultilineText:D}:\"; // Two-dimensional array of multiline strings.\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Float:D}/{PropertyHint."
+"Range:D}:-1,1,0.1\"; // Two-dimensional array of floats (in range from -1 to "
+"1).\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Object:D}/{PropertyHint."
+"ResourceType:D}:Texture2D\"; // Two-dimensional array of textures.\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"[b]Note:[/b] The trailing colon is required for properly detecting built-in "
+"types."
+msgstr ""
+"如果属性为 [String],则提示该属性代表特定的类型(类)。这样就能使用创建对话框"
+"选择类型。该属性中存放的是所选类型,是一个字符串。\n"
+"如果属性为 [Array],则提示编辑器如何显示其中的元素。[code]hint_string[/code] "
+"必须使用 [code]\":\"[/code] 和 [code]\"/\"[/code] 对内嵌的类型进行编码。\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"# elem_type 数组。\n"
+"hint_string = \"%d:\" % [elem_type]\n"
+"hint_string = \"%d/%d:%s\" % [elem_type, elem_hint, elem_hint_string]\n"
+"# elem_type 二维数组(elem_type 数组的数组)。\n"
+"hint_string = \"%d:%d:\" % [TYPE_ARRAY, elem_type]\n"
+"hint_string = \"%d:%d/%d:%s\" % [TYPE_ARRAY, elem_type, elem_hint, "
+"elem_hint_string]\n"
+"# elem_type 三维数组(elem_type 数组的数组的数组)。\n"
+"hint_string = \"%d:%d:%d:\" % [TYPE_ARRAY, TYPE_ARRAY, elem_type]\n"
+"hint_string = \"%d:%d:%d/%d:%s\" % [TYPE_ARRAY, TYPE_ARRAY, elem_type, "
+"elem_hint, elem_hint_string]\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"// elem_type 数组。\n"
+"hintString = $\"{elemType:D}:\";\n"
+"hintString = $\"{elemType:}/{elemHint:D}:{elemHintString}\";\n"
+"// elem_type 二维数组(elem_type 数组的数组)。\n"
+"hintString = $\"{Variant.Type.Array:D}:{elemType:D}:\";\n"
+"hintString = $\"{Variant.Type.Array:D}:{elemType:D}/{elemHint:D}:"
+"{elemHintString}\";\n"
+"// elem_type 三维数组(elem_type 数组的数组的数组)。\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Array:D}:{elemType:D}:"
+"\";\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Array:D}:{elemType:D}/"
+"{elemHint:D}:{elemHintString}\";\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"示例:\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"hint_string = \"%d:\" % [TYPE_INT] # 整数数组。\n"
+"hint_string = \"%d/%d:1,10,1\" % [TYPE_INT, PROPERTY_HINT_RANGE] # 整数数组"
+"(范围为 1 到 10)。\n"
+"hint_string = \"%d/%d:Zero,One,Two\" % [TYPE_INT, PROPERTY_HINT_ENUM] # 整数"
+"数组(枚举)。\n"
+"hint_string = \"%d/%d:Zero,One,Three:3,Six:6\" % [TYPE_INT, "
+"PROPERTY_HINT_ENUM] # 整数数组(枚举)。\n"
+"hint_string = \"%d/%d:*.png\" % [TYPE_STRING, PROPERTY_HINT_FILE] # 字符串数"
+"组(文件路径)。\n"
+"hint_string = \"%d/%d:Texture2D\" % [TYPE_OBJECT, "
+"PROPERTY_HINT_RESOURCE_TYPE] # 纹理数组。\n"
+"\n"
+"hint_string = \"%d:%d:\" % [TYPE_ARRAY, TYPE_FLOAT] # 浮点数二维数组。\n"
+"hint_string = \"%d:%d/%d:\" % [TYPE_ARRAY, TYPE_STRING, "
+"PROPERTY_HINT_MULTILINE_TEXT] # 多行字符串二维数组。\n"
+"hint_string = \"%d:%d/%d:-1,1,0.1\" % [TYPE_ARRAY, TYPE_FLOAT, "
+"PROPERTY_HINT_RANGE] # 浮点数二维数组(范围为 -1 到 1)。\n"
+"hint_string = \"%d:%d/%d:Texture2D\" % [TYPE_ARRAY, TYPE_OBJECT, "
+"PROPERTY_HINT_RESOURCE_TYPE] # 纹理二维数组。\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"hintString = $\"{Variant.Type.Int:D}/{PropertyHint.Range:D}:1,10,1\"; // 整数"
+"数组(范围为 1 到 10)。\n"
+"hintString = $\"{Variant.Type.Int:D}/{PropertyHint.Enum:D}:Zero,One,"
+"Two\"; // 整数数组(枚举)。\n"
+"hintString = $\"{Variant.Type.Int:D}/{PropertyHint.Enum:D}:Zero,One,Three:3,"
+"Six:6\"; // 整数数组(枚举)。\n"
+"hintString = $\"{Variant.Type.String:D}/{PropertyHint.File:D}:*.png\"; // 字"
+"符串数组(文件路径)。\n"
+"hintString = $\"{Variant.Type.Object:D}/{PropertyHint.ResourceType:D}:"
+"Texture2D\"; // 纹理数组。\n"
+"\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Float:D}:\"; // 浮点数二"
+"维数组。\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.String:D}/{PropertyHint."
+"MultilineText:D}:\"; // 多行字符串二维数组。\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Float:D}/{PropertyHint."
+"Range:D}:-1,1,0.1\"; // 浮点数二维数组(范围为 -1 到 1)。\n"
+"hintString = $\"{Variant.Type.Array:D}:{Variant.Type.Object:D}/{PropertyHint."
+"ResourceType:D}:Texture2D\"; // 纹理二维数组。\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"[b]注意:[/b]后缀冒号是必须的,否则无法正确识别内置类型。"
+
+msgid ""
"Hints that a string property is a locale code. Editing it will show a locale "
"dialog for picking language and country."
msgstr ""
@@ -6513,7 +6755,72 @@ msgstr ""
"[AnimationPlayer] 或 [AnimatedSprite2D]。"
msgid "Holds data that can be used to animate anything in the engine."
-msgstr "存放数据,可用于在引擎中将任何对象进行动画处理。"
+msgstr "存放的是用于对引擎中的任何对象进行动画处理的数据。"
+
+msgid ""
+"This resource holds data that can be used to animate anything in the engine. "
+"Animations are divided into tracks and each track must be linked to a node. "
+"The state of that node can be changed through time, by adding timed keys "
+"(events) to the track.\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"# This creates an animation that makes the node \"Enemy\" move to the right "
+"by\n"
+"# 100 pixels in 0.5 seconds.\n"
+"var animation = Animation.new()\n"
+"var track_index = animation.add_track(Animation.TYPE_VALUE)\n"
+"animation.track_set_path(track_index, \"Enemy:position:x\")\n"
+"animation.track_insert_key(track_index, 0.0, 0)\n"
+"animation.track_insert_key(track_index, 0.5, 100)\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"// This creates an animation that makes the node \"Enemy\" move to the right "
+"by\n"
+"// 100 pixels in 0.5 seconds.\n"
+"var animation = new Animation();\n"
+"int trackIndex = animation.AddTrack(Animation.TrackType.Value);\n"
+"animation.TrackSetPath(trackIndex, \"Enemy:position:x\");\n"
+"animation.TrackInsertKey(trackIndex, 0.0f, 0);\n"
+"animation.TrackInsertKey(trackIndex, 0.5f, 100);\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"Animations are just data containers, and must be added to nodes such as an "
+"[AnimationPlayer] to be played back. Animation tracks have different types, "
+"each with its own set of dedicated methods. Check [enum TrackType] to see "
+"available types.\n"
+"[b]Note:[/b] For 3D position/rotation/scale, using the dedicated [constant "
+"TYPE_POSITION_3D], [constant TYPE_ROTATION_3D] and [constant TYPE_SCALE_3D] "
+"track types instead of [constant TYPE_VALUE] is recommended for performance "
+"reasons."
+msgstr ""
+"这个资源存放的是用于对引擎中的任何对象进行动画处理的数据。动画分为轨道,轨道"
+"必须与节点关联。向轨道添加定时关键帧(事件)后,节点的状态可以随时间变化。\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"# 创建动画,让“Enemy”节点在 0.5 秒内\n"
+"# 向右移动 100 像素。\n"
+"var animation = Animation.new()\n"
+"var track_index = animation.add_track(Animation.TYPE_VALUE)\n"
+"animation.track_set_path(track_index, \"Enemy:position:x\")\n"
+"animation.track_insert_key(track_index, 0.0, 0)\n"
+"animation.track_insert_key(track_index, 0.5, 100)\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"# 创建动画,让“Enemy”节点在 0.5 秒内\n"
+"# 向右移动 100 像素。\n"
+"var animation = new Animation();\n"
+"int trackIndex = animation.AddTrack(Animation.TrackType.Value);\n"
+"animation.TrackSetPath(trackIndex, \"Enemy:position:x\");\n"
+"animation.TrackInsertKey(trackIndex, 0.0f, 0);\n"
+"animation.TrackInsertKey(trackIndex, 0.5f, 100);\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"动画只是数据的容器,必须添加至 [AnimationPlayer] 等节点才能进行播放。动画轨道"
+"分为不同的类型,不同的类型有各自不同的专属方法。可用的类型请查看 [enum "
+"TrackType]。\n"
+"[b]注意:[/b]对于 3D 的位置、旋转、缩放,推荐使用专门的 [constant "
+"TYPE_POSITION_3D]、[constant TYPE_ROTATION_3D]、[constant TYPE_SCALE_3D] 轨道"
+"类型,不要使用 [constant TYPE_VALUE],性能更高。"
msgid "Animation documentation index"
msgstr "动画教程索引"
@@ -6679,6 +6986,13 @@ msgstr ""
msgid "Inserts a key in a given blend shape track. Returns the key index."
msgstr "在给定的混合形状轨道中插入一个关键帧。返回键索引。"
+msgid ""
+"Returns the interpolated blend shape value at the given time (in seconds). "
+"The [param track_idx] must be the index of a blend shape track."
+msgstr ""
+"返回位于给定时间(以秒为单位)的插值后的混合形状值。[param track_idx] 必须是"
+"混合形状轨道的索引。"
+
msgid "Clear the animation (clear all tracks and reset all)."
msgstr "清除动画(清除所有轨道并重置所有)。"
@@ -6723,16 +7037,37 @@ msgstr "返回给定方法轨道中给定键的方法要调用的参数值。"
msgid "Inserts a key in a given 3D position track. Returns the key index."
msgstr "在给定的 3D 位置轨道中插入关键帧。返回该关键帧的索引。"
+msgid ""
+"Returns the interpolated position value at the given time (in seconds). The "
+"[param track_idx] must be the index of a 3D position track."
+msgstr ""
+"返回位于给定时间(以秒为单位)的插值后的位置值。[param track_idx] 必须是 3D "
+"位置轨道的索引。"
+
msgid "Removes a track by specifying the track index."
msgstr "通过指定轨道索引来移除一个轨道。"
msgid "Inserts a key in a given 3D rotation track. Returns the key index."
msgstr "在给定的 3D 旋转轨道中插入关键帧。返回该关键帧的索引。"
+msgid ""
+"Returns the interpolated rotation value at the given time (in seconds). The "
+"[param track_idx] must be the index of a 3D rotation track."
+msgstr ""
+"返回位于给定时间(以秒为单位)的插值后的旋转值。[param track_idx] 必须是 3D "
+"旋转轨道的索引。"
+
msgid "Inserts a key in a given 3D scale track. Returns the key index."
msgstr "在给定的 3D 缩放轨道中插入关键帧。返回该关键帧的索引。"
msgid ""
+"Returns the interpolated scale value at the given time (in seconds). The "
+"[param track_idx] must be the index of a 3D scale track."
+msgstr ""
+"返回位于给定时间(以秒为单位)的插值后的缩放值。[param track_idx] 必须是 3D "
+"缩放轨道的索引。"
+
+msgid ""
"Finds the key index by time in a given track. Optionally, only find it if "
"the approx/exact time is given."
msgstr ""
@@ -7080,10 +7415,111 @@ msgid ""
"[param to_name]."
msgstr "当 [Animation] 的键从 [param name] 更改为 [param to_name] 时发出。"
+msgid "Base class for [AnimationTree] nodes. Not related to scene nodes."
+msgstr "[AnimationTree] 节点的基类。与场景节点无关。"
+
+msgid ""
+"Base resource for [AnimationTree] nodes. In general, it's not used directly, "
+"but you can create custom ones with custom blending formulas.\n"
+"Inherit this when creating animation nodes mainly for use in "
+"[AnimationNodeBlendTree], otherwise [AnimationRootNode] should be used "
+"instead."
+msgstr ""
+"[AnimationTree] 节点的基础资源。通常不会直接使用,但你可以使用自定义混合公式"
+"创建自定义节点。\n"
+"创建动画节点时继承这个类主要是用在 [AnimationNodeBlendTree] 中,否则应改用 "
+"[AnimationRootNode]。"
+
msgid "Using AnimationTree"
msgstr "使用 AnimationTree"
msgid ""
+"When inheriting from [AnimationRootNode], implement this virtual method to "
+"override the text caption for this animation node."
+msgstr ""
+"继承 [AnimationRootNode] 时,实现这个虚方法可以覆盖这个动画节点的标题文本。"
+
+msgid ""
+"When inheriting from [AnimationRootNode], implement this virtual method to "
+"return a child animation node by its [param name]."
+msgstr ""
+"继承 [AnimationRootNode] 时,实现这个虚方法可以根据名称 [param name] 来返回对"
+"应的子动画节点。"
+
+msgid ""
+"When inheriting from [AnimationRootNode], implement this virtual method to "
+"return all children animation nodes in order as a [code]name: node[/code] "
+"dictionary."
+msgstr ""
+"继承 [AnimationRootNode] 时,实现这个虚方法可以用 [code]名称:节点[/code] 字典"
+"的形式按顺序返回所有子动画节点。"
+
+msgid ""
+"When inheriting from [AnimationRootNode], implement this virtual method to "
+"return the default value of a [param parameter]. Parameters are custom local "
+"memory used for your animation nodes, given a resource can be reused in "
+"multiple trees."
+msgstr ""
+"继承 [AnimationRootNode] 时,实现这个虚方法可以返回参数“[param parameter]”的"
+"默认值。参数是动画节点的自定义本地存储,资源可以在多个树中重用。"
+
+msgid ""
+"When inheriting from [AnimationRootNode], implement this virtual method to "
+"return a list of the properties on this animation node. Parameters are "
+"custom local memory used for your animation nodes, given a resource can be "
+"reused in multiple trees. Format is similar to [method Object."
+"get_property_list]."
+msgstr ""
+"继承 [AnimationRootNode] 时,实现这个虚方法可以返回这个节点的属性列表。参数是"
+"动画节点的自定义本地存储,资源可以在多个树中重用。格式与 [method Object."
+"get_property_list] 类似。"
+
+msgid ""
+"When inheriting from [AnimationRootNode], implement this virtual method to "
+"return whether the blend tree editor should display filter editing on this "
+"animation node."
+msgstr ""
+"继承 [AnimationRootNode] 时,实现这个虚方法可以返回混合树编辑器是否应该在这个"
+"动画节点上显示过滤器编辑。"
+
+msgid ""
+"When inheriting from [AnimationRootNode], implement this virtual method to "
+"return whether the [param parameter] is read-only. Parameters are custom "
+"local memory used for your animation nodes, given a resource can be reused "
+"in multiple trees."
+msgstr ""
+"继承 [AnimationRootNode] 时,实现这个虚方法可以返回参数 [param parameter] 是"
+"否只读。参数是动画节点的自定义本地存储,资源可以在多个树中重用。"
+
+msgid ""
+"When inheriting from [AnimationRootNode], implement this virtual method to "
+"run some code when this animation node is processed. The [param time] "
+"parameter is a relative delta, unless [param seek] is [code]true[/code], in "
+"which case it is absolute.\n"
+"Here, call the [method blend_input], [method blend_node] or [method "
+"blend_animation] functions. You can also use [method get_parameter] and "
+"[method set_parameter] to modify local memory.\n"
+"This function should return the time left for the current animation to "
+"finish (if unsure, pass the value from the main blend being called)."
+msgstr ""
+"继承 [AnimationRootNode] 时,实现这个虚方法可以在这个动画节点进行处理时执行代"
+"码。参数 [param time] 是相对增量,除非 [param seek] 为 [code]true[/code],此"
+"时为绝对增量。\n"
+"请在此处调用 [method blend_input]、[method blend_node] 或 [method "
+"blend_animation] 函数。你也可以使用 [method get_parameter] 和 [method "
+"set_parameter] 来修改本地存储。\n"
+"这个函数应当返回当前动画还需多少时间完成(不确定的话,请传递调用主混合的"
+"值)。"
+
+msgid ""
+"Adds an input to the animation node. This is only useful for animation nodes "
+"created for use in an [AnimationNodeBlendTree]. If the addition fails, "
+"returns [code]false[/code]."
+msgstr ""
+"为节点添加一个输入。这只对创建用于 [AnimationNodeBlendTree] 的动画节点有用。"
+"如果添加失败,返回 [code]false[/code]。"
+
+msgid ""
"Blend an animation by [param blend] amount (name must be valid in the linked "
"[AnimationPlayer]). A [param time] and [param delta] may be passed, as well "
"as whether [param seeked] happened.\n"
@@ -7097,14 +7533,47 @@ msgstr ""
"LoopedFlag]。"
msgid ""
+"Blend an input. This is only useful for animation nodes created for an "
+"[AnimationNodeBlendTree]. The [param time] parameter is a relative delta, "
+"unless [param seek] is [code]true[/code], in which case it is absolute. A "
+"filter mode may be optionally passed (see [enum FilterAction] for options)."
+msgstr ""
+"混合一个输入。这只对为 [AnimationNodeBlendTree] 创建的动画节点有用。时间参数 "
+"[param time] 是一个相对的增量,除非 [param seek] 是 [code]true[/code],此时它"
+"是绝对的。可以选择传入过滤模式(选项请参阅 [enum FilterAction])。"
+
+msgid ""
+"Blend another animation node (in case this animation node contains children "
+"animation nodes). This function is only useful if you inherit from "
+"[AnimationRootNode] instead, else editors will not display your animation "
+"node for addition."
+msgstr ""
+"混合另一个动画节点(在这个动画节点包含子动画节点的情况下)。这个函数只有在你"
+"继承 [AnimationRootNode] 时才有用,否则编辑器在添加节点时不会显示你的动画节"
+"点。"
+
+msgid ""
"Returns the input index which corresponds to [param name]. If not found, "
"returns [code]-1[/code]."
msgstr ""
"返回与名称 [param name] 相关的输入索引,如果不存在则返回 [code]-1[/code]。"
+msgid ""
+"Amount of inputs in this animation node, only useful for animation nodes "
+"that go into [AnimationNodeBlendTree]."
+msgstr ""
+"这个动画节点的输入数量,只对进入 [AnimationNodeBlendTree] 的动画节点有用。"
+
msgid "Gets the name of an input by index."
msgstr "通过索引获取输入的名称。"
+msgid ""
+"Gets the value of a parameter. Parameters are custom local memory used for "
+"your animation nodes, given a resource can be reused in multiple trees."
+msgstr ""
+"获取一个参数的值。参数是你的动画节点使用的自定义本地内存,给定的资源可以在多"
+"个树中重复使用。"
+
msgid "Returns whether the given path is filtered."
msgstr "返回给定路径是否被过滤。"
@@ -7131,6 +7600,39 @@ msgstr ""
msgid "If [code]true[/code], filtering is enabled."
msgstr "如果为 [code]true[/code],则启用筛选功能。"
+msgid ""
+"Emitted by nodes that inherit from this class and that have an internal tree "
+"when one of their animation nodes removes. The animation nodes that emit "
+"this signal are [AnimationNodeBlendSpace1D], [AnimationNodeBlendSpace2D], "
+"[AnimationNodeStateMachine], and [AnimationNodeBlendTree]."
+msgstr ""
+"由继承自该类的节点发出,并且当其中一个动画节点移除时具有内部树。发出此信号的"
+"动画节点可以是 [AnimationNodeBlendSpace1D]、[AnimationNodeBlendSpace2D]、"
+"[AnimationNodeStateMachine] 和 [AnimationNodeBlendTree]。"
+
+msgid ""
+"Emitted by nodes that inherit from this class and that have an internal tree "
+"when one of their animation node names changes. The animation nodes that "
+"emit this signal are [AnimationNodeBlendSpace1D], "
+"[AnimationNodeBlendSpace2D], [AnimationNodeStateMachine], and "
+"[AnimationNodeBlendTree]."
+msgstr ""
+"由继承自该类的节点发出,并且当其中一个动画节点名称更改时具有内部树。发出此信"
+"号的动画节点可以是 [AnimationNodeBlendSpace1D]、[AnimationNodeBlendSpace2D]、"
+"[AnimationNodeStateMachine] 和 [AnimationNodeBlendTree]。"
+
+msgid ""
+"Emitted by nodes that inherit from this class and that have an internal tree "
+"when one of their animation nodes changes. The animation nodes that emit "
+"this signal are [AnimationNodeBlendSpace1D], [AnimationNodeBlendSpace2D], "
+"[AnimationNodeStateMachine], [AnimationNodeBlendTree] and "
+"[AnimationNodeTransition]."
+msgstr ""
+"由继承自该类的节点发出,并且当其一个动画节点发生变化时具有内部树。发出此信号"
+"的动画节点可以是 [AnimationNodeBlendSpace1D]、[AnimationNodeBlendSpace2D]、"
+"[AnimationNodeStateMachine]、[AnimationNodeBlendTree] 和 "
+"[AnimationNodeTransition]。"
+
msgid "Do not use filtering."
msgstr "不要使用筛选功能。"
@@ -7220,6 +7722,17 @@ msgid "Blends two animations linearly inside of an [AnimationNodeBlendTree]."
msgstr "在 [AnimationNodeBlendTree] 中将两个动画进行线性混合。"
msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Blends two animations "
+"linearly based on the amount value.\n"
+"In general, the blend value should be in the [code][0.0, 1.0][/code] range. "
+"Values outside of this range can blend amplified or inverted animations, "
+"however, [AnimationNodeAdd2] works better for this purpose."
+msgstr ""
+"添加到 [AnimationNodeBlendTree] 的资源。根据取值将两个动画进行线性混合。\n"
+"一般而言,混合值应该在 [code][0.0, 1.0][/code] 的范围内。超出该范围的值可以混"
+"合放大或翻转后的动画,然而,这种场合 [AnimationNodeAdd2] 的效果更好。"
+
+msgid ""
"Blends two of three animations linearly inside of an "
"[AnimationNodeBlendTree]."
msgstr "在 [AnimationNodeBlendTree] 中将三个动画中的两个进行线性混合。"
@@ -7254,6 +7767,21 @@ msgstr ""
"[AnimationTree] 使用。"
msgid ""
+"A resource used by [AnimationNodeBlendTree].\n"
+"[AnimationNodeBlendSpace1D] represents a virtual axis on which any type of "
+"[AnimationRootNode]s can be added using [method add_blend_point]. Outputs "
+"the linear blend of the two [AnimationRootNode]s adjacent to the current "
+"value.\n"
+"You can set the extents of the axis with [member min_space] and [member "
+"max_space]."
+msgstr ""
+"可添加到 [AnimationNodeBlendTree] 的资源。\n"
+"[AnimationNodeBlendSpace1D] 代表一个虚拟轴,可以使用 [method "
+"add_blend_point] 在上面添加任何类型的 [AnimationRootNode]。输出的是最接近当前"
+"值的两个 [AnimationRootNode] 之间的线性混合。\n"
+"可以使用 [member min_space] 和 [member max_space] 来扩展轴的范围。"
+
+msgid ""
"Adds a new point that represents a [param node] on the virtual axis at a "
"given position set by [param pos]. You can insert it at a specific index "
"using the [param at_index] argument. If you use the default value for [param "
@@ -8081,6 +8609,20 @@ msgstr ""
"除。"
msgid ""
+"Process animation during physics frames (see [constant Node."
+"NOTIFICATION_INTERNAL_PHYSICS_PROCESS]). This is especially useful when "
+"animating physics bodies."
+msgstr ""
+"在物理帧中处理动画(见 [constant Node."
+"NOTIFICATION_INTERNAL_PHYSICS_PROCESS])。尤其适用于对物理体进行动画处理。"
+
+msgid ""
+"Process animation during process frames (see [constant Node."
+"NOTIFICATION_INTERNAL_PROCESS])."
+msgstr ""
+"在处理帧中处理动画(见 [constant Node.NOTIFICATION_INTERNAL_PROCESS])。"
+
+msgid ""
"Do not process animation. Use [method advance] to process the animation "
"manually."
msgstr "不处理动画。使用[method advance]手动处理动画。"
@@ -9214,6 +9756,91 @@ msgstr ""
msgid "A built-in data structure that holds a sequence of elements."
msgstr "一种内置数据结构,包含一系列元素。"
+msgid ""
+"An array data structure that can contain a sequence of elements of any type. "
+"Elements are accessed by a numerical index starting at 0. Negative indices "
+"are used to count from the back (-1 is the last element, -2 is the second to "
+"last, etc.).\n"
+"[b]Example:[/b]\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"var array = [\"One\", 2, 3, \"Four\"]\n"
+"print(array[0]) # One.\n"
+"print(array[2]) # 3.\n"
+"print(array[-1]) # Four.\n"
+"array[2] = \"Three\"\n"
+"print(array[-2]) # Three.\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"var array = new Godot.Collections.Array{\"One\", 2, 3, \"Four\"};\n"
+"GD.Print(array[0]); // One.\n"
+"GD.Print(array[2]); // 3.\n"
+"GD.Print(array[array.Count - 1]); // Four.\n"
+"array[2] = \"Three\";\n"
+"GD.Print(array[array.Count - 2]); // Three.\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"Arrays can be concatenated using the [code]+[/code] operator:\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"var array1 = [\"One\", 2]\n"
+"var array2 = [3, \"Four\"]\n"
+"print(array1 + array2) # [\"One\", 2, 3, \"Four\"]\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"// Array concatenation is not possible with C# arrays, but is with Godot."
+"Collections.Array.\n"
+"var array1 = new Godot.Collections.Array{\"One\", 2};\n"
+"var array2 = new Godot.Collections.Array{3, \"Four\"};\n"
+"GD.Print(array1 + array2); // Prints [One, 2, 3, Four]\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"[b]Note:[/b] Arrays are always passed by reference. To get a copy of an "
+"array that can be modified independently of the original array, use [method "
+"duplicate].\n"
+"[b]Note:[/b] Erasing elements while iterating over arrays is [b]not[/b] "
+"supported and will result in unpredictable behavior."
+msgstr ""
+"通用数组,可以包含任意类型的多个元素,可以通过从 0 开始的数字索引进行访问。负"
+"数索引可以用来从后面数起,就像在 Python 中一样(-1 是最后一个元素、-2 是倒数"
+"第二,以此类推)。\n"
+"[b]示例:[/b]\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"var array = [\"One\", 2, 3, \"Four\"]\n"
+"print(array[0]) # One。\n"
+"print(array[2]) # 3。\n"
+"print(array[-1]) # Four。\n"
+"array[2] = \"Three\"\n"
+"print(array[-2]) # Three。\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"var array = new Godot.Collections.Array{\"One\", 2, 3, \"Four\"};\n"
+"GD.Print(array[0]); // One。\n"
+"GD.Print(array[2]); // 3。\n"
+"GD.Print(array[array.Count - 1]); // Four。\n"
+"array[2] = \"Three\";\n"
+"GD.Print(array[array.Count - 2]); // Three。\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"可以使用 [code]+[/code] 运算符连接数组:\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"var array1 = [\"One\", 2]\n"
+"var array2 = [3, \"Four\"]\n"
+"print(array1 + array2) # [\"One\", 2, 3, \"Four\"]\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"// C# 数组无法进行数组串联,但 Godot.Collections.Array 可以。\n"
+"var array1 = new Godot.Collections.Array{\"One\", 2};\n"
+"var array2 = new Godot.Collections.Array{3, \"Four\"};\n"
+"GD.Print(array1 + array2); // Prints [One, 2, 3, Four]\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"[b]注意:[/b]数组总是通过引用来传递。要获得一个可以独立于原始数组而被修改的数"
+"组的副本,请使用 [method duplicate]。\n"
+"[b]注意:[/b][b]不[/b]支持在遍历数组时擦除元素,这将导致不可预知的行为。"
+
msgid "Constructs an empty [Array]."
msgstr "构造空的 [Array]。"
@@ -9899,6 +10526,28 @@ msgstr ""
"另见 [method map]、[method filter]、[method any]、[method all]。"
msgid ""
+"Removes an element from the array by index. If the index does not exist in "
+"the array, nothing happens. To remove an element by searching for its value, "
+"use [method erase] instead.\n"
+"[b]Note:[/b] This method acts in-place and doesn't return a value.\n"
+"[b]Note:[/b] On large arrays, this method will be slower if the removed "
+"element is close to the beginning of the array (index 0). This is because "
+"all elements placed after the removed element have to be reindexed.\n"
+"[b]Note:[/b] [param position] cannot be negative. To remove an element "
+"relative to the end of the array, use [code]arr.remove_at(arr.size() - (i + "
+"1))[/code]. To remove the last element from the array without returning the "
+"value, use [code]arr.resize(arr.size() - 1)[/code]."
+msgstr ""
+"按索引从数组中移除一个元素。如果索引在数组中不存在,则什么也不会发生。要通过"
+"搜索一个元素的值来移除它,请使用 [method erase] 来代替。\n"
+"[b]注意:[/b]这个方法是就地操作,不返回值。\n"
+"[b]注意:[/b]在大数组中,如果被删除的元素靠近数组的开头(索引 0),这个方法会"
+"比较慢。这是因为所有放置在被移除元素之后的元素都要被重新索引。\n"
+"[b]注意:[/b][param position] 不能为负。要移除数组末尾的元素,请使用 "
+"[code]arr.remove_at(arr.size() - (i + 1))[/code]。要移除数组末尾的元素并不返"
+"回值,请使用 [code]arr.resize(arr.size() - 1)[/code]。"
+
+msgid ""
"Resizes the array to contain a different number of elements. If the array "
"size is smaller, elements are cleared, if bigger, new elements are "
"[code]null[/code]."
@@ -11436,6 +12085,16 @@ msgstr ""
"发生变化,需要在查找下一条路径之前调用 [method update]。"
msgid ""
+"The size of the grid (number of cells of size [member cell_size] on each "
+"axis). If changed, [method update] needs to be called before finding the "
+"next path.\n"
+"[i]Deprecated.[/i] Use [member region] instead."
+msgstr ""
+"栅格的大小(每个轴上大小为 [member cell_size] 的单元格数)。如果发生变化,需"
+"要在查找下一条路径之前调用 [method update]。\n"
+"[i]已弃用。[/i]请使用 [member region] 替代。"
+
+msgid ""
"The [url=https://en.wikipedia.org/wiki/Euclidean_distance]Euclidean "
"heuristic[/url] to be used for the pathfinding using the following formula:\n"
"[codeblock]\n"
@@ -13414,6 +14073,20 @@ msgid "Disables doppler tracking."
msgstr "禁用多普勒跟踪。"
msgid ""
+"Executes doppler tracking during process frames (see [constant Node."
+"NOTIFICATION_INTERNAL_PROCESS])."
+msgstr ""
+"在过程帧期间执行多普勒跟踪(请参阅 [constant Node."
+"NOTIFICATION_INTERNAL_PROCESS])。"
+
+msgid ""
+"Executes doppler tracking during physics frames (see [constant Node."
+"NOTIFICATION_INTERNAL_PHYSICS_PROCESS])."
+msgstr ""
+"在物理帧期间执行多普勒跟踪(请参阅 [constant Node."
+"NOTIFICATION_INTERNAL_PHYSICS_PROCESS])。"
+
+msgid ""
"AudioStream that lets the user play custom streams at any time from code, "
"simultaneously using a single player."
msgstr ""
@@ -13730,6 +14403,15 @@ msgid ""
msgstr "确定按钮何时被认为被点击,是 [enum ActionMode] 常量之一。"
msgid ""
+"The [ButtonGroup] associated with the button. Not to be confused with node "
+"groups.\n"
+"[b]Note:[/b] The button will be configured as a radio button if a "
+"[ButtonGroup] is assigned to it."
+msgstr ""
+"与按钮关联的 [ButtonGroup]。不要与节点组混淆。\n"
+"[b]注意:[/b]如果按钮被分配了 [ButtonGroup],则它将被配置为单选按钮。"
+
+msgid ""
"Binary mask to choose which mouse buttons this button will respond to.\n"
"To allow both left-click and right-click, use [code]MOUSE_BUTTON_MASK_LEFT | "
"MOUSE_BUTTON_MASK_RIGHT[/code]."
@@ -15702,7 +16384,7 @@ msgid ""
"and [code]b[2][/code] is equivalent to [code]b.z[/code]."
msgstr ""
"使用索引访问基的分量。[code]b[0][/code] 相当于 [code]b.x[/code]、[code]b[1][/"
-"code] 相当于 [code]b.y[/code]、[code] b[2][/code] 相当于 [code]b.z[/code]。"
+"code] 相当于 [code]b.y[/code]、[code]b[2][/code] 相当于 [code]b.z[/code]。"
msgid "Boolean matrix."
msgstr "布尔矩阵。"
@@ -16524,6 +17206,24 @@ msgstr ""
"调用该 [Callable] 所代表的方法。可以传递参数,必须与该方法的签名相匹配。"
msgid ""
+"Calls the method represented by this [Callable] in deferred mode, i.e. at "
+"the end of the current frame. Arguments can be passed and should match the "
+"method's signature.\n"
+"[codeblock]\n"
+"func _ready():\n"
+" grab_focus.call_deferred()\n"
+"[/codeblock]\n"
+"See also [method Object.call_deferred]."
+msgstr ""
+"使用延迟模式调用该 [Callable] 所代表的方法,即在当前帧的末尾调用。可以传递参"
+"数,必须与该方法的签名相匹配。\n"
+"[codeblock]\n"
+"func _ready():\n"
+" grab_focus.call_deferred()\n"
+"[/codeblock]\n"
+"另见 [method Object.call_deferred]。"
+
+msgid ""
"Calls the method represented by this [Callable]. Unlike [method call], this "
"method expects all arguments to be contained inside the [param arguments] "
"[Array]."
@@ -16606,27 +17306,6 @@ msgstr ""
"[code]true[/code]。"
msgid ""
-"Perform an RPC (Remote Procedure Call). This is used for multiplayer and is "
-"normally not available, unless the function being called has been marked as "
-"[i]RPC[/i]. Calling this method on unsupported functions will result in an "
-"error. See [method Node.rpc]."
-msgstr ""
-"执行 RPC(Remote Procedure Call,远程过程调用)。用于多人游戏,一般不可用,除"
-"非所调用的函数有 [i]RPC[/i] 标记。在不支持的方法上调用该方法会导致出错。见 "
-"[method Node.rpc]。"
-
-msgid ""
-"Perform an RPC (Remote Procedure Call) on a specific peer ID (see "
-"multiplayer documentation for reference). This is used for multiplayer and "
-"is normally not available unless the function being called has been marked "
-"as [i]RPC[/i]. Calling this method on unsupported functions will result in "
-"an error. See [method Node.rpc_id]."
-msgstr ""
-"针对特定的对等体 ID(请参阅多人游戏文档)执行 RPC(Remote Procedure Call,远"
-"程过程调用)。用于多人游戏,一般不可用,除非所调用的函数有 [i]RPC[/i] 标记。"
-"在不支持的方法上调用该方法会导致出错。见 [method Node.rpc_id]。"
-
-msgid ""
"Returns a copy of this [Callable] with a number of arguments unbound. In "
"other words, when the new callable is called the last few arguments supplied "
"by the user are ignored, according to [param argcount]. The remaining "
@@ -17059,6 +17738,20 @@ msgid ""
"screen size."
msgstr "相机的位置要考虑垂直/水平偏移和屏幕尺寸。"
+msgid ""
+"The camera updates during physics frames (see [constant Node."
+"NOTIFICATION_INTERNAL_PHYSICS_PROCESS])."
+msgstr ""
+"相机在物理帧期间更新(请参阅 [constant Node.NOTIFICATION_INTERVAL "
+"_PHYSICS_PROCESS])。"
+
+msgid ""
+"The camera updates during process frames (see [constant Node."
+"NOTIFICATION_INTERNAL_PROCESS])."
+msgstr ""
+"相机在进程帧期间更新(请参阅 [constant Node."
+"NOTIFICATION_INTERNAL_PROCESS])。"
+
msgid "Camera node, displays from a point of view."
msgstr "相机节点,会从某个角度进行显示。"
@@ -22967,6 +23660,9 @@ msgstr "矩形拾取器形状的图标。"
msgid "The icon for rectangular wheel picker shapes."
msgstr "矩形轮拾取器形状的图标。"
+msgid "A button that brings up a [ColorPicker] when pressed."
+msgstr "点击后会显示 [ColorPicker] 的按钮。"
+
msgid ""
"Returns the [ColorPicker] that this node toggles.\n"
"[b]Warning:[/b] This is a required internal node, removing and freeing it "
@@ -23725,6 +24421,14 @@ msgid ""
msgstr "取消按钮显示的文本(见 [method get_cancel_button])。"
msgid ""
+"Base class for all GUI containers. A [Container] automatically arranges its "
+"child controls in a certain way. This class can be inherited to make custom "
+"container types."
+msgstr ""
+"所有 GUI 容器的基础节点。[Container] 包含其他控件,并自动以某种方式排列它们。"
+"可以继承此类来生成自定义的容器类。"
+
+msgid ""
"Implement to return a list of allowed horizontal [enum Control.SizeFlags] "
"for child nodes. This doesn't technically prevent the usages of any other "
"size flags, if your implementation requires that. This only limits the "
@@ -29688,6 +30392,29 @@ msgstr ""
"持的平台上返回 [code]72[/code]。"
msgid ""
+"Returns screenshot of the [param screen].\n"
+"[b]Note:[/b] This method is implemented on Linux (X11), macOS, and Windows.\n"
+"[b]Note:[/b] On macOS, this method requires \"Screen Recording\" permission, "
+"if permission is not granted it will return desktop wallpaper color."
+msgstr ""
+"返回 [param screen] 的屏幕截图。\n"
+"[b]注意:[/b]该方法在 Linux(X11)、macOS 和 Windows 上实现。\n"
+"[b]注意:[/b]在 macOS 上,该方法需要“屏幕录制”权限,如果未授予权限将返回桌面"
+"壁纸颜色。"
+
+msgid ""
+"Returns the greatest scale factor of all screens.\n"
+"[b]Note:[/b] On macOS returned value is [code]2.0[/code] if there is at "
+"least one hiDPI (Retina) screen in the system, and [code]1.0[/code] in all "
+"other cases.\n"
+"[b]Note:[/b] This method is implemented only on macOS."
+msgstr ""
+"返回所有屏幕的最大缩放系数。\n"
+"[b]注意:[/b]在 macOS 上,如果系统中至少有一个 hiDPI(Retina)屏幕,则返回值"
+"为 [code]2.0[/code],在所有其他情况下返回值为 [code]1.0[/code] 。\n"
+"[b]注意:[/b]该方法仅在 macOS 上实现。"
+
+msgid ""
"Returns the [param screen]'s current orientation. See also [method "
"screen_set_orientation].\n"
"[b]Note:[/b] This method is implemented on Android and iOS."
@@ -29696,6 +30423,17 @@ msgstr ""
"[b]注意:[/b]该方法在 Android 和 iOS 上实现。"
msgid ""
+"Returns color of the display pixel at the [param position].\n"
+"[b]Note:[/b] This method is implemented on Linux (X11), macOS, and Windows.\n"
+"[b]Note:[/b] On macOS, this method requires \"Screen Recording\" permission, "
+"if permission is not granted it will return desktop wallpaper color."
+msgstr ""
+"返回 [param position] 处的显示像素的颜色。\n"
+"[b]注意:[/b]该方法在 Linux(X11)、macOS 和 Windows 上实现。\n"
+"[b]注意:[/b]在 macOS 上,该方法需要“屏幕录制”权限,如果未授予权限将返回桌面"
+"壁纸颜色。"
+
+msgid ""
"Returns the screen's top-left corner position in pixels. On multi-monitor "
"setups, the screen position is relative to the virtual desktop area. On "
"multi-monitor setups with different screen resolutions or orientations, the "
@@ -29751,6 +30489,17 @@ msgstr ""
"[/codeblock]"
msgid ""
+"Returns the scale factor of the specified screen by index.\n"
+"[b]Note:[/b] On macOS returned value is [code]2.0[/code] for hiDPI (Retina) "
+"screen, and [code]1.0[/code] for all other cases.\n"
+"[b]Note:[/b] This method is implemented only on macOS."
+msgstr ""
+"返回按索引指定的屏幕的缩放系数。\n"
+"[b]注意:[/b]在 macOS 上,对于 hiDPI (Retina) 屏幕,返回值为 [code]2.0[/"
+"code];对于所有其他情况,返回值为 [code]1.0[/code]。\n"
+"[b]注意:[/b]该方法仅在 macOS 上实现。"
+
+msgid ""
"Returns the screen's size in pixels. See also [method screen_get_position] "
"and [method screen_get_usable_rect]."
msgstr ""
@@ -29779,6 +30528,17 @@ msgstr ""
"screen_is_kept_on]。"
msgid ""
+"Sets the [param screen]'s [param orientation]. See also [method "
+"screen_get_orientation].\n"
+"[b]Note:[/b] On iOS, this method has no effect if [member ProjectSettings."
+"display/window/handheld/orientation] is not set to [constant SCREEN_SENSOR]."
+msgstr ""
+"设置 [param screen] 的 [param orientation]。另见 [method "
+"screen_get_orientation]。\n"
+"[b]注意:[/b]在 iOS 上,如果 [member ProjectSettings.display/window/handheld/"
+"orientation] 未设置为 [constant SCREEN_SENSOR],则该方法无效。"
+
+msgid ""
"Sets the window icon (usually displayed in the top-left corner) with an "
"[Image]. To use icons in the operating system's native format, use [method "
"set_native_icon] instead."
@@ -29804,6 +30564,112 @@ msgstr ""
"式的图标,请改用 [method set_icon]。"
msgid ""
+"Returns current active tablet driver name.\n"
+"[b]Note:[/b] This method is implemented only on Windows."
+msgstr ""
+"返回当前活动的数位板驱动程序的名称。\n"
+"[b]注意:[/b]该方法仅在 Windows 上实现。"
+
+msgid ""
+"Returns the total number of available tablet drivers.\n"
+"[b]Note:[/b] This method is implemented only on Windows."
+msgstr ""
+"返回可用的数位板驱动程序的总数。\n"
+"[b]注意:[/b]该方法仅在 Windows 上实现。"
+
+msgid ""
+"Returns the tablet driver name for the given index.\n"
+"[b]Note:[/b] This method is implemented only on Windows."
+msgstr ""
+"返回给定索引的数位板驱动程序名称。\n"
+"[b]注意:[/b]该方法仅在 Windows 上实现。"
+
+msgid ""
+"Set active tablet driver name.\n"
+"[b]Note:[/b] This method is implemented only on Windows."
+msgstr ""
+"设置活动的数位板驱动程序的名称。\n"
+"[b]注意:[/b]该方法仅在 Windows 上实现。"
+
+msgid ""
+"Returns an [Array] of voice information dictionaries.\n"
+"Each [Dictionary] contains two [String] entries:\n"
+"- [code]name[/code] is voice name.\n"
+"- [code]id[/code] is voice identifier.\n"
+"- [code]language[/code] is language code in [code]lang_Variant[/code] "
+"format. [code]lang[/code] part is a 2 or 3-letter code based on the ISO-639 "
+"standard, in lowercase. And [code]Variant[/code] part is an engine dependent "
+"string describing country, region or/and dialect.\n"
+"Note that Godot depends on system libraries for text-to-speech "
+"functionality. These libraries are installed by default on Windows and "
+"macOS, but not on all Linux distributions. If they are not present, this "
+"method will return an empty list. This applies to both Godot users on Linux, "
+"as well as end-users on Linux running Godot games that use text-to-speech.\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), "
+"macOS, and Windows.\n"
+"[b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be "
+"[code]true[/code] to use text-to-speech."
+msgstr ""
+"返回语音信息字典的 [Array]。\n"
+"每个 [Dictionary] 包含两个 [String] 条目:\n"
+"- [code]name[/code] 是语音名称。\n"
+"- [code]id[/code] 是语音标识符。\n"
+"- [code]language[/code] 是语言代码,格式为 [code]lang_Variant[/code] 。"
+"[code]lang[/code] 部分是小写的基于 ISO-639 标准的 2 或 3 字母代码。而 "
+"[code]Variant[/code] 部分是一个依赖于引擎的字符串,描述国家、地区或/和方"
+"言。\n"
+"请注意,Godot 依赖于系统库来实现文本到语音的功能。这些库在 Windows 和 MacOS "
+"上是默认安装的,但并非安装在所有 Linux 发行版上。如果它们不存在,此方法将返回"
+"一个空列表。这适用于 Linux 上的 Godot 用户,以及在 Linux 上运行使用文本到语音"
+"的 Godot 游戏的最终用户。\n"
+"[b]注意:[/b]这个方法在 Android、iOS、Web、Linux(X11)、macOS 和 Windows 上"
+"实现。\n"
+"[b]注意:[/b][member ProjectSettings.audio/general/text_to_speech] 应当为 "
+"[code]true[/code] 才能够使用文本到语音功能。"
+
+msgid ""
+"Returns an [PackedStringArray] of voice identifiers for the [param "
+"language].\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), "
+"macOS, and Windows.\n"
+"[b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be "
+"[code]true[/code] to use text-to-speech."
+msgstr ""
+"返回 [param language] 的语音标识符的 [PackedStringArray]。\n"
+"[b]注意:[/b]该方法在 Android、iOS、Web、Linux(X11)、macOS 和 Windows 上实"
+"现。\n"
+"[b]注意:[/b][member ProjectSettings.audio/general/text_to_speech] 应为 "
+"[code]true[/code] 才能使用文本转语音。"
+
+msgid ""
+"Returns [code]true[/code] if the synthesizer is in a paused state.\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), "
+"macOS, and Windows.\n"
+"[b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be "
+"[code]true[/code] to use text-to-speech."
+msgstr ""
+"如果合成器处于暂停状态,则返回 [code]true[/code]。\n"
+"[b]注意:[/b]该方法在 Android、iOS、Web、Linux(X11)、macOS 和 Windows 上实"
+"现。\n"
+"[b]注意:[/b][member ProjectSettings.audio/general/text_to_speech] 应为 "
+"[code]true[/code] 才能使用文本转语音。"
+
+msgid ""
+"Returns [code]true[/code] if the synthesizer is generating speech, or have "
+"utterance waiting in the queue.\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), "
+"macOS, and Windows.\n"
+"[b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be "
+"[code]true[/code] to use text-to-speech."
+msgstr ""
+"如果合成器正在生成语音,或者有发言正在队列中等待,则返回 [code]true[/"
+"code]。\n"
+"[b]注意:[/b]该方法在 Android、iOS、Web、Linux(X11)、macOS 和 Windows 上实"
+"现。\n"
+"[b]注意:[/b][member ProjectSettings.audio/general/text_to_speech] 应为 "
+"[code]true[/code] 才能使用文本转语音。"
+
+msgid ""
"Returns the on-screen keyboard's height in pixels. Returns 0 if there is no "
"keyboard or if it is currently hidden."
msgstr ""
@@ -31623,6 +32489,570 @@ msgstr ""
"如果为空,则回退到 [code]EditorSettings.export/android/debug_keystore[/"
"code]。"
+msgid ""
+"Allows read/write access to the \"properties\" table in the checkin "
+"database. See [url=https://developer.android.com/reference/android/Manifest."
+"permission#ACCESS_CHECKIN_PROPERTIES]ACCESS_CHECKIN_PROPERTIES[/url]."
+msgstr ""
+"允许对签到数据库的“properties”表进行读写访问。见 [url=https://developer."
+"android.com/reference/android/Manifest."
+"permission#ACCESS_CHECKIN_PROPERTIES]ACCESS_CHECKIN_PROPERTIES[/url]。"
+
+msgid ""
+"Allows access to the approximate location information. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#ACCESS_COARSE_LOCATION]ACCESS_COARSE_LOCATION[/url]."
+msgstr ""
+"允许访问大致位置信息。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#ACCESS_COARSE_LOCATION]ACCESS_COARSE_LOCATION[/"
+"url]。"
+
+msgid ""
+"Allows access to the precise location information. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#ACCESS_FINE_LOCATION]ACCESS_FINE_LOCATION[/url]."
+msgstr ""
+"允许访问精确位置信息。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#ACCESS_FINE_LOCATION]ACCESS_FINE_LOCATION[/url]。"
+
+msgid ""
+"Allows access to the extra location provider commands. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#ACCESS_LOCATION_EXTRA_COMMANDS]ACCESS_LOCATION_EXTRA_COMMANDS[/"
+"url]."
+msgstr ""
+"允许对额外位置提供方命令的访问。见 [url=https://developer.android.com/"
+"reference/android/Manifest."
+"permission#ACCESS_LOCATION_EXTRA_COMMANDS]ACCESS_LOCATION_EXTRA_COMMANDS[/"
+"url]。"
+
+msgid "Allows an application to create mock location providers for testing."
+msgstr "允许应用程序为测试目的创建 Mock 位置提供方。"
+
+msgid ""
+"Allows access to the information about networks. See [url=https://developer."
+"android.com/reference/android/Manifest."
+"permission#ACCESS_NETWORK_STATE]ACCESS_NETWORK_STATE[/url]."
+msgstr ""
+"允许对网络相关信息进行访问。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#ACCESS_NETWORK_STATE]ACCESS_NETWORK_STATE[/url]。"
+
+msgid "Allows an application to use SurfaceFlinger's low level features."
+msgstr "允许应用程序使用 SurfaceFlinger 的底层特性。"
+
+msgid ""
+"Allows access to the information about Wi-Fi networks. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#ACCESS_WIFI_STATE]ACCESS_WIFI_STATE[/url]."
+msgstr ""
+"允许对 Wi-Fi 网络相关信息进行访问。见 [url=https://developer.android.com/"
+"reference/android/Manifest.permission#ACCESS_WIFI_STATE]ACCESS_WIFI_STATE[/"
+"url]。"
+
+msgid ""
+"Allows applications to call into AccountAuthenticators. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#ACCOUNT_MANAGER]ACCOUNT_MANAGER[/url]."
+msgstr ""
+"允许应用程序对 AccountAuthenticator 进行调用。见 [url=https://developer."
+"android.com/reference/android/Manifest."
+"permission#ACCOUNT_MANAGER]ACCOUNT_MANAGER[/url]。"
+
+msgid ""
+"Allows an application to add voicemails into the system. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#ADD_VOICEMAIL]ADD_VOICEMAIL[/url]."
+msgstr ""
+"允许应用程序向系统中添加语音邮件。见 [url=https://developer.android.com/"
+"reference/android/Manifest.permission#ADD_VOICEMAIL]ADD_VOICEMAIL[/url]。"
+
+msgid ""
+"Allows an application to act as an AccountAuthenticator for the "
+"AccountManager."
+msgstr "允许应用程序在 AccountManager 中扮演 AccountAuthenticator 的角色。"
+
+msgid ""
+"Allows an application to collect battery statistics. Sett [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#BATTERY_STATS]BATTERY_STATS[/url]."
+msgstr ""
+"允许应用程序收集电池统计信息。见 [url=https://developer.android.com/"
+"reference/android/Manifest.permission#BATTERY_STATS]BATTERY_STATS[/url]。"
+
+msgid ""
+"Must be required by an AccessibilityService, to ensure that only the system "
+"can bind to it. See [url=https://developer.android.com/reference/android/"
+"Manifest.permission#BIND_ACCESSIBILITY_SERVICE]BIND_ACCESSIBILITY_SERVICE[/"
+"url]."
+msgstr ""
+"AccessibilityService 必须要求此权限,确保只能系统能够进行绑定。见 "
+"[url=https://developer.android.com/reference/android/Manifest."
+"permission#BIND_ACCESSIBILITY_SERVICE]BIND_ACCESSIBILITY_SERVICE[/url]。"
+
+msgid ""
+"Allows an application to receive the Intent.ACTION_BOOT_COMPLETED that is "
+"broadcast after the system finishes booting. See [url=https://developer."
+"android.com/reference/android/Manifest."
+"permission#RECEIVE_BOOT_COMPLETED]RECEIVE_BOOT_COMPLETED[/url]."
+msgstr ""
+"允许应用程序接收系统启动完成后广播的 Intent.ACTION_BOOT_COMPLETED。见 "
+"[url=https://developer.android.com/reference/android/Manifest."
+"permission#RECEIVE_BOOT_COMPLETED]RECEIVE_BOOT_COMPLETED[/url]。"
+
+msgid ""
+"Allows an application to monitor incoming MMS messages. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#RECEIVE_MMS]RECEIVE_MMS[/url]."
+msgstr ""
+"允许应用程序监听收到的 MMS 消息。见 [url=https://developer.android.com/"
+"reference/android/Manifest.permission#RECEIVE_MMS]RECEIVE_MMS[/url]。"
+
+msgid ""
+"Allows an application to receive SMS messages. See [url=https://developer."
+"android.com/reference/android/Manifest.permission#RECEIVE_SMS]RECEIVE_SMS[/"
+"url]."
+msgstr ""
+"允许应用程序接收短信。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#RECEIVE_SMS]RECEIVE_SMS[/url]。"
+
+msgid ""
+"Allows an application to receive WAP push messages. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#RECEIVE_WAP_PUSH]RECEIVE_WAP_PUSH[/url]."
+msgstr ""
+"允许应用程序接收 WAP 推送消息。见 [url=https://developer.android.com/"
+"reference/android/Manifest.permission#RECEIVE_WAP_PUSH]RECEIVE_WAP_PUSH[/"
+"url]。"
+
+msgid ""
+"Allows an application to record audio. See [url=https://developer.android."
+"com/reference/android/Manifest.permission#RECORD_AUDIO]RECORD_AUDIO[/url]."
+msgstr ""
+"允许应用程序录音。见 [url=https://developer.android.com/reference/android/"
+"Manifest.permission#RECORD_AUDIO]RECORD_AUDIO[/url]。"
+
+msgid ""
+"Allows an application to change the Z-order of tasks. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#REORDER_TASKS]REORDER_TASKS[/url]."
+msgstr ""
+"允许应用程序对任务的 Z 顺序进行修改。见 [url=https://developer.android.com/"
+"reference/android/Manifest.permission#REORDER_TASKS]REORDER_TASKS[/url]。"
+
+msgid "Deprecated in API level 15."
+msgstr "API 级别 15 中废弃。"
+
+msgid ""
+"Allows an application (Phone) to send a request to other applications to "
+"handle the respond-via-message action during incoming calls. See "
+"[url=https://developer.android.com/reference/android/Manifest."
+"permission#SEND_RESPOND_VIA_MESSAGE]SEND_RESPOND_VIA_MESSAGE[/url]."
+msgstr ""
+"允许应用程序(手机)在接听电话时向其他应用程序发送对“通过短信回复”动作的处理"
+"请求。见 [url=https://developer.android.com/reference/android/Manifest."
+"permission#SEND_RESPOND_VIA_MESSAGE]SEND_RESPOND_VIA_MESSAGE[/url]。"
+
+msgid ""
+"Allows an application to send SMS messages. See [url=https://developer."
+"android.com/reference/android/Manifest.permission#SEND_SMS]SEND_SMS[/url]."
+msgstr ""
+"允许应用程序发送短信。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#SEND_SMS]SEND_SMS[/url]。"
+
+msgid ""
+"Allows an application to watch and control how activities are started "
+"globally in the system."
+msgstr "允许应用程序对系统如何启动 Activity 进行全局监听和控制。"
+
+msgid ""
+"Allows an application to broadcast an Intent to set an alarm for the user. "
+"See [url=https://developer.android.com/reference/android/Manifest."
+"permission#SET_ALARM]SET_ALARM[/url]."
+msgstr ""
+"允许应用程序对设置用户闹钟的 Intent 进行广播。见 [url=https://developer."
+"android.com/reference/android/Manifest.permission#SET_ALARM]SET_ALARM[/url]。"
+
+msgid ""
+"Allows an application to control whether activities are immediately finished "
+"when put in the background. See [url=https://developer.android.com/reference/"
+"android/Manifest.permission#SET_ALWAYS_FINISH]SET_ALWAYS_FINISH[/url]."
+msgstr ""
+"允许应用程序对进入后台时是否立即终止 Activity 进行控制。见 [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#SET_ALWAYS_FINISH]SET_ALWAYS_FINISH[/url]。"
+
+msgid ""
+"Allows to modify the global animation scaling factor. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#SET_ANIMATION_SCALE]SET_ANIMATION_SCALE[/url]."
+msgstr ""
+"允许对全局动画缩放系数进行修改。见 [url=https://developer.android.com/"
+"reference/android/Manifest."
+"permission#SET_ANIMATION_SCALE]SET_ANIMATION_SCALE[/url]。"
+
+msgid ""
+"Configure an application for debugging. See [url=https://developer.android."
+"com/reference/android/Manifest.permission#SET_DEBUG_APP]SET_DEBUG_APP[/url]."
+msgstr ""
+"对应用程序进行调试配置。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#SET_DEBUG_APP]SET_DEBUG_APP[/url]。"
+
+msgid ""
+"Allows low-level access to setting the orientation (actually rotation) of "
+"the screen."
+msgstr "允许对设置屏幕朝向(本质为旋转)的功能进行底层访问。"
+
+msgid "Allows low-level access to setting the pointer speed."
+msgstr "允许对设置指针速度的功能进行底层访问。"
+
+msgid ""
+"Allows an application to set the maximum number of (not needed) application "
+"processes that can be running. See [url=https://developer.android.com/"
+"reference/android/Manifest.permission#SET_PROCESS_LIMIT]SET_PROCESS_LIMIT[/"
+"url]."
+msgstr ""
+"允许应用程序对同时能够运行的最大(不再需要的)应用程序进程数进行设置。见 "
+"[url=https://developer.android.com/reference/android/Manifest."
+"permission#SET_PROCESS_LIMIT]SET_PROCESS_LIMIT[/url]。"
+
+msgid ""
+"Allows applications to set the system time directly. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#SET_TIME]SET_TIME[/url]."
+msgstr ""
+"允许应用程序对系统时间进行直接设置。见 [url=https://developer.android.com/"
+"reference/android/Manifest.permission#SET_TIME]SET_TIME[/url]。"
+
+msgid ""
+"Allows applications to set the system time zone directly. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#SET_TIME_ZONE]SET_TIME_ZONE[/url]."
+msgstr ""
+"允许应用程序对系统时区进行直接设置。见 [url=https://developer.android.com/"
+"reference/android/Manifest.permission#SET_TIME_ZONE]SET_TIME_ZONE[/url]。"
+
+msgid ""
+"Allows applications to set the wallpaper. See [url=https://developer.android."
+"com/reference/android/Manifest.permission#SET_WALLPAPER]SET_WALLPAPER[/url]."
+msgstr ""
+"允许应用程序对壁纸进行设置。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#SET_WALLPAPER]SET_WALLPAPER[/url]。"
+
+msgid ""
+"Allows applications to set the wallpaper hints. See [url=https://developer."
+"android.com/reference/android/Manifest."
+"permission#SET_WALLPAPER_HINTS]SET_WALLPAPER_HINTS[/url]."
+msgstr ""
+"允许应用程序对壁纸提示进行设置。见 [url=https://developer.android.com/"
+"reference/android/Manifest."
+"permission#SET_WALLPAPER_HINTS]SET_WALLPAPER_HINTS[/url]。"
+
+msgid ""
+"Allow an application to request that a signal be sent to all persistent "
+"processes. See [url=https://developer.android.com/reference/android/Manifest."
+"permission#SIGNAL_PERSISTENT_PROCESSES]SIGNAL_PERSISTENT_PROCESSES[/url]."
+msgstr ""
+"允许应用程序请求将信号发送到所有持久化进程。见 [url=https://developer."
+"android.com/reference/android/Manifest."
+"permission#SIGNAL_PERSISTENT_PROCESSES]SIGNAL_PERSISTENT_PROCESSES[/url]。"
+
+msgid ""
+"Allows an application to open, close, or disable the status bar and its "
+"icons. See [url=https://developer.android.com/reference/android/Manifest."
+"permission#STATUS_BAR]STATUS_BAR[/url]."
+msgstr ""
+"允许应用程序对状态栏及其图标进行打开、关闭、禁用等操作。见 [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#STATUS_BAR]STATUS_BAR[/url]。"
+
+msgid ""
+"Allows an application to allow access the subscribed feeds ContentProvider."
+msgstr "允许应用程序对订阅的 ContentProvider 源进行访问。"
+
+msgid ""
+"Allows an app to create windows using the type WindowManager.LayoutParams."
+"TYPE_APPLICATION_OVERLAY, shown on top of all other apps. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#SYSTEM_ALERT_WINDOW]SYSTEM_ALERT_WINDOW[/url]."
+msgstr ""
+"允许应用使用 WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY 类型创建显示"
+"在其他应用之上的窗口。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#SYSTEM_ALERT_WINDOW]SYSTEM_ALERT_WINDOW[/url]。"
+
+msgid ""
+"Allows using the device's IR transmitter, if available. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#TRANSMIT_IR]TRANSMIT_IR[/url]."
+msgstr ""
+"允许使用该设备的 IR 发送器。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#TRANSMIT_IR]TRANSMIT_IR[/url]。"
+
+msgid ""
+"Allows an application to update device statistics. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#UPDATE_DEVICE_STATS]UPDATE_DEVICE_STATS[/url]."
+msgstr ""
+"允许应用程序对设备统计信息进行更新。见 [url=https://developer.android.com/"
+"reference/android/Manifest."
+"permission#UPDATE_DEVICE_STATS]UPDATE_DEVICE_STATS[/url]。"
+
+msgid "Allows an application to request authtokens from the AccountManager."
+msgstr "允许应用程序向 AccountManager 请求授权令牌。"
+
+msgid ""
+"Allows an application to use SIP service. See [url=https://developer.android."
+"com/reference/android/Manifest.permission#USE_SIP]USE_SIP[/url]."
+msgstr ""
+"允许应用程序使用 SIP 服务。见 [url=https://developer.android.com/reference/"
+"android/Manifest.permission#USE_SIP]USE_SIP[/url]。"
+
+msgid ""
+"Allows access to the vibrator. See [url=https://developer.android.com/"
+"reference/android/Manifest.permission#VIBRATE]VIBRATE[/url]."
+msgstr ""
+"允许访问振动器。见 [url=https://developer.android.com/reference/android/"
+"Manifest.permission#VIBRATE]VIBRATE[/url]。"
+
+msgid ""
+"Allows using PowerManager WakeLocks to keep processor from sleeping or "
+"screen from dimming. See [url=https://developer.android.com/reference/"
+"android/Manifest.permission#WAKE_LOCK]WAKE_LOCK[/url]."
+msgstr ""
+"允许使用 PowerManager WakeLock 放置处理器进入休眠或屏幕变暗。见 [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#WAKE_LOCK]WAKE_LOCK[/url]。"
+
+msgid ""
+"Allows applications to write the apn settings and read sensitive fields of "
+"an existing apn settings like user and password. See [url=https://developer."
+"android.com/reference/android/Manifest."
+"permission#WRITE_APN_SETTINGS]WRITE_APN_SETTINGS[/url]."
+msgstr ""
+"允许应用程序写入 APN 设置并读取已有 APN 设置中的用户名、密码等敏感字段。见 "
+"[url=https://developer.android.com/reference/android/Manifest."
+"permission#WRITE_APN_SETTINGS]WRITE_APN_SETTINGS[/url]。"
+
+msgid ""
+"Allows an application to write the user's calendar data. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#WRITE_CALENDAR]WRITE_CALENDAR[/url]."
+msgstr ""
+"允许应用程序对用户的日历数据进行写操作。见 [url=https://developer.android."
+"com/reference/android/Manifest.permission#WRITE_CALENDAR]WRITE_CALENDAR[/"
+"url]。"
+
+msgid ""
+"Allows an application to write (but not read) the user's call log data. See "
+"[url=https://developer.android.com/reference/android/Manifest."
+"permission#WRITE_CALL_LOG]WRITE_CALL_LOG[/url]."
+msgstr ""
+"允许应用程序对用户的通话记录数据进行写操作(不会允许读操作)。见 "
+"[url=https://developer.android.com/reference/android/Manifest."
+"permission#WRITE_CALL_LOG]WRITE_CALL_LOG[/url]。"
+
+msgid ""
+"Allows an application to write the user's contacts data. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#WRITE_CONTACTS]WRITE_CONTACTS[/url]."
+msgstr ""
+"允许应用程序对用户的通讯录数据进行写操作。见 [url=https://developer.android."
+"com/reference/android/Manifest.permission#WRITE_CONTACTS]WRITE_CONTACTS[/"
+"url]。"
+
+msgid ""
+"Allows an application to write to external storage. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#WRITE_EXTERNAL_STORAGE]WRITE_EXTERNAL_STORAGE[/url]."
+msgstr ""
+"允许应用程序对外部存储进行写操作。见 [url=https://developer.android.com/"
+"reference/android/Manifest."
+"permission#WRITE_EXTERNAL_STORAGE]WRITE_EXTERNAL_STORAGE[/url]。"
+
+msgid ""
+"Allows an application to modify the Google service map. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#WRITE_GSERVICES]WRITE_GSERVICES[/url]."
+msgstr ""
+"允许应用程序对 Google 服务映射进行修改。见 [url=https://developer.android."
+"com/reference/android/Manifest.permission#WRITE_GSERVICES]WRITE_GSERVICES[/"
+"url]。"
+
+msgid ""
+"Allows an application to write (but not read) the user's browsing history "
+"and bookmarks."
+msgstr "允许应用程序对用户的浏览器历史和收藏进行写操作(不会允许读操作)。"
+
+msgid ""
+"Allows an application to write (but not read) the user's personal profile "
+"data."
+msgstr "允许应用程序对用户的个人信息数据进行写操作(不会允许读操作)。"
+
+msgid ""
+"Allows an application to read or write the secure system settings. See "
+"[url=https://developer.android.com/reference/android/Manifest."
+"permission#WRITE_SECURE_SETTINGS]WRITE_SECURE_SETTINGS[/url]."
+msgstr ""
+"允许应用程序对安全系统设置进行读写操作。见 [url=https://developer.android."
+"com/reference/android/Manifest."
+"permission#WRITE_SECURE_SETTINGS]WRITE_SECURE_SETTINGS[/url]。"
+
+msgid ""
+"Allows an application to read or write the system settings. See [url=https://"
+"developer.android.com/reference/android/Manifest."
+"permission#WRITE_SETTINGS]WRITE_SETTINGS[/url]."
+msgstr ""
+"允许应用程序对系统设置进行读写操作。见 [url=https://developer.android.com/"
+"reference/android/Manifest.permission#WRITE_SETTINGS]WRITE_SETTINGS[/url]。"
+
+msgid "Allows an application to write SMS messages."
+msgstr "允许应用程序发送短信。"
+
+msgid ""
+"Allows an application to write (but not read) the user's social stream data."
+msgstr "允许应用程序对用户的社交流数据进行写操作(不会允许读操作)。"
+
+msgid ""
+"Allows applications to write the sync settings. See [url=https://developer."
+"android.com/reference/android/Manifest."
+"permission#WRITE_SYNC_SETTINGS]WRITE_SYNC_SETTINGS[/url]."
+msgstr ""
+"允许应用程序对同步设置进行写操作。见 [url=https://developer.android.com/"
+"reference/android/Manifest."
+"permission#WRITE_SYNC_SETTINGS]WRITE_SYNC_SETTINGS[/url]。"
+
+msgid "Allows an application to write to the user dictionary."
+msgstr "允许应用程序对用户字典进行写操作。"
+
+msgid "If [code]true[/code], hides navigation and status bar."
+msgstr "如果为 [code]true[/code],则隐藏导航栏及状态栏。"
+
+msgid "Indicates whether the application supports larger screen form-factors."
+msgstr "表示应用程序是否支持较大屏幕尺寸。"
+
+msgid ""
+"Indicates whether an application supports the \"normal\" screen form-factors."
+msgstr "表示应用程序是否支持“正常”屏幕尺寸。"
+
+msgid "Indicates whether the application supports smaller screen form-factors."
+msgstr "表示应用程序是否支持较小屏幕尺寸。"
+
+msgid ""
+"Indicates whether the application supports extra large screen form-factors."
+msgstr "表示应用程序是否支持超大屏幕尺寸。"
+
+msgid ""
+"If [code]true[/code], allows the application to participate in the backup "
+"and restore infrastructure."
+msgstr "如果为 [code]true[/code],则允许应用程序参与基础设施的备份与恢复。"
+
+msgid "Machine-readable application version."
+msgstr "可机读的应用程序版本号。"
+
+msgid "Application version visible to the user."
+msgstr "用户可见的应用程序版本号。"
+
+msgid "Exporter for iOS."
+msgstr "iOS 导出器。"
+
+msgid "Exporting for iOS"
+msgstr "为 iOS 导出"
+
+msgid "Exporter for Linux/BSD."
+msgstr "Linux/BSD 导出器。"
+
+msgid "Exporting for Linux"
+msgstr "为 Linux 导出"
+
+msgid ""
+"Application executable architecture.\n"
+"Supported architectures: [code]x86_32[/code], [code]x86_64[/code], "
+"[code]arm64[/code], [code]arm32[/code], [code]rv64[/code], [code]ppc64[/"
+"code], and [code]ppc32[/code].\n"
+"Official export templates include [code]x86_32[/code] and [code]x86_64[/"
+"code] binaries only."
+msgstr ""
+"程序可执行文件架构。\n"
+"支持的架构有:[code]x86_32[/code]、[code]x86_64[/code]、[code]arm64[/code]、"
+"[code]arm32[/code]、[code]rv64[/code]、[code]ppc64[/code]、[code]ppc32[/"
+"code]。\n"
+"官方导出模板中仅包含 [code]x86_32[/code] 和 [code]x86_64[/code] 的二进制文"
+"件。"
+
+msgid ""
+"If [code]true[/code], a console wrapper is exported alongside the main "
+"executable, which allows running the project with enabled console output."
+msgstr ""
+"如果为 [code]true[/code],则会在导出主可执行文件的同时导出一个控制台封装,能"
+"够在运行项目时启用控制台输出。"
+
+msgid "macOS build number used to build application executable."
+msgstr "构建应用程序可执行文件所使用的 macOS 构建号。"
+
+msgid "macOS SDK build number used to build application executable."
+msgstr "构建应用程序可执行文件所使用的 macOS SDK 构建号。"
+
+msgid "macOS SDK name used to build application executable."
+msgstr "构建应用程序可执行文件所使用的 macOS SDK 名称。"
+
+msgid ""
+"macOS SDK version used to build application executable in the [code]major."
+"minor[/code] format."
+msgstr ""
+"构建应用程序可执行文件所使用的 macOS SDK 版本,格式为 [code]主版本号.次版本号"
+"[/code]。"
+
+msgid "Xcode build number used to build application executable."
+msgstr "构建应用程序可执行文件所使用的 Xcode 构建号。"
+
+msgid "Xcode version used to build application executable."
+msgstr "构建应用程序可执行文件所使用的 Xcode 版本。"
+
+msgid "Base class for the desktop platform exporter (Windows and Linux/BSD)."
+msgstr "桌面平台导出器的基类(Windows 与 Linux/BSD)。"
+
+msgid "Exporter for the Web."
+msgstr "Web 导出器。"
+
+msgid "Exporting for the Web"
+msgstr "为 Web 导出"
+
+msgid ""
+"The canvas resize policy determines how the canvas should be resized by "
+"Godot."
+msgstr "画布大小调整策略决定 Godot 应当如何调整画布的大小。"
+
+msgid "Exporter for Windows."
+msgstr "Windows 导出器。"
+
+msgid "Exporting for Windows"
+msgstr "为 Windows 导出"
+
+msgid ""
+"Company that produced the application. Required. See [url=https://learn."
+"microsoft.com/en-us/windows/win32/menurc/stringfileinfo-"
+"block]StringFileInfo[/url]."
+msgstr ""
+"出品该程序的公司。必填。见 [url=https://learn.microsoft.com/en-us/windows/"
+"win32/menurc/stringfileinfo-block]StringFileInfo[/url]。"
+
+msgid ""
+"Console wrapper icon file. If left empty, it will fallback to [member "
+"application/icon], then to [member ProjectSettings.application/config/"
+"windows_native_icon], and lastly, [member ProjectSettings.application/config/"
+"icon]."
+msgstr ""
+"控制台封装图标文件。如果留空,则依次回退至 [member application/icon]、"
+"[member ProjectSettings.application/config/windows_native_icon]、[member "
+"ProjectSettings.application/config/icon]。"
+
+msgid ""
+"If [code]true[/code], a console wrapper executable is exported alongside the "
+"main executable, which allows running the project with enabled console "
+"output."
+msgstr ""
+"如果为 [code]true[/code],则会在导出主可执行文件的同时导出一个控制台封装可执"
+"行文件,能够在运行项目时启用控制台输出。"
+
msgid "A script that is executed when exporting the project."
msgstr "在导出项目时执行的脚本。"
@@ -45524,12 +46954,6 @@ msgstr "设置渐变色在索引 [param point] 处的颜色。"
msgid "Sets the offset for the gradient color at index [param point]."
msgstr "设置渐变色在索引 [param point] 处的偏移。"
-msgid "Gradient's colors returned as a [PackedColorArray]."
-msgstr "将渐变色中的颜色以 [PackedColorArray] 的形式返回。"
-
-msgid "Gradient's offsets returned as a [PackedFloat32Array]."
-msgstr "将渐变色中的偏移以 [PackedFloat32Array] 的形式返回。"
-
msgid ""
"Constant interpolation, color changes abruptly at each point and stays "
"uniform between. This might cause visible aliasing when used for a gradient "
@@ -57801,6 +59225,13 @@ msgstr ""
"- [code]link_exit_position[/code]:如果 [code]owner[/code] 可用且该所有者是一"
"个 [NavigationLink3D],它将包含代理正在退出时的链接点的全局位置。"
+msgid ""
+"A link between two positions on [NavigationRegion2D]s that agents can be "
+"routed through."
+msgstr ""
+"连接两个位于 [NavigationRegion2D] 上的位置的链接,导航时代理能够通过这个链"
+"接。"
+
msgid "Using NavigationLinks"
msgstr "使用 NavigationLink"
@@ -57871,6 +59302,13 @@ msgstr ""
"控制。"
msgid ""
+"A link between two positions on [NavigationRegion3D]s that agents can be "
+"routed through."
+msgstr ""
+"连接两个位于 [NavigationRegion3D] 上的位置的链接,导航时代理能够通过这个链"
+"接。"
+
+msgid ""
"Whether this link is currently active. If [code]false[/code], [method "
"NavigationServer3D.map_get_path] will ignore this link."
msgstr ""
@@ -58006,6 +59444,20 @@ msgstr ""
"[b]注意:[/b]烘焙时,这个值会向上取整到最接近的 [member cell_size] 的倍数。"
msgid ""
+"The cell height used to rasterize the navigation mesh vertices on the Y "
+"axis. Must match with the cell height on the navigation map."
+msgstr ""
+"单元格高度,用于将导航网格的顶点在 Y 轴上进行栅格化。必须与导航地图的单元格高"
+"度匹配。"
+
+msgid ""
+"The cell size used to rasterize the navigation mesh vertices on the XZ "
+"plane. Must match with the cell size on the navigation map."
+msgstr ""
+"单元格大小,用于将导航网格的顶点在 XZ 平面上进行栅格化。必须与导航地图的单元"
+"格大小匹配。"
+
+msgid ""
"The sampling distance to use when generating the detail mesh, in cell unit."
msgstr "生成细分网格时使用的采样距离,以单元格为单位。"
@@ -58247,13 +59699,92 @@ msgstr ""
"纳一个导航网格区域,则烘焙时将生成位于障碍源几何体网格内部的导航网格区域。"
msgid ""
+"The bake function is deprecated due to core threading changes. To upgrade "
+"existing code, first create a [NavigationMeshSourceGeometryData3D] resource. "
+"Use this resource with [method parse_source_geometry_data] to parse the "
+"SceneTree for nodes that should contribute to the navigation mesh baking. "
+"The SceneTree parsing needs to happen on the main thread. After the parsing "
+"is finished use the resource with [method bake_from_source_geometry_data] to "
+"bake a navigation mesh."
+msgstr ""
+"由于核心多线程方面的更改,烘焙功能已废弃。更新现有代码时,请先创建一个 "
+"[NavigationMeshSourceGeometryData3D] 资源。调用 [method "
+"parse_source_geometry_data] 来解析 SceneTree 中影响导航网格烘焙的节点时请使用"
+"该资源。对 SceneTree 的解析需要在主线程进行。解析完成后,请在调用 [method "
+"bake_from_source_geometry_data] 时使用该资源对导航网格进行烘焙。"
+
+msgid ""
+"Bakes the provided [param navigation_mesh] with the data from the provided "
+"[param source_geometry_data]. After the process is finished the optional "
+"[param callback] will be called."
+msgstr ""
+"使用 [param source_geometry_data] 中提供的数据对 [param navigation_mesh] 进行"
+"烘焙。烘焙过程结束后,会调用可选的 [param callback]。"
+
+msgid ""
"Removes all polygons and vertices from the provided [param navigation_mesh] "
"resource."
msgstr "从提供的 [param navigation_mesh] 资源中移除所有多边形和顶点。"
+msgid ""
+"Parses the [SceneTree] for source geometry according to the properties of "
+"[param navigation_mesh]. Updates the provided [param source_geometry_data] "
+"resource with the resulting data. The resource can then be used to bake a "
+"navigation mesh with [method bake_from_source_geometry_data]. After the "
+"process is finished the optional [param callback] will be called.\n"
+"[b]Note:[/b] This function needs to run on the main thread or with a "
+"deferred call as the SceneTree is not thread-safe."
+msgstr ""
+"根据 [param navigation_mesh] 的属性解析 [SceneTree] 中的源几何体。会使用解析"
+"的结果对提供的 [param source_geometry_data] 资源进行更新。后续可以在使用 "
+"[method bake_from_source_geometry_data] 烘焙导航网格时使用该资源。解析过程完"
+"成后,会调用可选的 [param callback]。\n"
+"[b]注意:[/b]因为 SceneTree 并不是线程安全的,所以这个函数需要在主线程执行或"
+"使用延迟调用。"
+
+msgid ""
+"Container for parsed source geometry data used in navigation mesh baking."
+msgstr "存放解析所得的源几何体数据的容器,用于导航网格的烘焙。"
+
+msgid ""
+"2D Obstacle used in navigation to constrain avoidance controlled agents "
+"outside or inside an area."
+msgstr ""
+"用于导航的 2D 障碍物,能够将启用了避障处理的代理约束在某个区域之外或之内。"
+
msgid "Using NavigationObstacles"
msgstr "使用 NavigationObstacle"
+msgid "Sets the avoidance radius for the obstacle."
+msgstr "设置该障碍物的避障半径。"
+
+msgid ""
+"Sets the wanted velocity for the obstacle so other agent's can better "
+"predict the obstacle if it is moved with a velocity regularly (every frame) "
+"instead of warped to a new position. Does only affect avoidance for the "
+"obstacles [member radius]. Does nothing for the obstacles static vertices."
+msgstr ""
+"设置该障碍物的期望速度,这样如果(每帧)一直使用相同的速度移动而不是直接跳到"
+"某个位置,那么其他代理就能够更好地预测该障碍物的行为。仅影响该障碍物 [member "
+"radius] 的避障。不会影响障碍物的静态顶点。"
+
+msgid ""
+"The outline vertices of the obstacle. If the vertices are winded in "
+"clockwise order agents will be pushed in by the obstacle, else they will be "
+"pushed out. Outlines can not be crossed or overlap. Should the vertices "
+"using obstacle be warped to a new position agent's can not predict this "
+"movement and may get trapped inside the obstacle."
+msgstr ""
+"该障碍物的轮廓顶点。如果这些顶点是按照顺时针顺序缠绕的,那么障碍物就会将其他"
+"代理向内推,否则就会向外推。轮廓不能交叉或重叠。如果这些顶点直接跳到了新的位"
+"置,那么其他代理可能无法预测这种行为,导致被困在障碍物内。"
+
+msgid ""
+"3D Obstacle used in navigation to constrain avoidance controlled agents "
+"outside or inside an area."
+msgstr ""
+"用于导航的 3D 障碍物,能够将启用了避障处理的代理约束在某个区域之外或之内。"
+
msgid "Using NavigationPathQueryObjects"
msgstr "使用 NavigationPathQueryObject"
@@ -67121,6 +68652,27 @@ msgstr "应用于该 [PanoramaSkyMaterial] 的 [Texture2D]。"
msgid "A node used to create a parallax scrolling background."
msgstr "用于创建视差滚动背景的节点。"
+msgid ""
+"A ParallaxBackground uses one or more [ParallaxLayer] child nodes to create "
+"a parallax effect. Each [ParallaxLayer] can move at a different speed using "
+"[member ParallaxLayer.motion_offset]. This creates an illusion of depth in a "
+"2D game. If not used with a [Camera2D], you must manually calculate the "
+"[member scroll_offset].\n"
+"[b]Note:[/b] Each [ParallaxBackground] is drawn on one specific [Viewport] "
+"and cannot be shared between multiple [Viewport]s, see [member CanvasLayer."
+"custom_viewport]. When using multiple [Viewport]s, for example in a split-"
+"screen game, you need create an individual [ParallaxBackground] for each "
+"[Viewport] you want it to be drawn on."
+msgstr ""
+"ParallaxBackground 使用一个或多个 [ParallaxLayer] 子节点来创建视差效果。每个 "
+"[ParallaxLayer] 可以使用 [member ParallaxLayer.motion_offset] 以不同的速度移"
+"动。这在 2D 游戏中可以创造一种深度错觉。如果没有与 [Camera2D] 一起使用,你必"
+"须手动计算 [member scroll_offset]。\n"
+"[b]注意:[/b]每个 [ParallaxBackground] 都是在各自的 [Viewport] 中绘制的,无法"
+"在不同 [Viewport] 之间共享,见 [member CanvasLayer.custom_viewport]。在分屏游"
+"戏等使用多个 [Viewport] 的场景下,你需要每个需要绘制的 [Viewport] 创建单独的 "
+"[ParallaxBackground]。"
+
msgid "The base position offset for all [ParallaxLayer] children."
msgstr "所有 [ParallaxLayer] 子元素的基本位置偏移。"
@@ -67174,6 +68726,23 @@ msgstr ""
"[b]注意:[/b]当该节点进入场景后,对其位置和比例的任何改变都将被忽略。"
msgid ""
+"The ParallaxLayer's [Texture2D] repeating. Useful for creating an infinite "
+"scrolling background. If an axis is set to [code]0[/code], the [Texture2D] "
+"will not be repeated.\n"
+"If the length of the viewport axis is bigger than twice the repeated axis "
+"size, it will not repeat infinitely, as the parallax layer only draws 2 "
+"instances of the texture at any given time.\n"
+"[b]Note:[/b] Despite its name, the texture will not be mirrored, it will "
+"simply be repeated."
+msgstr ""
+"ParallaxLayer 的 [Texture2D] 镜像。用于创建无限滚动的背景。如果轴被设置为 "
+"[code]0[/code],则该 [Texture2D] 将不会被镜像。\n"
+"如果视口轴的长度大于镜像轴的两倍大小,并不会无限重复,因为视差层在任何时候只"
+"会绘制 2 个纹理实例。\n"
+"[b]注意:[/b]虽然属性的名称如此,但实际不会对纹理进行镜像操作,而是简单地重"
+"复。"
+
+msgid ""
"The ParallaxLayer's offset relative to the parent ParallaxBackground's "
"[member ParallaxBackground.scroll_offset]."
msgstr ""
@@ -67407,14 +68976,14 @@ msgid "Each particle's hue will vary along this [CurveTexture]."
msgstr "每个粒子的色调将沿着这个 [CurveTexture] 变化。"
msgid ""
-"Particle lifetime randomness ratio. The lifetime will be multiplied by a "
-"value interpolated between [code]1.0[/code] and a random number less than "
-"one. For example a random ratio of [code]0.4[/code] would scale the original "
-"lifetime between [code]0.4-1.0[/code] of its original value."
+"Particle lifetime randomness ratio. The equation for the lifetime of a "
+"particle is [code]lifetime * (1.0 - randf() * lifetime_randomness)[/code]. "
+"For example, a [member lifetime_randomness] of [code]0.4[/code] scales the "
+"lifetime between [code]0.6[/code] to [code]1.0[/code] of its original value."
msgstr ""
-"粒子寿命随机性比率。生命周期将乘以一个介于 [code]1.0[/code] 和小于 1 的随机数"
-"之间的插值。例如,[code]0.4[/code] 的随机比率将在其原始生命周期的 "
-"[code]0.4-1.0[/code] 之间缩放原始生命周期。"
+"粒子寿命随机比率。粒子寿命的公式为 [code]lifetime * (1.0 - randf() * "
+"lifetime_randomness)[/code]。例如 [member lifetime_randomness] 为 [code]0.4[/"
+"code] 时,寿命会被缩放为原本的 [code]0.6[/code] 到 [code]1.0[/code] 倍。"
msgid ""
"Each particle's linear acceleration will vary along this [CurveTexture]."
@@ -105976,6 +107545,205 @@ msgstr ""
"弃。把这个值设置为[code]0[/code]可以有效地防止任何新的待定连接被接受,例如,"
"当你的所有玩家都连接时。"
+msgid ""
+"UndoRedo works by registering methods and property changes inside "
+"\"actions\". You can create an action, then provide ways to do and undo this "
+"action using function calls and property changes, then commit the action.\n"
+"When an action is committed, all of the [code]do_*[/code] methods will run. "
+"If the [method undo] method is used, the [code]undo_*[/code] methods will "
+"run. If the [method redo] method is used, once again, all of the [code]do_*[/"
+"code] methods will run.\n"
+"Here's an example on how to add an action:\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"var undo_redo = UndoRedo.new()\n"
+"\n"
+"func do_something():\n"
+" pass # Put your code here.\n"
+"\n"
+"func undo_something():\n"
+" pass # Put here the code that reverts what's done by "
+"\"do_something()\".\n"
+"\n"
+"func _on_my_button_pressed():\n"
+" var node = get_node(\"MyNode2D\")\n"
+" undo_redo.create_action(\"Move the node\")\n"
+" undo_redo.add_do_method(do_something)\n"
+" undo_redo.add_undo_method(undo_something)\n"
+" undo_redo.add_do_property(node, \"position\", Vector2(100,100))\n"
+" undo_redo.add_undo_property(node, \"position\", node.position)\n"
+" undo_redo.commit_action()\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"private UndoRedo _undoRedo;\n"
+"\n"
+"public override void _Ready()\n"
+"{\n"
+" _undoRedo = new UndoRedo();\n"
+"}\n"
+"\n"
+"public void DoSomething()\n"
+"{\n"
+" // Put your code here.\n"
+"}\n"
+"\n"
+"public void UndoSomething()\n"
+"{\n"
+" // Put here the code that reverts what's done by \"DoSomething()\".\n"
+"}\n"
+"\n"
+"private void OnMyButtonPressed()\n"
+"{\n"
+" var node = GetNode<Node2D>(\"MyNode2D\");\n"
+" _undoRedo.CreateAction(\"Move the node\");\n"
+" _undoRedo.AddDoMethod(new Callable(this, MethodName.DoSomething));\n"
+" _undoRedo.AddUndoMethod(new Callable(this, MethodName.UndoSomething));\n"
+" _undoRedo.AddDoProperty(node, \"position\", new Vector2(100, 100));\n"
+" _undoRedo.AddUndoProperty(node, \"position\", node.Position);\n"
+" _undoRedo.CommitAction();\n"
+"}\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"Before calling any of the [code]add_(un)do_*[/code] methods, you need to "
+"first call [method create_action]. Afterwards you need to call [method "
+"commit_action].\n"
+"If you don't need to register a method, you can leave [method add_do_method] "
+"and [method add_undo_method] out; the same goes for properties. You can also "
+"register more than one method/property.\n"
+"If you are making an [EditorPlugin] and want to integrate into the editor's "
+"undo history, use [EditorUndoRedoManager] instead.\n"
+"If you are registering multiple properties/method which depend on one "
+"another, be aware that by default undo operation are called in the same "
+"order they have been added. Therefore instead of grouping do operation with "
+"their undo operations it is better to group do on one side and undo on the "
+"other as shown below.\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"undo_redo.create_action(\"Add object\")\n"
+"\n"
+"# DO\n"
+"undo_redo.add_do_method(_create_object)\n"
+"undo_redo.add_do_method(_add_object_to_singleton)\n"
+"\n"
+"# UNDO\n"
+"undo_redo.add_undo_method(_remove_object_from_singleton)\n"
+"undo_redo.add_undo_method(_destroy_that_object)\n"
+"\n"
+"undo_redo.commit_action()\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"_undo_redo.CreateAction(\"Add object\");\n"
+"\n"
+"// DO\n"
+"_undo_redo.AddDoMethod(new Callable(this, MethodName.CreateObject));\n"
+"_undo_redo.AddDoMethod(new Callable(this, MethodName."
+"AddObjectToSingleton));\n"
+"\n"
+"// UNDO\n"
+"_undo_redo.AddUndoMethod(new Callable(this, MethodName."
+"RemoveObjectFromSingleton));\n"
+"_undo_redo.AddUndoMethod(new Callable(this, MethodName.DestroyThatObject));\n"
+"\n"
+"_undo_redo.CommitAction();\n"
+"[/csharp]\n"
+"[/codeblocks]"
+msgstr ""
+"UndoRedo 的原理是在“动作”中注册方法和属性的变化。你可以创建一个动作,然后提供"
+"执行(do)和撤销(undo)这个动作需要进行的函数调用和属性更改,然后提交该动"
+"作。\n"
+"动作提交后就会执行所有 [code]do_*[/code] 方法。如果使用 [method undo] 方法,"
+"那么就会执行 [code]undo_*[/code] 方法。如果使用 [method redo] 方法,那么就会"
+"再次执行所有 [code]do_*[/code] 方法。\n"
+"以下是添加动作的示例:\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"var undo_redo = UndoRedo.new()\n"
+"\n"
+"func do_something():\n"
+" pass # 在此处编写你的代码。\n"
+"\n"
+"func undo_something():\n"
+" pass # 在此处编写恢复“do_something()”里所做事情的代码。\n"
+"\n"
+"func _on_my_button_pressed():\n"
+" var node = get_node(\"MyNode2D\")\n"
+" undo_redo.create_action(\"移动节点\")\n"
+" undo_redo.add_do_method(do_something)\n"
+" undo_redo.add_undo_method(undo_something)\n"
+" undo_redo.add_do_property(node, \"position\", Vector2(100,100))\n"
+" undo_redo.add_undo_property(node, \"position\", node.position)\n"
+" undo_redo.commit_action()\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"private UndoRedo _undoRedo;\n"
+"\n"
+"public override void _Ready()\n"
+"{\n"
+" _undoRedo = new UndoRedo();\n"
+"}\n"
+"\n"
+"public void DoSomething()\n"
+"{\n"
+" // 在此处编写你的代码。\n"
+"}\n"
+"\n"
+"public void UndoSomething()\n"
+"{\n"
+" // 在此处编写恢复“DoSomething()”里所做事情的代码。\n"
+"}\n"
+"\n"
+"private void OnMyButtonPressed()\n"
+"{\n"
+" var node = GetNode<Node2D>(\"MyNode2D\");\n"
+" _undoRedo.CreateAction(\"移动节点\");\n"
+" _undoRedo.AddDoMethod(new Callable(this, MethodName.DoSomething));\n"
+" _undoRedo.AddUndoMethod(new Callable(this, MethodName.UndoSomething));\n"
+" _undoRedo.AddDoProperty(node, \"position\", new Vector2(100, 100));\n"
+" _undoRedo.AddUndoProperty(node, \"position\", node.Position);\n"
+" _undoRedo.CommitAction();\n"
+"}\n"
+"[/csharp]\n"
+"[/codeblocks]\n"
+"调用 [code]add_(un)do_*[/code] 方法之前,你需要先调用 [method "
+"create_action]。调用之后则需要调用 [method commit_action]。\n"
+"如果你不需要注册方法,则可以将 [method add_do_method] 和 [method "
+"add_undo_method] 省去;属性同理。你也可以注册多个方法/属性。\n"
+"如果你要制作 [EditorPlugin],希望集成编辑器的撤销历史,请改用 "
+"[EditorUndoRedoManager]。\n"
+"如果你所注册的不同属性/方法之间有相互依赖,请注意默认情况下撤销操作的调用顺序"
+"和添加顺序是一致的。因此请不要将 do 操作和 undo 操作写在一起,最好还是和下面"
+"一样 do 和 do 一起写,undo 和 undo 一起写。\n"
+"[codeblocks]\n"
+"[gdscript]\n"
+"undo_redo.create_action(\"添加对象\")\n"
+"\n"
+"# DO\n"
+"undo_redo.add_do_method(_create_object)\n"
+"undo_redo.add_do_method(_add_object_to_singleton)\n"
+"\n"
+"# UNDO\n"
+"undo_redo.add_undo_method(_remove_object_from_singleton)\n"
+"undo_redo.add_undo_method(_destroy_that_object)\n"
+"\n"
+"undo_redo.commit_action()\n"
+"[/gdscript]\n"
+"[csharp]\n"
+"_undo_redo.CreateAction(\"添加对象\");\n"
+"\n"
+"// DO\n"
+"_undo_redo.AddDoMethod(new Callable(this, MethodName.CreateObject));\n"
+"_undo_redo.AddDoMethod(new Callable(this, MethodName."
+"AddObjectToSingleton));\n"
+"\n"
+"// UNDO\n"
+"_undo_redo.AddUndoMethod(new Callable(this, MethodName."
+"RemoveObjectFromSingleton));\n"
+"_undo_redo.AddUndoMethod(new Callable(this, MethodName.DestroyThatObject));\n"
+"\n"
+"_undo_redo.CommitAction();\n"
+"[/csharp]\n"
+"[/codeblocks]"
+
msgid "Register a [Callable] that will be called when the action is committed."
msgstr "注册 [Callable],会在提交动作时调用。"
@@ -114089,6 +115857,17 @@ msgid "Moves the [Window] on top of other windows and focuses it."
msgstr "将该 [Window] 移动到其他窗口的顶部并聚焦。"
msgid ""
+"Popups the [Window] centered inside its parent [Window]. [param "
+"fallback_ratio] determines the maximum size of the [Window], in relation to "
+"its parent.\n"
+"[b]Note:[/b] Calling it with the default value of [param minsize] is "
+"equivalent to calling it with [member size]."
+msgstr ""
+"在父 [Window] 中居中弹出该 [Window]。[param fallback_ratio] 确定 [Window] 相"
+"对于其父级的最大尺寸。\n"
+"[b]注意:[/b]用 [param minsize] 的默认值调用它等同于用 [member size] 调用它。"
+
+msgid ""
"Tells the OS that the [Window] needs an attention. This makes the window "
"stand out in some way depending on the system, e.g. it might blink on the "
"task bar."
@@ -114321,6 +116100,18 @@ msgstr ""
"[b]注意:[/b]该属性在 Linux (X11)、macOS 和 Windows 上实现。"
msgid ""
+"If [code]true[/code], the [Window] will be considered a popup. Popups are "
+"sub-windows that don't show as separate windows in system's window manager's "
+"window list and will send close request when anything is clicked outside of "
+"them (unless [member exclusive] is enabled).\n"
+"[b]Note:[/b] This property only works with native windows."
+msgstr ""
+"如果为 [code]true[/code],则该 [Window] 将被视为弹出窗口。弹出窗口是子窗口,"
+"不会在系统窗口管理器的窗口列表中显示为单独的窗口,并且会在单击它们之外的任何"
+"位置时发送关闭请求(除非启用了 [member exclusive])。\n"
+"[b]注意:[/b]此属性仅适用于本地窗口。"
+
+msgid ""
"The window's position in pixels.\n"
"If [member ProjectSettings.display/window/subwindows/embed_subwindows] is "
"[code]false[/code], the position is in absolute screen coordinates. This "
@@ -114977,6 +116768,28 @@ msgstr ""
"似,能够强制所有物理体都保持在它的上方。哪个方向是“上方”由该直线的法线确定,"
"这个方向在编辑器中由直线上方的一条段线表示。用例是无限的平坦地面。"
+msgid ""
+"The distance from the origin to the line, expressed in terms of [member "
+"normal] (according to its direction and magnitude). Actual absolute distance "
+"from the origin to the line can be calculated as [code]abs(distance) / "
+"normal.length()[/code].\n"
+"In the scalar equation of the line [code]ax + by = d[/code], this is "
+"[code]d[/code], while the [code](a, b)[/code] coordinates are represented by "
+"the [member normal] property."
+msgstr ""
+"从原点到直线的距离,沿 [member normal] 方向(根据其方向和大小)。原点到直线实"
+"际距离的绝对值可以用 [code]abs(distance) / normal.length()[/code] 计算。\n"
+"在直线 [code]ax + by = d[/code] 的标量方程中,这是 [code]d[/code],而 [code]"
+"(a, b)[/code] 坐标由 [member normal] 属性表示。"
+
+msgid ""
+"The line's normal, typically a unit vector. Its direction indicates the non-"
+"colliding half-plane. Can be of any length but zero. Defaults to "
+"[code]Vector2.UP[/code]."
+msgstr ""
+"该直线的法线,通常是单位向量。方向表示不带碰撞的那半个平面。长度可以是零以外"
+"的任何值。默认为 [code]Vector2.UP[/code]。"
+
msgid "A 3D world boundary (half-space) shape used for physics collision."
msgstr "用于物理碰撞的 3D 空间边界(半空间)形状。"
diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp
index b8c56018dc..658c0e6145 100644
--- a/drivers/gles3/effects/copy_effects.cpp
+++ b/drivers/gles3/effects/copy_effects.cpp
@@ -31,6 +31,7 @@
#ifdef GLES3_ENABLED
#include "copy_effects.h"
+#include "../storage/texture_storage.h"
using namespace GLES3;
@@ -133,6 +134,7 @@ void CopyEffects::copy_screen() {
draw_screen_triangle();
}
+// Intended for efficiently mipmapping textures.
void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
GLuint framebuffers[2];
glGenFramebuffers(2, framebuffers);
@@ -158,6 +160,80 @@ void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, con
glDeleteFramebuffers(2, framebuffers);
}
+// Intended for approximating a gaussian blur. Used for 2D backbuffer mipmaps. Slightly less efficient than bilinear_blur().
+void CopyEffects::gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size) {
+ GLuint framebuffer;
+ glGenFramebuffers(1, &framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, p_source_texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ Size2i base_size = p_size;
+
+ Rect2i source_region = p_region;
+ Rect2i dest_region = p_region;
+
+ Size2 float_size = Size2(p_size);
+ Rect2 normalized_source_region = Rect2(p_region);
+ normalized_source_region.position = normalized_source_region.position / float_size;
+ normalized_source_region.size = normalized_source_region.size / float_size;
+ Rect2 normalized_dest_region = Rect2(p_region);
+ for (int i = 1; i < p_mipmap_count; i++) {
+ dest_region.position.x >>= 1;
+ dest_region.position.y >>= 1;
+ dest_region.size.x = MAX(1, dest_region.size.x >> 1);
+ dest_region.size.y = MAX(1, dest_region.size.y >> 1);
+ base_size.x >>= 1;
+ base_size.y >>= 1;
+
+ glBindTexture(GL_TEXTURE_2D, p_source_texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, i - 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i - 1);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, i);
+#ifdef DEV_ENABLED
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ WARN_PRINT("Could not bind Gaussian blur framebuffer, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+ }
+#endif
+
+ glViewport(0, 0, base_size.x, base_size.y);
+
+ bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);
+ if (!success) {
+ return;
+ }
+
+ float_size = Size2(base_size);
+ normalized_dest_region.position = Size2(dest_region.position) / float_size;
+ normalized_dest_region.size = Size2(dest_region.size) / float_size;
+
+ copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, normalized_dest_region.position.x, normalized_dest_region.position.y, normalized_dest_region.size.x, normalized_dest_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);
+ copy.shader.version_set_uniform(CopyShaderGLES3::SOURCE_SECTION, normalized_source_region.position.x, normalized_source_region.position.y, normalized_source_region.size.x, normalized_source_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);
+ copy.shader.version_set_uniform(CopyShaderGLES3::PIXEL_SIZE, 1.0 / float_size.x, 1.0 / float_size.y, copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);
+
+ draw_screen_quad();
+
+ source_region = dest_region;
+ normalized_source_region = normalized_dest_region;
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDeleteFramebuffers(1, &framebuffer);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, p_mipmap_count - 1);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ glViewport(0, 0, p_size.x, p_size.y);
+}
+
void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) {
bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
if (!success) {
diff --git a/drivers/gles3/effects/copy_effects.h b/drivers/gles3/effects/copy_effects.h
index 105fbcfe98..b2bceb84af 100644
--- a/drivers/gles3/effects/copy_effects.h
+++ b/drivers/gles3/effects/copy_effects.h
@@ -64,6 +64,7 @@ public:
void copy_to_rect(const Rect2 &p_rect);
void copy_screen();
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
+ void gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size);
void set_color(const Color &p_color, const Rect2i &p_region);
void draw_screen_triangle();
void draw_screen_quad();
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index e6e7dd6f17..d8ddfe5c32 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -608,18 +608,20 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
material = nullptr;
}
}
+ }
- if (!material) {
- sky_material = sky_globals.default_material;
- material = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
- }
+ if (!material) {
+ sky_material = sky_globals.default_material;
+ material = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
- ERR_FAIL_COND(!material);
+ ERR_FAIL_COND(!material);
- shader_data = material->shader_data;
+ shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_COND(!shader_data);
+ if (sky) {
if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
sky->prev_time = time;
sky->reflection_dirty = true;
@@ -640,111 +642,113 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
sky->prev_position = p_transform.origin;
sky->reflection_dirty = true;
}
+ }
- glBindBufferBase(GL_UNIFORM_BUFFER, SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, sky_globals.directional_light_buffer);
- if (shader_data->uses_light) {
- sky_globals.directional_light_count = 0;
- for (int i = 0; i < (int)p_lights.size(); i++) {
- GLES3::LightInstance *li = GLES3::LightStorage::get_singleton()->get_light_instance(p_lights[i]);
- if (!li) {
- continue;
- }
- RID base = li->light;
+ glBindBufferBase(GL_UNIFORM_BUFFER, SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, sky_globals.directional_light_buffer);
+ if (shader_data->uses_light) {
+ sky_globals.directional_light_count = 0;
+ for (int i = 0; i < (int)p_lights.size(); i++) {
+ GLES3::LightInstance *li = GLES3::LightStorage::get_singleton()->get_light_instance(p_lights[i]);
+ if (!li) {
+ continue;
+ }
+ RID base = li->light;
- ERR_CONTINUE(base.is_null());
+ ERR_CONTINUE(base.is_null());
- RS::LightType type = light_storage->light_get_type(base);
- if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) {
- DirectionalLightData &sky_light_data = sky_globals.directional_lights[sky_globals.directional_light_count];
- Transform3D light_transform = li->transform;
- Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
+ RS::LightType type = light_storage->light_get_type(base);
+ if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) {
+ DirectionalLightData &sky_light_data = sky_globals.directional_lights[sky_globals.directional_light_count];
+ Transform3D light_transform = li->transform;
+ Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
- sky_light_data.direction[0] = world_direction.x;
- sky_light_data.direction[1] = world_direction.y;
- sky_light_data.direction[2] = world_direction.z;
+ sky_light_data.direction[0] = world_direction.x;
+ sky_light_data.direction[1] = world_direction.y;
+ sky_light_data.direction[2] = world_direction.z;
- float sign = light_storage->light_is_negative(base) ? -1 : 1;
- sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
+ float sign = light_storage->light_is_negative(base) ? -1 : 1;
+ sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
- if (is_using_physical_light_units()) {
- sky_light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
- }
+ if (is_using_physical_light_units()) {
+ sky_light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
+ }
- if (p_render_data->camera_attributes.is_valid()) {
- sky_light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
- }
+ if (p_render_data->camera_attributes.is_valid()) {
+ sky_light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
- Color linear_col = light_storage->light_get_color(base);
- sky_light_data.color[0] = linear_col.r;
- sky_light_data.color[1] = linear_col.g;
- sky_light_data.color[2] = linear_col.b;
+ Color linear_col = light_storage->light_get_color(base);
+ sky_light_data.color[0] = linear_col.r;
+ sky_light_data.color[1] = linear_col.g;
+ sky_light_data.color[2] = linear_col.b;
- sky_light_data.enabled = true;
+ sky_light_data.enabled = true;
- float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
- if (angular_diameter > 0.0) {
- angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter));
- } else {
- angular_diameter = 0.0;
- }
- sky_light_data.size = angular_diameter;
- sky_globals.directional_light_count++;
- if (sky_globals.directional_light_count >= sky_globals.max_directional_lights) {
- break;
- }
+ float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ if (angular_diameter > 0.0) {
+ angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter));
+ } else {
+ angular_diameter = 0.0;
}
- }
- // Check whether the directional_light_buffer changes
- bool light_data_dirty = false;
-
- // Light buffer is dirty if we have fewer or more lights
- // If we have fewer lights, make sure that old lights are disabled
- if (sky_globals.directional_light_count != sky_globals.last_frame_directional_light_count) {
- light_data_dirty = true;
- for (uint32_t i = sky_globals.directional_light_count; i < sky_globals.max_directional_lights; i++) {
- sky_globals.directional_lights[i].enabled = false;
- sky_globals.last_frame_directional_lights[i].enabled = false;
+ sky_light_data.size = angular_diameter;
+ sky_globals.directional_light_count++;
+ if (sky_globals.directional_light_count >= sky_globals.max_directional_lights) {
+ break;
}
}
+ }
+ // Check whether the directional_light_buffer changes
+ bool light_data_dirty = false;
+
+ // Light buffer is dirty if we have fewer or more lights
+ // If we have fewer lights, make sure that old lights are disabled
+ if (sky_globals.directional_light_count != sky_globals.last_frame_directional_light_count) {
+ light_data_dirty = true;
+ for (uint32_t i = sky_globals.directional_light_count; i < sky_globals.max_directional_lights; i++) {
+ sky_globals.directional_lights[i].enabled = false;
+ sky_globals.last_frame_directional_lights[i].enabled = false;
+ }
+ }
- if (!light_data_dirty) {
- for (uint32_t i = 0; i < sky_globals.directional_light_count; i++) {
- if (sky_globals.directional_lights[i].direction[0] != sky_globals.last_frame_directional_lights[i].direction[0] ||
- sky_globals.directional_lights[i].direction[1] != sky_globals.last_frame_directional_lights[i].direction[1] ||
- sky_globals.directional_lights[i].direction[2] != sky_globals.last_frame_directional_lights[i].direction[2] ||
- sky_globals.directional_lights[i].energy != sky_globals.last_frame_directional_lights[i].energy ||
- sky_globals.directional_lights[i].color[0] != sky_globals.last_frame_directional_lights[i].color[0] ||
- sky_globals.directional_lights[i].color[1] != sky_globals.last_frame_directional_lights[i].color[1] ||
- sky_globals.directional_lights[i].color[2] != sky_globals.last_frame_directional_lights[i].color[2] ||
- sky_globals.directional_lights[i].enabled != sky_globals.last_frame_directional_lights[i].enabled ||
- sky_globals.directional_lights[i].size != sky_globals.last_frame_directional_lights[i].size) {
- light_data_dirty = true;
- break;
- }
+ if (!light_data_dirty) {
+ for (uint32_t i = 0; i < sky_globals.directional_light_count; i++) {
+ if (sky_globals.directional_lights[i].direction[0] != sky_globals.last_frame_directional_lights[i].direction[0] ||
+ sky_globals.directional_lights[i].direction[1] != sky_globals.last_frame_directional_lights[i].direction[1] ||
+ sky_globals.directional_lights[i].direction[2] != sky_globals.last_frame_directional_lights[i].direction[2] ||
+ sky_globals.directional_lights[i].energy != sky_globals.last_frame_directional_lights[i].energy ||
+ sky_globals.directional_lights[i].color[0] != sky_globals.last_frame_directional_lights[i].color[0] ||
+ sky_globals.directional_lights[i].color[1] != sky_globals.last_frame_directional_lights[i].color[1] ||
+ sky_globals.directional_lights[i].color[2] != sky_globals.last_frame_directional_lights[i].color[2] ||
+ sky_globals.directional_lights[i].enabled != sky_globals.last_frame_directional_lights[i].enabled ||
+ sky_globals.directional_lights[i].size != sky_globals.last_frame_directional_lights[i].size) {
+ light_data_dirty = true;
+ break;
}
}
+ }
- if (light_data_dirty) {
- glBufferData(GL_UNIFORM_BUFFER, sizeof(DirectionalLightData) * sky_globals.max_directional_lights, sky_globals.directional_lights, GL_STREAM_DRAW);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ if (light_data_dirty) {
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(DirectionalLightData) * sky_globals.max_directional_lights, sky_globals.directional_lights, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
- DirectionalLightData *temp = sky_globals.last_frame_directional_lights;
- sky_globals.last_frame_directional_lights = sky_globals.directional_lights;
- sky_globals.directional_lights = temp;
- sky_globals.last_frame_directional_light_count = sky_globals.directional_light_count;
+ DirectionalLightData *temp = sky_globals.last_frame_directional_lights;
+ sky_globals.last_frame_directional_lights = sky_globals.directional_lights;
+ sky_globals.directional_lights = temp;
+ sky_globals.last_frame_directional_light_count = sky_globals.directional_light_count;
+ if (sky) {
sky->reflection_dirty = true;
}
}
+ }
- if (p_render_data->view_count > 1) {
- glBindBufferBase(GL_UNIFORM_BUFFER, SKY_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
- }
+ if (p_render_data->view_count > 1) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, SKY_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
- if (!sky->radiance) {
- _invalidate_sky(sky);
- _update_dirty_skys();
- }
+ if (sky && !sky->radiance) {
+ _invalidate_sky(sky);
+ _update_dirty_skys();
}
}
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 29e9ada72b..fdc787b4a1 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -667,7 +667,7 @@ void ShaderGLES3::_clear_version(Version *p_version) {
void ShaderGLES3::_initialize_version(Version *p_version) {
ERR_FAIL_COND(p_version->variants.size() > 0);
- if (_load_from_cache(p_version)) {
+ if (shader_cache_dir_valid && _load_from_cache(p_version)) {
return;
}
p_version->variants.reserve(variant_count);
@@ -678,7 +678,9 @@ void ShaderGLES3::_initialize_version(Version *p_version) {
_compile_specialization(spec, i, p_version, specialization_default_mask);
p_version->variants[i].insert(specialization_default_mask, spec);
}
- _save_to_cache(p_version);
+ if (shader_cache_dir_valid) {
+ _save_to_cache(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) {
diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl
index 796ba79c2e..3a85569555 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/copy.glsl
@@ -16,17 +16,24 @@ layout(location = 0) in vec2 vertex_attrib;
out vec2 uv_interp;
/* clang-format on */
-#ifdef USE_COPY_SECTION
+#if defined(USE_COPY_SECTION) || defined(MODE_GAUSSIAN_BLUR)
+// Defined in 0-1 coords.
uniform highp vec4 copy_section;
#endif
+#ifdef MODE_GAUSSIAN_BLUR
+uniform highp vec4 source_section;
+#endif
void main() {
uv_interp = vertex_attrib * 0.5 + 0.5;
gl_Position = vec4(vertex_attrib, 1.0, 1.0);
-#ifdef USE_COPY_SECTION
+#if defined(USE_COPY_SECTION) || defined(MODE_GAUSSIAN_BLUR)
gl_Position.xy = (copy_section.xy + uv_interp.xy * copy_section.zw) * 2.0 - 1.0;
#endif
+#ifdef MODE_GAUSSIAN_BLUR
+ uv_interp = source_section.xy + uv_interp * source_section.zw;
+#endif
}
/* clang-format off */
@@ -39,6 +46,7 @@ uniform vec4 color_in;
#endif
#ifdef MODE_GAUSSIAN_BLUR
+// Defined in 0-1 coords.
uniform highp vec2 pixel_size;
#endif
@@ -55,4 +63,31 @@ void main() {
#ifdef MODE_SIMPLE_COLOR
frag_color = color_in;
#endif
+
+// Efficient box filter from Jimenez: http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+// Approximates a Gaussian in a single pass.
+#ifdef MODE_GAUSSIAN_BLUR
+ vec4 A = textureLod(source, uv_interp + pixel_size * vec2(-1.0, -1.0), 0.0);
+ vec4 B = textureLod(source, uv_interp + pixel_size * vec2(0.0, -1.0), 0.0);
+ vec4 C = textureLod(source, uv_interp + pixel_size * vec2(1.0, -1.0), 0.0);
+ vec4 D = textureLod(source, uv_interp + pixel_size * vec2(-0.5, -0.5), 0.0);
+ vec4 E = textureLod(source, uv_interp + pixel_size * vec2(0.5, -0.5), 0.0);
+ vec4 F = textureLod(source, uv_interp + pixel_size * vec2(-1.0, 0.0), 0.0);
+ vec4 G = textureLod(source, uv_interp, 0.0);
+ vec4 H = textureLod(source, uv_interp + pixel_size * vec2(1.0, 0.0), 0.0);
+ vec4 I = textureLod(source, uv_interp + pixel_size * vec2(-0.5, 0.5), 0.0);
+ vec4 J = textureLod(source, uv_interp + pixel_size * vec2(0.5, 0.5), 0.0);
+ vec4 K = textureLod(source, uv_interp + pixel_size * vec2(-1.0, 1.0), 0.0);
+ vec4 L = textureLod(source, uv_interp + pixel_size * vec2(0.0, 1.0), 0.0);
+ vec4 M = textureLod(source, uv_interp + pixel_size * vec2(1.0, 1.0), 0.0);
+
+ float weight = 0.5 / 4.0;
+ float lesser_weight = 0.125 / 4.0;
+
+ frag_color = (D + E + I + J) * weight;
+ frag_color += (A + B + G + F) * lesser_weight;
+ frag_color += (B + C + H + G) * lesser_weight;
+ frag_color += (F + G + L + K) * lesser_weight;
+ frag_color += (G + H + M + L) * lesser_weight;
+#endif
}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index aa68febec8..7cba77be2f 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1039,17 +1039,16 @@ void main() {
if (alpha < alpha_scissor_threshold) {
discard;
}
-#endif // ALPHA_SCISSOR_USED
-
+#else
+#ifdef MODE_RENDER_DEPTH
#ifdef USE_OPAQUE_PREPASS
-#if !defined(ALPHA_SCISSOR_USED)
if (alpha < opaque_prepass_threshold) {
discard;
}
-
-#endif // not ALPHA_SCISSOR_USED
#endif // USE_OPAQUE_PREPASS
+#endif // MODE_RENDER_DEPTH
+#endif // !ALPHA_SCISSOR_USED
#endif // !USE_SHADOW_TO_OPACITY
@@ -1270,17 +1269,16 @@ void main() {
if (alpha < alpha_scissor) {
discard;
}
-#endif // ALPHA_SCISSOR_USED
-
+#else
+#ifdef MODE_RENDER_DEPTH
#ifdef USE_OPAQUE_PREPASS
-#if !defined(ALPHA_SCISSOR_USED)
if (alpha < opaque_prepass_threshold) {
discard;
}
-
-#endif // not ALPHA_SCISSOR_USED
#endif // USE_OPAQUE_PREPASS
+#endif // MODE_RENDER_DEPTH
+#endif // !ALPHA_SCISSOR_USED
#endif // USE_SHADOW_TO_OPACITY
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
index 191d873269..9f9c22cf6d 100644
--- a/drivers/gles3/shaders/sky.glsl
+++ b/drivers/gles3/shaders/sky.glsl
@@ -167,24 +167,24 @@ void main() {
#ifdef USE_CUBEMAP_PASS
#ifdef USES_HALF_RES_COLOR
- half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal);
+ half_res_color = texture(samplerCube(half_res, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_normal);
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal);
+ quarter_res_color = texture(samplerCube(quarter_res, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_normal);
#endif
#else
#ifdef USES_HALF_RES_COLOR
#ifdef USE_MULTIVIEW
- half_res_color = textureLod(sampler2DArray(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0);
+ half_res_color = textureLod(sampler2DArray(half_res, SAMPLER_LINEAR_CLAMP), vec3(uv, ViewIndex), 0.0);
#else
- half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+ half_res_color = textureLod(sampler2D(half_res, SAMPLER_LINEAR_CLAMP), uv, 0.0);
#endif
#endif
#ifdef USES_QUARTER_RES_COLOR
#ifdef USE_MULTIVIEW
- quarter_res_color = textureLod(sampler2DArray(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0);
+ quarter_res_color = textureLod(sampler2DArray(quarter_res, SAMPLER_LINEAR_CLAMP), vec3(uv, ViewIndex), 0.0);
#else
- quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+ quarter_res_color = textureLod(sampler2D(quarter_res, SAMPLER_LINEAR_CLAMP), uv, 0.0);
#endif
#endif
#endif
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index d0746a8fc8..aa6319f0ef 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1338,7 +1338,7 @@ MaterialStorage::MaterialStorage() {
actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
- actions.render_mode_defines["depth_draw_opaque"] = "#define USE_OPAQUE_PREPASS\n";
+ actions.render_mode_defines["depth_prepass_alpha"] = "#define USE_OPAQUE_PREPASS\n";
bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index ad4bdae272..381cf1a7c6 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -1075,6 +1075,7 @@ void MeshStorage::update_mesh_instances() {
}
glEnable(GL_RASTERIZER_DISCARD);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Process skeletons and blend shapes using transform feedback
while (dirty_mesh_instance_arrays.first()) {
MeshInstance *mi = dirty_mesh_instance_arrays.first()->self();
@@ -1284,13 +1285,17 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
multimesh->data_cache_used_dirty_regions = 0;
}
+ // If we have either color or custom data, reserve space for both to make data handling logic simpler.
+ // This way we can always treat them both as a single, compressed uvec4.
+ int color_and_custom_strides = (p_use_colors || p_use_custom_data) ? 2 : 0;
+
multimesh->instances = p_instances;
multimesh->xform_format = p_transform_format;
multimesh->uses_colors = p_use_colors;
multimesh->color_offset_cache = p_transform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12;
multimesh->uses_custom_data = p_use_custom_data;
- multimesh->custom_data_offset_cache = multimesh->color_offset_cache + (p_use_colors ? 2 : 0);
- multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 2 : 0);
+ multimesh->custom_data_offset_cache = multimesh->color_offset_cache + color_and_custom_strides;
+ multimesh->stride_cache = multimesh->custom_data_offset_cache + color_and_custom_strides;
multimesh->buffer_set = false;
multimesh->data_cache = Vector<float>();
diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp
index c50d2c48cc..b7ebe055f5 100644
--- a/drivers/gles3/storage/particles_storage.cpp
+++ b/drivers/gles3/storage/particles_storage.cpp
@@ -820,12 +820,11 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
particles->num_attrib_arrays_cache = 5 + userdata_count + (xform_size - 2);
particles->process_buffer_stride_cache = sizeof(float) * 4 * particles->num_attrib_arrays_cache;
- int process_data_amount = 4 * particles->num_attrib_arrays_cache * total_amount;
- float *data = memnew_arr(float, process_data_amount);
+ PackedByteArray data;
+ data.resize_zeroed(particles->process_buffer_stride_cache * total_amount);
- for (int i = 0; i < process_data_amount; i++) {
- data[i] = 0;
- }
+ PackedByteArray instance_data;
+ instance_data.resize_zeroed(particles->instance_buffer_size_cache);
{
glGenVertexArrays(1, &particles->front_vertex_array);
@@ -834,7 +833,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
glGenBuffers(1, &particles->front_instance_buffer);
glBindBuffer(GL_ARRAY_BUFFER, particles->front_process_buffer);
- GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_process_buffer, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY, "Particles front process buffer");
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_process_buffer, particles->process_buffer_stride_cache * total_amount, data.ptr(), GL_DYNAMIC_COPY, "Particles front process buffer");
for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
glEnableVertexAttribArray(j);
@@ -843,7 +842,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, particles->front_instance_buffer);
- GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_instance_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY, "Particles front instance buffer");
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_instance_buffer, particles->instance_buffer_size_cache, instance_data.ptr(), GL_DYNAMIC_COPY, "Particles front instance buffer");
}
{
@@ -853,7 +852,7 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
glGenBuffers(1, &particles->back_instance_buffer);
glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);
- GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_process_buffer, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY, "Particles back process buffer");
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_process_buffer, particles->process_buffer_stride_cache * total_amount, data.ptr(), GL_DYNAMIC_COPY, "Particles back process buffer");
for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
glEnableVertexAttribArray(j);
@@ -862,11 +861,9 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, particles->back_instance_buffer);
- GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_instance_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY, "Particles back instance buffer");
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_instance_buffer, particles->instance_buffer_size_cache, instance_data.ptr(), GL_DYNAMIC_COPY, "Particles back instance buffer");
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- memdelete_arr(data);
}
}
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index 19bf57df94..76c0097bab 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -37,25 +37,25 @@ RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data();
}
-void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p_config) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
- //internal_size.x = p_internal_size.x; // ignore for now
- //internal_size.y = p_internal_size.y;
- width = p_target_size.x;
- height = p_target_size.y;
- //scaling_3d_mode = p_scaling_3d_mode
- //fsr_sharpness = p_fsr_sharpness;
- //texture_mipmap_bias = p_texture_mipmap_bias;
- render_target = p_render_target;
- //msaa = p_msaa;
- //screen_space_aa = p_screen_space_aa;
- //use_debanding = p_use_debanding;
- view_count = p_view_count;
+ //internal_size.x = p_config->get_internal_size().x; // ignore for now
+ //internal_size.y = p_config->get_internal_size().y;
+ width = p_config->get_target_size().x;
+ height = p_config->get_target_size().y;
+ //scaling_3d_mode = p_config->get_scaling_3d_mode()
+ //fsr_sharpness = p_config->get_fsr_sharpness();
+ //texture_mipmap_bias = p_config->get_texture_mipmap_bias();
+ render_target = p_config->get_render_target();
+ //msaa = p_config->get_msaa_3d();
+ //screen_space_aa = p_config->get_screen_space_aa();
+ //use_debanding = p_config->get_use_debanding();
+ view_count = p_config->get_view_count();
free_render_buffer_data();
- GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
+ GLES3::RenderTarget *rt = texture_storage->get_render_target(render_target);
is_transparent = rt->is_transparent;
}
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index d07a0812f6..64b95c417c 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -81,7 +81,7 @@ public:
private:
public:
virtual ~RenderSceneBuffersGLES3();
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void configure(const RenderSceneBuffersConfiguration *p_config) override;
virtual void set_fsr_sharpness(float p_fsr_sharpness) override{};
virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override{};
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 305be68706..a3f230f9e2 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1192,6 +1192,9 @@ Size2 TextureStorage::texture_size_with_proxy(RID p_texture) {
}
}
+void TextureStorage::texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type) {
+}
+
RID TextureStorage::texture_get_rd_texture(RID p_texture, bool p_srgb) const {
return RID();
}
@@ -1837,10 +1840,10 @@ void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
}
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, texture_size_bytes, "Render target backbuffer color texture");
- // Initialize all levels to opaque Magenta.
+ // Initialize all levels to clear black.
for (int j = 0; j < count; j++) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, j);
- glClearColor(1.0, 0.0, 1.0, 1.0);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
}
@@ -2568,18 +2571,18 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons
}
glDisable(GL_BLEND);
- //single texture copy for backbuffer
+ // Single texture copy for backbuffer.
glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rt->color);
GLES3::CopyEffects::get_singleton()->copy_screen();
if (p_gen_mipmaps) {
- GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region);
+ GLES3::CopyEffects::get_singleton()->gaussian_blur(rt->backbuffer, rt->mipmap_count, region, rt->size);
glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
}
- glEnable(GL_BLEND); // 2D almost always uses blend.
+ glEnable(GL_BLEND); // 2D starts with blend enabled.
}
void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) {
@@ -2624,8 +2627,10 @@ void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target,
return; //nothing to do
}
}
+ glDisable(GL_BLEND);
+ GLES3::CopyEffects::get_singleton()->gaussian_blur(rt->backbuffer, rt->mipmap_count, region, rt->size);
+ glEnable(GL_BLEND); // 2D starts with blend enabled.
- GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region);
glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
}
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index fefcd56570..bad2b31a31 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -252,10 +252,10 @@ struct Texture {
}
Config *config = Config::get_singleton();
state_filter = p_filter;
- GLenum pmin = GL_NEAREST; // param min
- GLenum pmag = GL_NEAREST; // param mag
- GLint max_lod = 1000;
- bool use_anisotropy = false;
+ GLenum pmin = GL_NEAREST;
+ GLenum pmag = GL_NEAREST;
+ GLint max_lod = 0;
+ GLfloat anisotropy = 1.0f;
switch (state_filter) {
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
pmin = GL_NEAREST;
@@ -268,7 +268,7 @@ struct Texture {
max_lod = 0;
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
- use_anisotropy = true;
+ anisotropy = config->anisotropic_level;
};
[[fallthrough]];
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
@@ -278,12 +278,14 @@ struct Texture {
max_lod = 0;
} else if (config->use_nearest_mip_filter) {
pmin = GL_NEAREST_MIPMAP_NEAREST;
+ max_lod = 1000;
} else {
pmin = GL_NEAREST_MIPMAP_LINEAR;
+ max_lod = 1000;
}
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
- use_anisotropy = true;
+ anisotropy = config->anisotropic_level;
};
[[fallthrough]];
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
@@ -293,19 +295,22 @@ struct Texture {
max_lod = 0;
} else if (config->use_nearest_mip_filter) {
pmin = GL_LINEAR_MIPMAP_NEAREST;
+ max_lod = 1000;
} else {
pmin = GL_LINEAR_MIPMAP_LINEAR;
+ max_lod = 1000;
}
} break;
default: {
+ return;
} break;
}
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, pmin);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, pmag);
glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, max_lod);
- if (config->support_anisotropic_filter && use_anisotropy) {
- glTexParameterf(target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, config->anisotropic_level);
+ if (config->support_anisotropic_filter) {
+ glTexParameterf(target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
}
}
void gl_set_repeat(RS::CanvasItemTextureRepeat p_repeat) {
@@ -313,8 +318,11 @@ struct Texture {
return;
}
state_repeat = p_repeat;
- GLenum prep = GL_CLAMP_TO_EDGE; // parameter repeat
+ GLenum prep = GL_CLAMP_TO_EDGE;
switch (state_repeat) {
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
+ prep = GL_CLAMP_TO_EDGE;
+ } break;
case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
prep = GL_REPEAT;
} break;
@@ -322,6 +330,7 @@ struct Texture {
prep = GL_MIRRORED_REPEAT;
} break;
default: {
+ return;
} break;
}
glTexParameteri(target, GL_TEXTURE_WRAP_T, prep);
@@ -330,8 +339,8 @@ struct Texture {
}
private:
- RS::CanvasItemTextureFilter state_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
- RS::CanvasItemTextureRepeat state_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
+ RS::CanvasItemTextureFilter state_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_MAX;
+ RS::CanvasItemTextureRepeat state_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX;
};
struct RenderTarget {
@@ -536,11 +545,12 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) override;
+ virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) override;
virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override;
virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override;
void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
- Image::Format texture_get_format(RID p_texture) const;
+ virtual Image::Format texture_get_format(RID p_texture) const override;
uint32_t texture_get_texid(RID p_texture) const;
uint32_t texture_get_width(RID p_texture) const;
uint32_t texture_get_height(RID p_texture) const;
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index ab0ff32514..0df6b2ba21 100644
--- a/drivers/png/resource_saver_png.cpp
+++ b/drivers/png/resource_saver_png.cpp
@@ -33,7 +33,7 @@
#include "core/io/file_access.h"
#include "core/io/image.h"
#include "drivers/png/png_driver_common.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/image_texture.h"
Error ResourceSaverPNG::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
Ref<ImageTexture> texture = p_resource;
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 45f9f14dab..a80b7d449e 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -108,10 +108,7 @@ Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
last_error = ERR_FILE_CANT_OPEN;
return last_error;
}
- // Fix temporary file permissions (defaults to 0600 instead of 0666 & ~umask).
- mode_t mask = umask(022);
- umask(mask);
- fchmod(fd, 0666 & ~mask);
+ fchmod(fd, 0666);
path = String::utf8(cs.ptr());
f = fdopen(fd, mode_string);
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index b46af012f1..a8074aa3f6 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -204,6 +204,9 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
if (err == WSAEACCES) {
return ERR_NET_UNAUTHORIZED;
}
+ if (err == WSAEMSGSIZE || err == WSAENOBUFS) {
+ return ERR_NET_BUFFER_TOO_SMALL;
+ }
print_verbose("Socket error: " + itos(err));
return ERR_NET_OTHER;
#else
@@ -222,6 +225,9 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
if (errno == EACCES) {
return ERR_NET_UNAUTHORIZED;
}
+ if (errno == ENOBUFS) {
+ return ERR_NET_BUFFER_TOO_SMALL;
+ }
print_verbose("Socket error: " + itos(errno));
return ERR_NET_OTHER;
#endif
@@ -550,6 +556,10 @@ Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
return ERR_BUSY;
}
+ if (err == ERR_NET_BUFFER_TOO_SMALL) {
+ return ERR_OUT_OF_MEMORY;
+ }
+
return FAILED;
}
@@ -571,6 +581,10 @@ Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddr
return ERR_BUSY;
}
+ if (err == ERR_NET_BUFFER_TOO_SMALL) {
+ return ERR_OUT_OF_MEMORY;
+ }
+
return FAILED;
}
@@ -606,6 +620,9 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
if (err == ERR_NET_WOULD_BLOCK) {
return ERR_BUSY;
}
+ if (err == ERR_NET_BUFFER_TOO_SMALL) {
+ return ERR_OUT_OF_MEMORY;
+ }
return FAILED;
}
@@ -625,6 +642,9 @@ Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP
if (err == ERR_NET_WOULD_BLOCK) {
return ERR_BUSY;
}
+ if (err == ERR_NET_BUFFER_TOO_SMALL) {
+ return ERR_OUT_OF_MEMORY;
+ }
return FAILED;
}
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h
index bd2088b4f9..2682530e15 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_posix.h
@@ -56,6 +56,7 @@ private:
ERR_NET_IN_PROGRESS,
ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE,
ERR_NET_UNAUTHORIZED,
+ ERR_NET_BUFFER_TOO_SMALL,
ERR_NET_OTHER,
};
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 967699c5f3..1ffacdf98d 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -315,7 +315,7 @@ Dictionary OS_Unix::get_memory_info() const {
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
vm_statistics64_data_t vmstat;
if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmstat, &count) != KERN_SUCCESS) {
- ERR_PRINT(vformat("Could not get host vm statistics."));
+ ERR_PRINT("Could not get host vm statistics.");
}
struct xsw_usage swap_used;
len = sizeof(swap_used);
@@ -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, "Can't open dynamic library: " + p_path + ". Error: " + dlerror());
+ ERR_FAIL_COND_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 0832a07f51..cd18d84837 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -54,9 +54,13 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
r_access_mask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
if (buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
- r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
@@ -68,8 +72,11 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
r_access_mask |= VK_ACCESS_INDEX_READ_BIT;
buffer = index_buffer_owner.get_or_null(p_buffer);
} else if (uniform_buffer_owner.owns(p_buffer)) {
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
- r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
@@ -77,8 +84,12 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
r_access_mask |= VK_ACCESS_UNIFORM_READ_BIT;
buffer = uniform_buffer_owner.get_or_null(p_buffer);
} else if (texture_buffer_owner.owns(p_buffer)) {
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
- r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+ r_access_mask |= VK_ACCESS_SHADER_READ_BIT;
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
r_access_mask |= VK_ACCESS_SHADER_READ_BIT;
}
if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
@@ -89,8 +100,12 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
buffer = &texture_buffer_owner.get_or_null(p_buffer)->buffer;
} else if (storage_buffer_owner.owns(p_buffer)) {
buffer = storage_buffer_owner.get_or_null(p_buffer);
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
- r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+ r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
@@ -2625,8 +2640,12 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
- barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+ access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
@@ -2874,6 +2893,29 @@ bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) {
return texture_owner.owns(p_texture);
}
+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());
+
+ TextureFormat tf;
+
+ tf.format = tex->format;
+ tf.width = tex->width;
+ tf.height = tex->height;
+ tf.depth = tex->depth;
+ tf.array_layers = tex->layers;
+ tf.mipmaps = tex->mipmaps;
+ tf.texture_type = tex->type;
+ tf.samples = tex->samples;
+ tf.usage_bits = tex->usage_flags;
+ tf.shareable_formats = tex->allowed_shared_formats;
+ tf.is_resolve_buffer = tex->is_resolve_buffer;
+
+ return tf;
+}
+
Size2i RenderingDeviceVulkan::texture_size(RID p_texture) {
_THREAD_SAFE_METHOD_
@@ -3020,8 +3062,12 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
- barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+ access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
@@ -3198,8 +3244,12 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
- barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+ access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
@@ -3334,8 +3384,12 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
- barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+ access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
@@ -4633,7 +4687,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
"Number of uniform sets is larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
// Collect reflection data into binary data.
- RenderingDeviceVulkanShaderBinaryData binary_data;
+ RenderingDeviceVulkanShaderBinaryData binary_data{};
Vector<Vector<RenderingDeviceVulkanShaderBinaryDataBinding>> uniform_info; // Set bindings.
Vector<RenderingDeviceVulkanShaderBinarySpecializationConstant> specialization_constants;
{
@@ -7470,6 +7524,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_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID);
@@ -7485,6 +7540,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_switch_to_next_pass
return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT;
}
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_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, ERR_INVALID_PARAMETER);
@@ -7649,10 +7705,14 @@ void RenderingDeviceVulkan::draw_list_end(BitField<BarrierMask> p_post_barrier)
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
- barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT /*| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT*/;
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT /*| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT*/;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT /*| VK_ACCESS_INDIRECT_COMMAND_READ_BIT*/;
}
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT /*| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT*/;
+ access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT /*| VK_ACCESS_INDIRECT_COMMAND_READ_BIT*/;
+ }
if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
@@ -7729,6 +7789,8 @@ void RenderingDeviceVulkan::draw_list_end(BitField<BarrierMask> p_post_barrier)
/***********************/
RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin(bool p_allow_draw_overlap) {
+ _THREAD_SAFE_METHOD_
+
ERR_FAIL_COND_V_MSG(!p_allow_draw_overlap && draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
@@ -7743,6 +7805,8 @@ RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin(bool p_
}
void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) {
+ // 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);
@@ -7807,6 +7871,8 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
}
void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) {
+ // 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);
@@ -7981,6 +8047,8 @@ void RenderingDeviceVulkan::compute_list_set_push_constant(ComputeListID p_list,
}
void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {
+ // 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);
@@ -8124,6 +8192,8 @@ void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list,
}
void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) {
+ // Must be called within a compute list, the class mutex is locked during that time
+
uint32_t barrier_flags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
uint32_t access_flags = VK_ACCESS_SHADER_READ_BIT;
_compute_list_add_barrier(BARRIER_MASK_COMPUTE, barrier_flags, access_flags);
@@ -8197,10 +8267,14 @@ void RenderingDeviceVulkan::compute_list_end(BitField<BarrierMask> p_post_barrie
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
- barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+ if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) {
+ barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
}
+ if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) {
+ barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+ access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
+ }
if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
@@ -8225,7 +8299,7 @@ void RenderingDeviceVulkan::barrier(BitField<BarrierMask> p_from, BitField<Barri
src_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
src_access_flags |= VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_from.has_flag(BARRIER_MASK_RASTER)) {
+ if (p_from.has_flag(BARRIER_MASK_FRAGMENT)) {
src_barrier_flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
src_access_flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
}
@@ -8245,10 +8319,14 @@ void RenderingDeviceVulkan::barrier(BitField<BarrierMask> p_from, BitField<Barri
dst_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_to.has_flag(BARRIER_MASK_RASTER)) {
- dst_barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+ if (p_to.has_flag(BARRIER_MASK_VERTEX)) {
+ dst_barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
}
+ if (p_to.has_flag(BARRIER_MASK_FRAGMENT)) {
+ dst_barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+ dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
+ }
if (p_to.has_flag(BARRIER_MASK_TRANSFER)) {
dst_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
dst_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
@@ -8604,6 +8682,8 @@ void RenderingDeviceVulkan::swap_buffers() {
}
void RenderingDeviceVulkan::submit() {
+ _THREAD_SAFE_METHOD_
+
ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync.");
ERR_FAIL_COND_MSG(local_device_processing, "device already submitted, call sync to wait until done.");
@@ -8615,6 +8695,8 @@ void RenderingDeviceVulkan::submit() {
}
void RenderingDeviceVulkan::sync() {
+ _THREAD_SAFE_METHOD_
+
ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync.");
ERR_FAIL_COND_MSG(!local_device_processing, "sync can only be called after a submit");
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 9c621c1d44..010f7c9337 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -1082,6 +1082,7 @@ public:
virtual bool texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const;
virtual bool texture_is_shared(RID p_texture);
virtual bool texture_is_valid(RID p_texture);
+ virtual TextureFormat texture_get_format(RID p_texture);
virtual Size2i texture_size(RID p_texture);
virtual uint64_t texture_get_native_handle(RID p_texture);
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 3feed2b109..3a1330b331 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -1775,6 +1775,7 @@ Error VulkanContext::_clean_up_swap_chain(Window *window) {
fpDestroySwapchainKHR(device, window->swapchain, nullptr);
window->swapchain = VK_NULL_HANDLE;
vkDestroyRenderPass(device, window->render_pass, nullptr);
+ window->render_pass = VK_NULL_HANDLE;
if (window->swapchain_image_resources) {
for (uint32_t i = 0; i < swapchainImageCount; i++) {
vkDestroyImageView(device, window->swapchain_image_resources[i].view, nullptr);
@@ -1783,6 +1784,7 @@ Error VulkanContext::_clean_up_swap_chain(Window *window) {
free(window->swapchain_image_resources);
window->swapchain_image_resources = nullptr;
+ swapchainImageCount = 0;
}
if (separate_present_queue) {
vkDestroyCommandPool(device, window->present_cmd_pool, nullptr);
@@ -1818,7 +1820,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
if (window->width == 0 || window->height == 0) {
free(presentModes);
// Likely window minimized, no swapchain created.
- return OK;
+ return ERR_SKIP;
}
// The FIFO present mode is guaranteed by the spec to be supported
// and to have no tearing. It's a great default present mode to use.
@@ -2275,8 +2277,10 @@ Error VulkanContext::prepare_buffers() {
// Swapchain is not as optimal as it could be, but the platform's
// presentation engine will still present the image correctly.
print_verbose("Vulkan: Early suboptimal swapchain, recreating.");
- _update_swap_chain(w);
- break;
+ Error swap_chain_err = _update_swap_chain(w);
+ if (swap_chain_err == ERR_SKIP) {
+ break;
+ }
} else if (err != VK_SUCCESS) {
ERR_BREAK_MSG(err != VK_SUCCESS, "Vulkan: Did not create swapchain successfully. Error code: " + String(string_VkResult(err)));
} else {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 24a6d89118..3aa3aa567b 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -3297,7 +3297,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
track_edits[_get_track_selected()]->release_focus();
}
if (animation.is_valid()) {
- animation->disconnect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed));
+ animation->disconnect_changed(callable_mp(this, &AnimationTrackEditor::_animation_changed));
_clear_selection();
}
animation = p_anim;
@@ -3308,7 +3308,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
_update_tracks();
if (animation.is_valid()) {
- animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed));
+ animation->connect_changed(callable_mp(this, &AnimationTrackEditor::_animation_changed));
hscroll->show();
edit->set_disabled(read_only);
@@ -3632,13 +3632,15 @@ void AnimationTrackEditor::commit_insert_queue() {
}
}
- if (bool(EDITOR_GET("editors/animation/confirm_insert_track")) && num_tracks > 0) {
+ // Skip the confirmation dialog if the user holds Shift while clicking the key icon.
+ if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && num_tracks > 0) {
+ String shortcut_hint = TTR("Hold Shift when clicking the key icon to skip this dialog.");
// Potentially a new key, does not exist.
if (num_tracks == 1) {
// TRANSLATORS: %s will be replaced by a phrase describing the target of track.
- insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?"), last_track_query));
+ insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?") + "\n\n" + shortcut_hint, last_track_query));
} else {
- insert_confirm_text->set_text(vformat(TTR("Create %d new tracks and insert keys?"), num_tracks));
+ insert_confirm_text->set_text(vformat(TTR("Create %d new tracks and insert keys?") + "\n\n" + shortcut_hint, num_tracks));
}
insert_confirm_bezier->set_visible(all_bezier);
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 6824bc7960..553f391a1d 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -875,8 +875,6 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int
Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream);
- float preview_len = preview->get_length();
-
int pixel_total_len = len * p_pixels_sec;
len -= end_ofs;
@@ -918,7 +916,7 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int
Vector<Vector2> points;
points.resize((to_x - from_x) * 2);
- preview_len = preview->get_length();
+ float preview_len = preview->get_length();
for (int i = from_x; i < to_x; i++) {
float ofs = (i - pixel_begin) * preview_len / pixel_total_len;
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index b48bd4ab5f..cde74e0854 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -126,7 +126,7 @@ void FindReplaceBar::unhandled_input(const Ref<InputEvent> &p_event) {
if (k.is_valid() && k->is_action_pressed(SNAME("ui_cancel"), false, true)) {
Control *focus_owner = get_viewport()->gui_get_focus_owner();
- if (text_editor->has_focus() || (focus_owner && vbc_lineedit->is_ancestor_of(focus_owner))) {
+ if (text_editor->has_focus() || (focus_owner && is_ancestor_of(focus_owner))) {
_hide_bar();
accept_event();
}
@@ -410,7 +410,7 @@ void FindReplaceBar::_update_matches_label() {
matches_label->add_theme_color_override("font_color", results_count > 0 ? get_theme_color(SNAME("font_color"), SNAME("Label")) : get_theme_color(SNAME("error_color"), SNAME("Editor")));
if (results_count == 0) {
- matches_label->set_text("No match");
+ matches_label->set_text(TTR("No match"));
} else if (results_count_to_current == -1) {
matches_label->set_text(vformat(TTRN("%d match", "%d matches", results_count), results_count));
} else {
@@ -905,7 +905,7 @@ void CodeTextEditor::_line_col_changed() {
}
void CodeTextEditor::_text_changed() {
- if (text_editor->is_insert_text_operation()) {
+ if (code_complete_enabled && text_editor->is_insert_text_operation()) {
code_complete_timer_line = text_editor->get_caret_line();
code_complete_timer->start();
}
@@ -1485,12 +1485,13 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) {
// Check first if there's any uncommented lines in selection.
bool is_commented = true;
for (int line = from; line <= to; line++) {
- if (!text_editor->get_line(line).begins_with(delimiter)) {
+ // `+ delimiter.length()` here because comment delimiter is not actually `in comment` so we check first character after it
+ int delimiter_idx = text_editor->is_in_comment(line, text_editor->get_first_non_whitespace_column(line) + delimiter.length());
+ if (delimiter_idx == -1 || text_editor->get_delimiter_start_key(delimiter_idx) != delimiter) {
is_commented = false;
break;
}
}
-
// Caret positions need to be saved since they could be moved at the eol.
Vector<int> caret_cols;
Vector<int> selection_to_cols;
@@ -1511,10 +1512,10 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) {
continue;
}
if (is_commented) {
- text_editor->set_line(line, line_text.substr(delimiter.length(), line_text.length()));
- continue;
+ text_editor->set_line(line, line_text.replace_first(delimiter, ""));
+ } else {
+ text_editor->set_line(line, line_text.insert(text_editor->get_first_non_whitespace_column(line), delimiter));
}
- text_editor->set_line(line, delimiter + line_text);
}
// Readjust carets and selections.
@@ -1736,6 +1737,7 @@ void CodeTextEditor::_apply_settings_change() {
text_editor->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"));
+ code_complete_enabled = EDITOR_GET("text_editor/completion/code_complete_enabled");
code_complete_timer->set_wait_time(EDITOR_GET("text_editor/completion/code_complete_delay"));
idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay"));
}
@@ -2010,6 +2012,7 @@ CodeTextEditor::CodeTextEditor() {
idle->set_one_shot(true);
idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay"));
+ code_complete_enabled = EDITOR_GET("text_editor/completion/code_complete_enabled");
code_complete_timer = memnew(Timer);
add_child(code_complete_timer);
code_complete_timer->set_one_shot(true);
diff --git a/editor/code_editor.h b/editor/code_editor.h
index a83bb96771..c18154a1ef 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -157,6 +157,7 @@ class CodeTextEditor : public VBoxContainer {
Label *info = nullptr;
Timer *idle = nullptr;
+ bool code_complete_enabled = true;
Timer *code_complete_timer = nullptr;
int code_complete_timer_line = 0;
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index f4b7b14e99..3965dcd198 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -39,6 +39,7 @@
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/gui/scene_tree_editor.h"
+#include "editor/node_dock.h"
#include "editor/scene_tree_dock.h"
#include "plugins/script_editor_plugin.h"
#include "scene/gui/button.h"
@@ -1440,6 +1441,7 @@ ConnectionsDock::ConnectionsDock() {
connect_button->connect("pressed", callable_mp(this, &ConnectionsDock::_connect_pressed));
connect_dialog = memnew(ConnectDialog);
+ connect_dialog->connect("connected", callable_mp(NodeDock::get_singleton(), &NodeDock::restore_last_valid_node), CONNECT_DEFERRED);
add_child(connect_dialog);
disconnect_all_dialog = memnew(ConfirmationDialog);
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 6d345a1d84..8b71d7586f 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -370,7 +370,8 @@ float CreateDialog::_score_type(const String &p_type, const String &p_search) co
// Look through at most 5 recent items
bool in_recent = false;
- for (int i = 0; i < MIN(5, recent->get_item_count()); i++) {
+ constexpr int RECENT_COMPLETION_SIZE = 5;
+ for (int i = 0; i < MIN(RECENT_COMPLETION_SIZE - 1, recent->get_item_count()); i++) {
if (recent->get_item_text(i) == p_type) {
in_recent = true;
break;
@@ -406,7 +407,8 @@ void CreateDialog::_confirmed() {
if (f.is_valid()) {
f->store_line(selected_item);
- for (int i = 0; i < MIN(32, recent->get_item_count()); i++) {
+ constexpr int RECENT_HISTORY_SIZE = 15;
+ for (int i = 0; i < MIN(RECENT_HISTORY_SIZE - 1, recent->get_item_count()); i++) {
if (recent->get_item_text(i) != selected_item) {
f->store_line(recent->get_item_text(i));
}
diff --git a/editor/debugger/editor_debugger_inspector.cpp b/editor/debugger/editor_debugger_inspector.cpp
index e083e1746d..1e9b7c2c60 100644
--- a/editor/debugger/editor_debugger_inspector.cpp
+++ b/editor/debugger/editor_debugger_inspector.cpp
@@ -232,7 +232,7 @@ void EditorDebuggerInspector::add_stack_variable(const Array &p_array) {
PropertyHint h = PROPERTY_HINT_NONE;
String hs;
- if (v.get_type() == Variant::OBJECT) {
+ if (var.var_type == Variant::OBJECT) {
v = Object::cast_to<EncodedObjectAsID>(v)->get_object_id();
h = PROPERTY_HINT_OBJECT_ID;
hs = "Object";
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 5e677c454e..e59fc6186a 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -33,6 +33,7 @@
#include "core/os/os.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "scene/resources/image_texture.h"
void EditorProfiler::_make_metric_ptrs(Metric &m) {
for (int i = 0; i < m.categories.size(); i++) {
diff --git a/editor/debugger/editor_profiler.h b/editor/debugger/editor_profiler.h
index eea8ed8365..3f7a0cade5 100644
--- a/editor/debugger/editor_profiler.h
+++ b/editor/debugger/editor_profiler.h
@@ -40,6 +40,8 @@
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
+class ImageTexture;
+
class EditorProfiler : public VBoxContainer {
GDCLASS(EditorProfiler, VBoxContainer);
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index 2ecb029f1a..984d8e33c5 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -33,6 +33,7 @@
#include "core/os/os.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "scene/resources/image_texture.h"
void EditorVisualProfiler::add_frame_metric(const Metric &p_metric) {
++last_metric;
diff --git a/editor/debugger/editor_visual_profiler.h b/editor/debugger/editor_visual_profiler.h
index 5831e3322d..492985506a 100644
--- a/editor/debugger/editor_visual_profiler.h
+++ b/editor/debugger/editor_visual_profiler.h
@@ -41,6 +41,8 @@
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
+class ImageTexture;
+
class EditorVisualProfiler : public VBoxContainer {
GDCLASS(EditorVisualProfiler, VBoxContainer);
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 8985387043..2c40f0e120 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -71,10 +71,12 @@
using CameraOverride = EditorDebuggerNode::CameraOverride;
-void ScriptEditorDebugger::_put_msg(String p_message, Array p_data) {
+void ScriptEditorDebugger::_put_msg(String p_message, Array p_data, uint64_t p_thread_id) {
+ ERR_FAIL_COND(p_thread_id == Thread::UNASSIGNED_ID);
if (is_session_active()) {
Array msg;
msg.push_back(p_message);
+ msg.push_back(p_thread_id);
msg.push_back(p_data);
peer->put_message(msg);
}
@@ -98,31 +100,31 @@ void ScriptEditorDebugger::debug_skip_breakpoints() {
Array msg;
msg.push_back(skip_breakpoints_value);
- _put_msg("set_skip_breakpoints", msg);
+ _put_msg("set_skip_breakpoints", msg, debugging_thread_id != Thread::UNASSIGNED_ID ? debugging_thread_id : Thread::MAIN_ID);
}
void ScriptEditorDebugger::debug_next() {
- ERR_FAIL_COND(!breaked);
+ ERR_FAIL_COND(!is_breaked());
- _put_msg("next", Array());
+ _put_msg("next", Array(), debugging_thread_id);
_clear_execution();
}
void ScriptEditorDebugger::debug_step() {
- ERR_FAIL_COND(!breaked);
+ ERR_FAIL_COND(!is_breaked());
- _put_msg("step", Array());
+ _put_msg("step", Array(), debugging_thread_id);
_clear_execution();
}
void ScriptEditorDebugger::debug_break() {
- ERR_FAIL_COND(breaked);
+ ERR_FAIL_COND(is_breaked());
_put_msg("break", Array());
}
void ScriptEditorDebugger::debug_continue() {
- ERR_FAIL_COND(!breaked);
+ ERR_FAIL_COND(!is_breaked());
// Allow focus stealing only if we actually run this client for security.
if (remote_pid && EditorNode::get_singleton()->has_child_process(remote_pid)) {
@@ -130,7 +132,7 @@ void ScriptEditorDebugger::debug_continue() {
}
_clear_execution();
- _put_msg("continue", Array());
+ _put_msg("continue", Array(), debugging_thread_id);
_put_msg("servers:foreground", Array());
}
@@ -299,43 +301,89 @@ Size2 ScriptEditorDebugger::get_minimum_size() const {
return ms;
}
-void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) {
+void ScriptEditorDebugger::_thread_debug_enter(uint64_t p_thread_id) {
+ ERR_FAIL_COND(!threads_debugged.has(p_thread_id));
+ ThreadDebugged &td = threads_debugged[p_thread_id];
+ _set_reason_text(td.error, MESSAGE_ERROR);
+ emit_signal(SNAME("breaked"), true, td.can_debug, td.error, td.has_stackdump);
+ if (!td.error.is_empty()) {
+ tabs->set_current_tab(0);
+ }
+ inspector->clear_cache(); // Take a chance to force remote objects update.
+ _put_msg("get_stack_dump", Array(), p_thread_id);
+}
+
+void ScriptEditorDebugger::_select_thread(int p_index) {
+ debugging_thread_id = threads->get_item_metadata(threads->get_selected());
+ _thread_debug_enter(debugging_thread_id);
+}
+
+void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread_id, const Array &p_data) {
emit_signal(SNAME("debug_data"), p_msg, p_data);
if (p_msg == "debug_enter") {
- _put_msg("get_stack_dump", Array());
-
- ERR_FAIL_COND(p_data.size() != 3);
- bool can_continue = p_data[0];
- String error = p_data[1];
- bool has_stackdump = p_data[2];
- breaked = true;
- can_request_idle_draw = true;
- can_debug = can_continue;
- _update_buttons_state();
- _set_reason_text(error, MESSAGE_ERROR);
- emit_signal(SNAME("breaked"), true, can_continue, error, has_stackdump);
- if (is_move_to_foreground()) {
- DisplayServer::get_singleton()->window_move_to_foreground();
- }
- if (!error.is_empty()) {
- tabs->set_current_tab(0);
+ ERR_FAIL_COND(p_data.size() != 4);
+
+ ThreadDebugged td;
+ td.name = p_data[3];
+ td.error = p_data[1];
+ td.can_debug = p_data[0];
+ td.has_stackdump = p_data[2];
+ td.thread_id = p_thread_id;
+ static uint32_t order_inc = 0;
+ td.debug_order = order_inc++;
+
+ threads_debugged.insert(p_thread_id, td);
+
+ if (threads_debugged.size() == 1) {
+ // First thread that requests debug
+ debugging_thread_id = p_thread_id;
+ _thread_debug_enter(p_thread_id);
+ can_request_idle_draw = true;
+ if (is_move_to_foreground()) {
+ DisplayServer::get_singleton()->window_move_to_foreground();
+ }
+ profiler->set_enabled(false, false);
+ visual_profiler->set_enabled(false);
}
- profiler->set_enabled(false, false);
- visual_profiler->set_enabled(false);
- inspector->clear_cache(); // Take a chance to force remote objects update.
+ _update_buttons_state();
} else if (p_msg == "debug_exit") {
- breaked = false;
- can_debug = false;
- _clear_execution();
- _update_buttons_state();
- _set_reason_text(TTR("Execution resumed."), MESSAGE_SUCCESS);
- emit_signal(SNAME("breaked"), false, false, "", false);
+ threads_debugged.erase(p_thread_id);
+ if (p_thread_id == debugging_thread_id) {
+ _clear_execution();
+ if (threads_debugged.size() == 0) {
+ debugging_thread_id = Thread::UNASSIGNED_ID;
+ } else {
+ // Find next thread to debug.
+ uint32_t min_order = 0xFFFFFFFF;
+ uint64_t next_thread = Thread::UNASSIGNED_ID;
+ for (KeyValue<uint64_t, ThreadDebugged> T : threads_debugged) {
+ if (T.value.debug_order < min_order) {
+ min_order = T.value.debug_order;
+ next_thread = T.key;
+ }
+ }
+
+ debugging_thread_id = next_thread;
+ }
- profiler->set_enabled(true, false);
- profiler->disable_seeking();
+ if (debugging_thread_id == Thread::UNASSIGNED_ID) {
+ // Nothing else to debug.
+ profiler->set_enabled(true, false);
+ profiler->disable_seeking();
- visual_profiler->set_enabled(true);
+ visual_profiler->set_enabled(true);
+
+ _set_reason_text(TTR("Execution resumed."), MESSAGE_SUCCESS);
+ emit_signal(SNAME("breaked"), false, false, "", false);
+
+ _update_buttons_state();
+ } else {
+ _thread_debug_enter(debugging_thread_id);
+ }
+ } else {
+ _update_buttons_state();
+ }
} else if (p_msg == "set_pid") {
ERR_FAIL_COND(p_data.size() < 1);
@@ -379,7 +427,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
vmem_total->set_tooltip_text(TTR("Bytes:") + " " + itos(total));
vmem_total->set_text(String::humanize_size(total));
-
} else if (p_msg == "servers:drawn") {
can_request_idle_draw = true;
} else if (p_msg == "stack_dump") {
@@ -414,11 +461,9 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
inspector->clear_stack_variables();
ERR_FAIL_COND(p_data.size() != 1);
emit_signal(SNAME("stack_frame_vars"), p_data[0]);
-
} else if (p_msg == "stack_frame_var") {
inspector->add_stack_variable(p_data);
emit_signal(SNAME("stack_frame_var"), p_data);
-
} else if (p_msg == "output") {
ERR_FAIL_COND(p_data.size() != 2);
@@ -458,7 +503,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
frame_data.write[i] = p_data[i];
}
performance_profiler->add_profile_frame(frame_data);
-
} else if (p_msg == "visual:profile_frame") {
ServersDebugger::VisualProfilerFrame frame;
frame.deserialize(p_data);
@@ -477,7 +521,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
}
}
visual_profiler->add_frame_metric(metric);
-
} else if (p_msg == "error") {
DebuggerMarshalls::OutputError oe;
ERR_FAIL_COND_MSG(oe.deserialize(p_data) == false, "Failed to deserialize error message");
@@ -625,13 +668,11 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
} else {
error_count++;
}
-
} else if (p_msg == "servers:function_signature") {
// Cache a profiler signature.
ServersDebugger::ScriptFunctionSignature sig;
sig.deserialize(p_data);
profiler_signature[sig.id] = sig.name;
-
} else if (p_msg == "servers:profile_frame" || p_msg == "servers:profile_total") {
EditorProfiler::Metric metric;
ServersDebugger::ServersProfilerFrame frame;
@@ -744,11 +785,9 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
} else {
profiler->add_frame_metric(metric, true);
}
-
} else if (p_msg == "request_quit") {
emit_signal(SNAME("stop_requested"));
_stop_and_notify();
-
} else if (p_msg == "performance:profile_names") {
Vector<StringName> monitors;
monitors.resize(p_data.size());
@@ -757,13 +796,11 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
monitors.set(i, p_data[i]);
}
performance_profiler->update_monitors(monitors);
-
} else if (p_msg == "filesystem:update_file") {
ERR_FAIL_COND(p_data.size() < 1);
if (EditorFileSystem::get_singleton()) {
EditorFileSystem::get_singleton()->update_file(p_data[0]);
}
-
} else {
int colon_index = p_msg.find_char(':');
ERR_FAIL_COND_MSG(colon_index < 1, "Invalid message received");
@@ -878,7 +915,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
msg.push_back(cam->get_far());
_put_msg("scene:override_camera_3D:transform", msg);
}
- if (breaked && can_request_idle_draw) {
+ if (is_breaked() && can_request_idle_draw) {
_put_msg("servers:draw", Array());
can_request_idle_draw = false;
}
@@ -888,11 +925,12 @@ void ScriptEditorDebugger::_notification(int p_what) {
while (peer.is_valid() && peer->has_message()) {
Array arr = peer->get_message();
- if (arr.size() != 2 || arr[0].get_type() != Variant::STRING || arr[1].get_type() != Variant::ARRAY) {
+ if (arr.size() != 3 || arr[0].get_type() != Variant::STRING || arr[1].get_type() != Variant::INT || arr[2].get_type() != Variant::ARRAY) {
_stop_and_notify();
ERR_FAIL_MSG("Invalid message format received from peer");
}
- _parse_message(arr[0], arr[1]);
+
+ _parse_message(arr[0], arr[1], arr[2]);
if (OS::get_singleton()->get_ticks_msec() > until) {
break;
@@ -959,8 +997,6 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
performance_profiler->reset();
set_process(true);
- breaked = false;
- can_debug = true;
camera_override = CameraOverride::OVERRIDE_NONE;
tabs->set_current_tab(0);
@@ -973,13 +1009,35 @@ void ScriptEditorDebugger::_update_buttons_state() {
const bool active = is_session_active();
const bool has_editor_tree = active && editor_remote_tree && editor_remote_tree->get_selected();
vmem_refresh->set_disabled(!active);
- step->set_disabled(!active || !breaked || !can_debug);
- next->set_disabled(!active || !breaked || !can_debug);
- copy->set_disabled(!active || !breaked);
- docontinue->set_disabled(!active || !breaked);
- dobreak->set_disabled(!active || breaked);
+ step->set_disabled(!active || !is_breaked() || !is_debuggable());
+ next->set_disabled(!active || !is_breaked() || !is_debuggable());
+ copy->set_disabled(!active || !is_breaked());
+ docontinue->set_disabled(!active || !is_breaked());
+ dobreak->set_disabled(!active || is_breaked());
le_clear->set_disabled(!active);
le_set->set_disabled(!has_editor_tree);
+
+ thread_list_updating = true;
+ LocalVector<ThreadDebugged *> threadss;
+ for (KeyValue<uint64_t, ThreadDebugged> &I : threads_debugged) {
+ threadss.push_back(&I.value);
+ }
+
+ threadss.sort_custom<ThreadSort>();
+ threads->clear();
+ int32_t selected_index = -1;
+ for (uint32_t i = 0; i < threadss.size(); i++) {
+ if (debugging_thread_id == threadss[i]->thread_id) {
+ selected_index = i;
+ }
+ threads->add_item(threadss[i]->name);
+ threads->set_item_metadata(threads->get_item_count() - 1, threadss[i]->thread_id);
+ }
+ if (selected_index != -1) {
+ threads->select(selected_index);
+ }
+
+ thread_list_updating = false;
}
void ScriptEditorDebugger::_stop_and_notify() {
@@ -990,8 +1048,8 @@ void ScriptEditorDebugger::_stop_and_notify() {
void ScriptEditorDebugger::stop() {
set_process(false);
- breaked = false;
- can_debug = false;
+ threads_debugged.clear();
+ debugging_thread_id = Thread::UNASSIGNED_ID;
remote_pid = 0;
_clear_execution();
@@ -1043,7 +1101,7 @@ void ScriptEditorDebugger::_profiler_activate(bool p_enable, int p_type) {
}
void ScriptEditorDebugger::_profiler_seeked() {
- if (breaked) {
+ if (is_breaked()) {
return;
}
debug_break();
@@ -1067,7 +1125,7 @@ void ScriptEditorDebugger::_export_csv() {
}
String ScriptEditorDebugger::get_var_value(const String &p_var) const {
- if (!breaked) {
+ if (!is_breaked()) {
return String();
}
return inspector->get_stack_variable(p_var);
@@ -1255,7 +1313,7 @@ bool ScriptEditorDebugger::request_stack_dump(const int &p_frame) {
Array msg;
msg.push_back(p_frame);
- _put_msg("get_stack_frame_vars", msg);
+ _put_msg("get_stack_frame_vars", msg, debugging_thread_id);
return true;
}
@@ -1407,7 +1465,7 @@ void ScriptEditorDebugger::set_breakpoint(const String &p_path, int p_line, bool
msg.push_back(p_path);
msg.push_back(p_line);
msg.push_back(p_enabled);
- _put_msg("breakpoint", msg);
+ _put_msg("breakpoint", msg, debugging_thread_id != Thread::UNASSIGNED_ID ? debugging_thread_id : Thread::MAIN_ID);
TreeItem *path_item = breakpoints_tree->search_item_text(p_path);
if (path_item == nullptr) {
@@ -1450,7 +1508,7 @@ void ScriptEditorDebugger::set_breakpoint(const String &p_path, int p_line, bool
}
void ScriptEditorDebugger::reload_scripts() {
- _put_msg("reload_scripts", Array());
+ _put_msg("reload_scripts", Array(), debugging_thread_id != Thread::UNASSIGNED_ID ? debugging_thread_id : Thread::MAIN_ID);
}
bool ScriptEditorDebugger::is_skip_breakpoints() {
@@ -1804,15 +1862,26 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
sc->set_h_size_flags(SIZE_EXPAND_FILL);
parent_sc->add_child(sc);
+ VBoxContainer *stack_vb = memnew(VBoxContainer);
+ stack_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ sc->add_child(stack_vb);
+ HBoxContainer *thread_hb = memnew(HBoxContainer);
+ stack_vb->add_child(thread_hb);
+ thread_hb->add_child(memnew(Label(TTR("Thread:"))));
+ threads = memnew(OptionButton);
+ thread_hb->add_child(threads);
+ threads->set_h_size_flags(SIZE_EXPAND_FILL);
+ threads->connect("item_selected", callable_mp(this, &ScriptEditorDebugger::_select_thread));
+
stack_dump = memnew(Tree);
stack_dump->set_allow_reselect(true);
stack_dump->set_columns(1);
stack_dump->set_column_titles_visible(true);
stack_dump->set_column_title(0, TTR("Stack Frames"));
- stack_dump->set_h_size_flags(SIZE_EXPAND_FILL);
stack_dump->set_hide_root(true);
+ stack_dump->set_v_size_flags(SIZE_EXPAND_FILL);
stack_dump->connect("cell_selected", callable_mp(this, &ScriptEditorDebugger::_stack_dump_frame_selected));
- sc->add_child(stack_dump);
+ stack_vb->add_child(stack_dump);
VBoxContainer *inspector_vbox = memnew(VBoxContainer);
inspector_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index 336a113163..7e9a767273 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -138,6 +138,7 @@ private:
Tree *stack_dump = nullptr;
LineEdit *search = nullptr;
+ OptionButton *threads = nullptr;
EditorDebuggerInspector *inspector = nullptr;
SceneDebuggerTree *scene_tree = nullptr;
@@ -152,19 +153,39 @@ private:
EditorPerformanceProfiler *performance_profiler = nullptr;
OS::ProcessID remote_pid = 0;
- bool breaked = false;
- bool can_debug = false;
bool move_to_foreground = true;
bool can_request_idle_draw = false;
bool live_debug;
+ uint64_t debugging_thread_id = Thread::UNASSIGNED_ID;
+
+ struct ThreadDebugged {
+ String name;
+ String error;
+ bool can_debug = false;
+ bool has_stackdump = false;
+ uint32_t debug_order = 0;
+ uint64_t thread_id = Thread::UNASSIGNED_ID; // for order
+ };
+
+ struct ThreadSort {
+ bool operator()(const ThreadDebugged *a, const ThreadDebugged *b) const {
+ return a->debug_order < b->debug_order;
+ }
+ };
+
+ HashMap<uint64_t, ThreadDebugged> threads_debugged;
+ bool thread_list_updating = false;
+
+ void _select_thread(int p_index);
+
EditorDebuggerNode::CameraOverride camera_override;
void _stack_dump_frame_selected();
void _file_selected(const String &p_file);
- void _parse_message(const String &p_msg, const Array &p_data);
+ void _parse_message(const String &p_msg, uint64_t p_thread_id, const Array &p_data);
void _set_reason_text(const String &p_reason, MessageType p_type);
void _update_buttons_state();
void _remote_object_selected(ObjectID p_object);
@@ -200,7 +221,7 @@ private:
void _item_menu_id_pressed(int p_option);
void _tab_changed(int p_tab);
- void _put_msg(String p_message, Array p_data);
+ void _put_msg(String p_message, Array p_data, uint64_t p_thread_id = Thread::MAIN_ID);
void _export_csv();
void _clear_execution();
@@ -213,6 +234,8 @@ private:
String _format_frame_text(const ScriptLanguage::StackInfo *info);
+ void _thread_debug_enter(uint64_t p_thread_id);
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -238,9 +261,9 @@ public:
void debug_step();
void debug_break();
void debug_continue();
- bool is_breaked() const { return breaked; }
- bool is_debuggable() const { return can_debug; }
- bool is_session_active() { return peer.is_valid() && peer->is_peer_connected(); };
+ bool is_breaked() const { return threads_debugged.size() > 0; }
+ bool is_debuggable() const { return threads_debugged.size() > 0 && threads_debugged[debugging_thread_id].can_debug; }
+ bool is_session_active() { return peer.is_valid() && peer->is_peer_connected(); }
int get_remote_pid() const { return remote_pid; }
bool is_move_to_foreground() const;
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 91358c3475..7929c4b0ca 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -36,9 +36,9 @@
#include "core/io/compression.h"
#include "core/io/dir_access.h"
#include "core/io/marshalls.h"
+#include "core/io/resource_importer.h"
#include "core/object/script_language.h"
#include "core/string/translation.h"
-#include "core/version.h"
#include "editor/editor_settings.h"
#include "editor/export/editor_export.h"
#include "scene/resources/theme.h"
@@ -374,11 +374,6 @@ void DocTools::generate(bool p_basic_types) {
classes.pop_front();
continue;
}
- if (ClassDB::get_api_type(name) != ClassDB::API_CORE && ClassDB::get_api_type(name) != ClassDB::API_EDITOR) {
- print_verbose(vformat("Class '%s' belongs neither to core nor editor, skipping.", name));
- classes.pop_front();
- continue;
- }
String cname = name;
// Property setters and getters do not get exposed as individual methods.
@@ -392,7 +387,13 @@ void DocTools::generate(bool p_basic_types) {
List<PropertyInfo> properties;
List<PropertyInfo> own_properties;
- // Special case for editor and project settings, so they can be documented.
+ // Special cases for editor/project settings, and ResourceImporter classes,
+ // we have to rely on Object's property list to get settings and import options.
+ // Otherwise we just use ClassDB's property list (pure registered properties).
+
+ bool properties_from_instance = true; // To skip `script`, etc.
+ bool import_option = false; // Special case for default value.
+ HashMap<StringName, Variant> import_options_default;
if (name == "EditorSettings") {
// We don't create the full blown EditorSettings (+ config file) with `create()`,
// instead we just make a local instance to get default values.
@@ -402,7 +403,20 @@ void DocTools::generate(bool p_basic_types) {
} else if (name == "ProjectSettings") {
ProjectSettings::get_singleton()->get_property_list(&properties);
own_properties = properties;
+ } else if (ClassDB::is_parent_class(name, "ResourceImporter") && name != "EditorImportPlugin" && ClassDB::can_instantiate(name)) {
+ import_option = true;
+ ResourceImporter *resimp = Object::cast_to<ResourceImporter>(ClassDB::instantiate(name));
+ List<ResourceImporter::ImportOption> options;
+ resimp->get_import_options("", &options);
+ for (int i = 0; i < options.size(); i++) {
+ const PropertyInfo &prop = options[i].option;
+ properties.push_back(prop);
+ import_options_default[prop.name] = options[i].default_value;
+ }
+ own_properties = properties;
+ memdelete(resimp);
} else if (name.begins_with("EditorExportPlatform") && ClassDB::can_instantiate(name)) {
+ properties_from_instance = false;
Ref<EditorExportPlatform> platform = Object::cast_to<EditorExportPlatform>(ClassDB::instantiate(name));
if (platform.is_valid()) {
List<EditorExportPlatform::ExportOption> options;
@@ -413,6 +427,7 @@ void DocTools::generate(bool p_basic_types) {
own_properties = properties;
}
} else {
+ properties_from_instance = false;
ClassDB::get_property_list(name, &properties);
ClassDB::get_property_list(name, &own_properties, true);
}
@@ -429,6 +444,13 @@ void DocTools::generate(bool p_basic_types) {
EO = EO->next();
}
+ if (properties_from_instance) {
+ if (E.name == "resource_local_to_scene" || E.name == "resource_name" || E.name == "resource_path" || E.name == "script") {
+ // Don't include spurious properties from Object property list.
+ continue;
+ }
+ }
+
if (E.usage & PROPERTY_USAGE_GROUP || E.usage & PROPERTY_USAGE_SUBGROUP || E.usage & PROPERTY_USAGE_CATEGORY || E.usage & PROPERTY_USAGE_INTERNAL || (E.type == Variant::NIL && E.usage & PROPERTY_USAGE_ARRAY)) {
continue;
}
@@ -448,22 +470,9 @@ void DocTools::generate(bool p_basic_types) {
bool default_value_valid = false;
Variant default_value;
- if (name == "EditorSettings") {
- if (E.name == "resource_local_to_scene" || E.name == "resource_name" || E.name == "resource_path" || E.name == "script") {
- // Don't include spurious properties in the generated EditorSettings class reference.
- continue;
- }
- }
-
- if (name.begins_with("EditorExportPlatform")) {
- if (E.name == "script") {
- continue;
- }
- }
-
if (name == "ProjectSettings") {
// Special case for project settings, so that settings are not taken from the current project's settings
- if (E.name == "script" || !ProjectSettings::get_singleton()->is_builtin_setting(E.name)) {
+ if (!ProjectSettings::get_singleton()->is_builtin_setting(E.name)) {
continue;
}
if (E.usage & PROPERTY_USAGE_EDITOR) {
@@ -472,6 +481,9 @@ void DocTools::generate(bool p_basic_types) {
default_value_valid = true;
}
}
+ } else if (import_option) {
+ default_value = import_options_default[E.name];
+ default_value_valid = true;
} else {
default_value = get_documentation_default_value(name, E.name, default_value_valid);
if (inherited) {
@@ -1487,7 +1499,6 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
header += " is_experimental=\"true\"";
}
}
- header += String(" version=\"") + VERSION_BRANCH + "\"";
if (p_include_xml_schema) {
// Reference the XML schema so editors can provide error checking.
// Modules are nested deep, so change the path to reference the same schema everywhere.
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index be7376a5c4..0b2c2bea15 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -925,7 +925,6 @@ Dictionary EditorData::restore_edited_scene_state(EditorSelection *p_selection,
for (Node *E : es.selection) {
p_selection->add_node(E);
}
- p_selection->cancel_update(); // Selection update results in redundant Node edit, so we cancel it.
set_editor_plugin_states(es.editor_states);
return es.custom_state;
@@ -1155,15 +1154,6 @@ Ref<Texture2D> EditorData::get_script_icon(const Ref<Script> &p_script) {
return ext_icon;
}
- // Look for the base type in the editor theme.
- // This is only relevant for built-in classes.
- const Control *gui_base = EditorNode::get_singleton()->get_gui_base();
- if (gui_base && gui_base->has_theme_icon(base_type, SNAME("EditorIcons"))) {
- Ref<Texture2D> theme_icon = gui_base->get_theme_icon(base_type, SNAME("EditorIcons"));
- _script_icon_cache[p_script] = theme_icon;
- return theme_icon;
- }
-
// If no icon found, cache it as null.
_script_icon_cache[p_script] = Ref<Texture>();
return nullptr;
@@ -1350,10 +1340,6 @@ void EditorSelection::clear() {
node_list_changed = true;
}
-void EditorSelection::cancel_update() {
- changed = false;
-}
-
EditorSelection::EditorSelection() {
}
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 400cbb0536..28fe13e537 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -312,7 +312,6 @@ public:
void update();
void clear();
- void cancel_update();
// Returns all the selected nodes.
TypedArray<Node> get_selected_nodes();
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 7c77fec81a..308bf33da5 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -419,13 +419,7 @@ void EditorFeatureProfileManager::_update_profile_list(const String &p_select_pr
void EditorFeatureProfileManager::_profile_action(int p_action) {
switch (p_action) {
case PROFILE_CLEAR: {
- EditorSettings::get_singleton()->set("_default_feature_profile", "");
- EditorSettings::get_singleton()->save();
- current_profile = "";
- current.unref();
-
- _update_profile_list();
- _emit_current_profile_changed();
+ set_current_profile("", false);
} break;
case PROFILE_SET: {
String selected = _get_selected_profile();
@@ -433,13 +427,7 @@ void EditorFeatureProfileManager::_profile_action(int p_action) {
if (selected == current_profile) {
return; // Nothing to do here.
}
- EditorSettings::get_singleton()->set("_default_feature_profile", selected);
- EditorSettings::get_singleton()->save();
- current_profile = selected;
- current = edited;
-
- _update_profile_list();
- _emit_current_profile_changed();
+ set_current_profile(selected, false);
} break;
case PROFILE_IMPORT: {
import_profiles->popup_file_dialog();
@@ -878,11 +866,45 @@ Ref<EditorFeatureProfile> EditorFeatureProfileManager::get_current_profile() {
return current;
}
+String EditorFeatureProfileManager::get_current_profile_name() const {
+ return current_profile;
+}
+
+void EditorFeatureProfileManager::set_current_profile(const String &p_profile_name, bool p_validate_profile) {
+ if (p_validate_profile && !p_profile_name.is_empty()) {
+ // Profile may not exist.
+ Ref<DirAccess> da = DirAccess::open(EditorPaths::get_singleton()->get_feature_profiles_dir());
+ ERR_FAIL_COND_MSG(da.is_null(), "Cannot open directory '" + EditorPaths::get_singleton()->get_feature_profiles_dir() + "'.");
+ ERR_FAIL_COND_MSG(!da->file_exists(p_profile_name + ".profile"), "Feature profile '" + p_profile_name + "' does not exist.");
+
+ // Change profile selection to emulate the UI interaction. Otherwise, the wrong profile would get activated.
+ // FIXME: Ideally, _update_selected_profile() should not rely on the user interface state to function properly.
+ for (int i = 0; i < profile_list->get_item_count(); i++) {
+ if (profile_list->get_item_metadata(i) == p_profile_name) {
+ profile_list->select(i);
+ break;
+ }
+ }
+ _update_selected_profile();
+ }
+
+ // Store in editor settings.
+ EditorSettings::get_singleton()->set("_default_feature_profile", p_profile_name);
+ EditorSettings::get_singleton()->save();
+
+ current_profile = p_profile_name;
+ if (p_profile_name.is_empty()) {
+ current.unref();
+ } else {
+ current = edited;
+ }
+ _update_profile_list();
+ _emit_current_profile_changed();
+}
+
EditorFeatureProfileManager *EditorFeatureProfileManager::singleton = nullptr;
void EditorFeatureProfileManager::_bind_methods() {
- ClassDB::bind_method("_update_selected_profile", &EditorFeatureProfileManager::_update_selected_profile);
-
ADD_SIGNAL(MethodInfo("current_feature_profile_changed"));
}
diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h
index 3f70e03ca8..25ee1c9ba4 100644
--- a/editor/editor_feature_profile.h
+++ b/editor/editor_feature_profile.h
@@ -177,6 +177,8 @@ protected:
public:
Ref<EditorFeatureProfile> get_current_profile();
+ String get_current_profile_name() const;
+ void set_current_profile(const String &p_profile_name, bool p_validate_profile);
void notify_changed();
static EditorFeatureProfileManager *get_singleton() { return singleton; }
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index b71c66d776..6f3b6ecdb0 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -544,7 +544,7 @@ bool EditorFileSystem::_scan_import_support(Vector<String> reimports) {
}
for (int i = 0; i < reimports.size(); i++) {
- HashMap<String, int>::Iterator E = import_support_test.find(reimports[i].get_extension());
+ HashMap<String, int>::Iterator E = import_support_test.find(reimports[i].get_extension().to_lower());
if (E) {
import_support_tested.write[E->value] = true;
}
@@ -1635,6 +1635,7 @@ void EditorFileSystem::_queue_update_script_class(const String &p_path) {
}
void EditorFileSystem::update_file(const String &p_file) {
+ ERR_FAIL_COND(p_file.is_empty());
EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 61e94388ba..c9a95df34e 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -45,37 +45,43 @@
#define CONTRIBUTE_URL vformat("%s/contributing/documentation/updating_the_class_reference.html", VERSION_DOCS_URL)
+#ifdef MODULE_MONO_ENABLED
+// Sync with the types mentioned in https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/c_sharp_differences.html
+const Vector<String> classes_with_csharp_differences = {
+ "@GlobalScope",
+ "String",
+ "NodePath",
+ "Signal",
+ "Callable",
+ "RID",
+ "Basis",
+ "Transform2D",
+ "Transform3D",
+ "Rect2",
+ "Rect2i",
+ "AABB",
+ "Quaternion",
+ "Projection",
+ "Color",
+ "Array",
+ "Dictionary",
+ "PackedByteArray",
+ "PackedColorArray",
+ "PackedFloat32Array",
+ "PackedFloat64Array",
+ "PackedInt32Array",
+ "PackedInt64Array",
+ "PackedStringArray",
+ "PackedVector2Array",
+ "PackedVector3Array",
+ "Variant",
+};
+#endif
+
// TODO: this is sometimes used directly as doc->something, other times as EditorHelp::get_doc_data(), which is thread-safe.
// Might this be a problem?
DocTools *EditorHelp::doc = nullptr;
-class DocCache : public Resource {
- GDCLASS(DocCache, Resource);
- RES_BASE_EXTENSION("doc_cache");
-
- String version_hash;
- Array classes;
-
-protected:
- static void _bind_methods() {
- ClassDB::bind_method(D_METHOD("set_version_hash", "version_hash"), &DocCache::set_version_hash);
- ClassDB::bind_method(D_METHOD("get_version_hash"), &DocCache::get_version_hash);
-
- ClassDB::bind_method(D_METHOD("set_classes", "classes"), &DocCache::set_classes);
- ClassDB::bind_method(D_METHOD("get_classes"), &DocCache::get_classes);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "version_hash"), "set_version_hash", "get_version_hash");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "classes"), "set_classes", "get_classes");
- }
-
-public:
- String get_version_hash() const { return version_hash; }
- void set_version_hash(const String &p_version_hash) { version_hash = p_version_hash; }
-
- Array get_classes() const { return classes; }
- void set_classes(const Array &p_classes) { classes = p_classes; }
-};
-
static bool _attempt_doc_load(const String &p_class) {
// Docgen always happens in the outer-most class: it also generates docs for inner classes.
String outer_class = p_class.get_slice(".", 0);
@@ -308,7 +314,7 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum, bool p_is
bool can_ref = !p_type.contains("*") || is_enum_type;
String link_t = p_type; // For links in metadata
- String display_t = link_t; // For display purposes
+ String display_t; // For display purposes.
if (is_enum_type) {
link_t = p_enum; // The link for enums is always the full enum description
display_t = _contextualize_class_specifier(p_enum, edited_class);
@@ -888,10 +894,26 @@ void EditorHelp::_update_doc() {
class_desc->append_text(TTR("There is currently no description for this class. Please help us by [color=$color][url=$url]contributing one[/url][/color]!").replace("$url", CONTRIBUTE_URL).replace("$color", link_color_text));
}
+ class_desc->add_newline();
+ class_desc->add_newline();
+ }
+
+#ifdef MODULE_MONO_ENABLED
+ if (classes_with_csharp_differences.has(cd.name)) {
+ const String &csharp_differences_url = vformat("%s/tutorials/scripting/c_sharp/c_sharp_differences.html", VERSION_DOCS_URL);
+
+ class_desc->push_color(theme_cache.text_color);
+ _push_normal_font();
+ class_desc->push_indent(1);
+ _add_text("[b]" + TTR("Note:") + "[/b] " + vformat(TTR("There are notable differences when using this API with C#. See [url=%s]C# API differences to GDScript[/url] for more information."), csharp_differences_url));
+ class_desc->pop();
+ _pop_normal_font();
class_desc->pop();
+
class_desc->add_newline();
class_desc->add_newline();
}
+#endif
// Online tutorials
if (cd.tutorials.size()) {
@@ -1367,7 +1389,7 @@ void EditorHelp::_update_doc() {
class_desc->add_newline();
// Enum description.
- if (e != "@unnamed_enums" && cd.enums.has(e)) {
+ if (e != "@unnamed_enums" && cd.enums.has(e) && !cd.enums[e].strip_edges().is_empty()) {
class_desc->push_color(theme_cache.text_color);
_push_normal_font();
class_desc->push_indent(1);
@@ -1906,7 +1928,7 @@ void EditorHelp::_help_callback(const String &p_topic) {
}
}
-static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control *p_owner_node) {
+static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control *p_owner_node, const String &p_class = "") {
DocTools *doc = EditorHelp::get_doc_data();
String base_path;
@@ -2107,21 +2129,28 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control
p_rt->pop(); // font
pos = brk_end + 1;
+ } else if (tag == p_class) {
+ // Use a bold font when class reference tags are in their own page.
+ p_rt->push_font(doc_bold_font);
+ p_rt->add_text(tag);
+ p_rt->pop();
+
+ pos = brk_end + 1;
+
} else if (doc->class_list.has(tag)) {
- // Class reference tag such as [Node2D] or [SceneTree].
- // Use monospace font to make clickable references
- // easier to distinguish from inline code and other text.
+ // Use a monospace font for class reference tags such as [Node2D] or [SceneTree].
+
p_rt->push_font(doc_code_font);
p_rt->push_font_size(doc_code_font_size);
-
p_rt->push_color(type_color);
p_rt->push_meta("#" + tag);
p_rt->add_text(tag);
+
p_rt->pop();
p_rt->pop();
+ p_rt->pop(); // Font size
+ p_rt->pop(); // Font
- p_rt->pop(); // font size
- p_rt->pop(); // font
pos = brk_end + 1;
} else if (tag == "b") {
@@ -2252,7 +2281,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control
}
void EditorHelp::_add_text(const String &p_bbcode) {
- _add_text_to_rt(p_bbcode, class_desc, this);
+ _add_text_to_rt(p_bbcode, class_desc, this, edited_class);
}
Thread EditorHelp::thread;
@@ -2264,21 +2293,23 @@ void EditorHelp::_wait_for_thread() {
}
String EditorHelp::get_cache_full_path() {
- return EditorPaths::get_singleton()->get_cache_dir().path_join("editor.doc_cache");
+ return EditorPaths::get_singleton()->get_cache_dir().path_join("editor_doc_cache.res");
}
static bool first_attempt = true;
static String _compute_doc_version_hash() {
- return vformat("%d/%d/%s", ClassDB::get_api_hash(ClassDB::API_CORE), ClassDB::get_api_hash(ClassDB::API_EDITOR), _doc_data_hash);
+ uint32_t version_hash = Engine::get_singleton()->get_version_info().hash();
+ return vformat("%d/%d/%d/%s", version_hash, ClassDB::get_api_hash(ClassDB::API_CORE), ClassDB::get_api_hash(ClassDB::API_EDITOR), _doc_data_hash);
}
void EditorHelp::_load_doc_thread(void *p_udata) {
DEV_ASSERT(first_attempt);
- Ref<DocCache> cache_res = ResourceLoader::load(get_cache_full_path());
- if (cache_res.is_valid() && cache_res->get_version_hash() == _compute_doc_version_hash()) {
- for (int i = 0; i < cache_res->get_classes().size(); i++) {
- doc->add_doc(DocData::ClassDoc::from_dict(cache_res->get_classes()[i]));
+ Ref<Resource> cache_res = ResourceLoader::load(get_cache_full_path());
+ if (cache_res.is_valid() && cache_res->get_meta("version_hash", "") == _compute_doc_version_hash()) {
+ Array classes = cache_res->get_meta("classes", Array());
+ for (int i = 0; i < classes.size(); i++) {
+ doc->add_doc(DocData::ClassDoc::from_dict(classes[i]));
}
} else {
// We have to go back to the main thread to start from scratch.
@@ -2292,14 +2323,14 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {
compdoc.load_compressed(_doc_data_compressed, _doc_data_compressed_size, _doc_data_uncompressed_size);
doc->merge_from(compdoc); // Ensure all is up to date.
- Ref<DocCache> cache_res;
+ Ref<Resource> cache_res;
cache_res.instantiate();
- cache_res->set_version_hash(_compute_doc_version_hash());
+ cache_res->set_meta("version_hash", _compute_doc_version_hash());
Array classes;
for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) {
classes.push_back(DocData::ClassDoc::to_dict(E.value));
}
- cache_res->set_classes(classes);
+ cache_res->set_meta("classes", classes);
Error err = ResourceSaver::save(cache_res, get_cache_full_path(), ResourceSaver::FLAG_COMPRESS);
if (err) {
ERR_PRINT("Cannot save editor help cache (" + get_cache_full_path() + ").");
@@ -2309,9 +2340,6 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {
static bool doc_gen_use_threads = true;
void EditorHelp::generate_doc(bool p_use_cache) {
- // Temporarily disable use of cache for pre-RC stabilization.
- p_use_cache = false;
-
OS::get_singleton()->benchmark_begin_measure("EditorHelp::generate_doc");
if (doc_gen_use_threads) {
// In case not the first attempt.
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index e3514b4691..d95b1de365 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -45,6 +45,7 @@
#include "scene/gui/texture_rect.h"
#include "scene/property_utils.h"
#include "scene/resources/packed_scene.h"
+#include "scene/resources/style_box_flat.h"
bool EditorInspector::_property_path_matches(const String &p_property_path, const String &p_filter, EditorPropertyNameProcessor::Style p_style) {
if (p_property_path.findn(p_filter) != -1) {
@@ -3184,10 +3185,11 @@ void EditorInspector::update_tree() {
if (val.enumeration == enum_name && !val.name.ends_with("_MAX")) {
const String enum_value = EditorPropertyNameProcessor::get_singleton()->process_name(val.name, EditorPropertyNameProcessor::STYLE_CAPITALIZED);
// Prettify the enum value display, so that "<ENUM NAME>_<VALUE>" becomes "Value".
+ String desc = DTR(val.description).trim_prefix("\n");
doc_info.description += vformat(
"\n[b]%s:[/b] %s",
enum_value.trim_prefix(EditorPropertyNameProcessor::get_singleton()->process_name(enum_name, EditorPropertyNameProcessor::STYLE_CAPITALIZED) + " "),
- DTR(val.description).trim_prefix("\n"));
+ desc.is_empty() ? ("[i]" + TTR("No description.") + "[/i]") : desc);
}
}
}
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index a5737b7dc6..9a4c4f7f99 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -44,6 +44,7 @@ class OptionButton;
class PanelContainer;
class PopupMenu;
class SpinBox;
+class StyleBoxFlat;
class TextureRect;
class EditorPropertyRevert {
diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp
index d9d9dc01c0..8d63082f31 100644
--- a/editor/editor_interface.cpp
+++ b/editor/editor_interface.cpp
@@ -31,6 +31,7 @@
#include "editor_interface.h"
#include "editor/editor_command_palette.h"
+#include "editor/editor_feature_profile.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_resource_preview.h"
@@ -239,6 +240,14 @@ void EditorInterface::popup_dialog_centered_clamped(Window *p_dialog, const Size
p_dialog->popup_exclusive_centered_clamped(EditorNode::get_singleton(), p_size, p_fallback_ratio);
}
+String EditorInterface::get_current_feature_profile() const {
+ return EditorFeatureProfileManager::get_singleton()->get_current_profile_name();
+}
+
+void EditorInterface::set_current_feature_profile(const String &p_profile_name) {
+ EditorFeatureProfileManager::get_singleton()->set_current_profile(p_profile_name, true);
+}
+
// Editor docks.
FileSystemDock *EditorInterface::get_file_system_dock() const {
@@ -337,6 +346,10 @@ void EditorInterface::mark_scene_as_unsaved() {
EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(EditorNode::get_editor_data().get_current_edited_scene_history_id());
}
+void EditorInterface::save_all_scenes() {
+ EditorNode::get_singleton()->save_all_scenes();
+}
+
// Scene playback.
void EditorInterface::play_main_scene() {
@@ -407,6 +420,9 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("popup_dialog_centered_ratio", "dialog", "ratio"), &EditorInterface::popup_dialog_centered_ratio, DEFVAL(0.8));
ClassDB::bind_method(D_METHOD("popup_dialog_centered_clamped", "dialog", "minsize", "fallback_ratio"), &EditorInterface::popup_dialog_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75));
+ ClassDB::bind_method(D_METHOD("get_current_feature_profile"), &EditorInterface::get_current_feature_profile);
+ ClassDB::bind_method(D_METHOD("set_current_feature_profile", "profile_name"), &EditorInterface::set_current_feature_profile);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distraction_free_mode"), "set_distraction_free_mode", "is_distraction_free_mode_enabled");
// Editor docks.
@@ -434,6 +450,7 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene);
ClassDB::bind_method(D_METHOD("save_scene_as", "path", "with_preview"), &EditorInterface::save_scene_as, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("save_all_scenes"), &EditorInterface::save_all_scenes);
ClassDB::bind_method(D_METHOD("mark_scene_as_unsaved"), &EditorInterface::mark_scene_as_unsaved);
diff --git a/editor/editor_interface.h b/editor/editor_interface.h
index f7e8cf8d4c..2ac1336202 100644
--- a/editor/editor_interface.h
+++ b/editor/editor_interface.h
@@ -104,6 +104,9 @@ public:
void popup_dialog_centered_ratio(Window *p_dialog, float p_ratio = 0.8);
void popup_dialog_centered_clamped(Window *p_dialog, const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75);
+ String get_current_feature_profile() const;
+ void set_current_feature_profile(const String &p_profile_name);
+
// Editor docks.
FileSystemDock *get_file_system_dock() const;
@@ -130,6 +133,7 @@ public:
Error save_scene();
void save_scene_as(const String &p_scene, bool p_with_preview = true);
void mark_scene_as_unsaved();
+ void save_all_scenes();
// Scene playback.
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 0fd9d64602..1bc9f00f08 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -338,13 +338,7 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
} else {
log->add_text(p_message.text);
}
-
- // Need to use pop() to exit out of the RichTextLabels current "push" stack.
- // We only "push" in the above switch when message type != STD and RICH, so only pop when that is the case.
- if (p_message.type != MSG_TYPE_STD && p_message.type != MSG_TYPE_STD_RICH) {
- log->pop();
- }
-
+ log->pop_all(); // Pop all unclosed tags.
log->add_newline();
if (p_replace_previous) {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 0c74468816..a8187c27b6 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -60,7 +60,9 @@
#include "scene/gui/tab_container.h"
#include "scene/main/window.h"
#include "scene/property_utils.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/packed_scene.h"
+#include "scene/resources/portable_compressed_texture.h"
#include "servers/display_server.h"
#include "servers/navigation_server_3d.h"
#include "servers/physics_server_2d.h"
@@ -1411,7 +1413,7 @@ void EditorNode::_dialog_display_load_error(String p_file, Error p_error) {
show_accept(vformat(TTR("Scene file '%s' appears to be invalid/corrupt."), p_file.get_file()), TTR("OK"));
} break;
case ERR_FILE_NOT_FOUND: {
- show_accept(vformat(TTR("Missing file '%s' or one its dependencies."), p_file.get_file()), TTR("OK"));
+ show_accept(vformat(TTR("Missing file '%s' or one of its dependencies."), p_file.get_file()), TTR("OK"));
} break;
default: {
show_accept(vformat(TTR("Error while loading file '%s'."), p_file.get_file()), TTR("OK"));
@@ -1982,6 +1984,9 @@ void EditorNode::_dialog_action(String p_file) {
if (scene_idx != -1) {
_discard_changes();
+ } else {
+ // Update the path of the edited scene to ensure later do/undo action history matches.
+ editor_data.set_scene_path(editor_data.get_edited_scene(), p_file);
}
}
@@ -2775,6 +2780,11 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_QUIT:
case RUN_PROJECT_MANAGER:
case RELOAD_CURRENT_PROJECT: {
+ if (p_confirmed && plugin_to_save) {
+ plugin_to_save->save_external_data();
+ p_confirmed = false;
+ }
+
if (!p_confirmed) {
bool save_each = EDITOR_GET("interface/editor/save_each_scene_on_quit");
if (_next_unsaved_scene(!save_each) == -1) {
@@ -2791,6 +2801,28 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
break;
}
+ plugin_to_save = nullptr;
+ for (int i = 0; i < editor_data.get_editor_plugin_count(); i++) {
+ const String unsaved_status = editor_data.get_editor_plugin(i)->get_unsaved_status();
+ if (!unsaved_status.is_empty()) {
+ if (p_option == RELOAD_CURRENT_PROJECT) {
+ save_confirmation->set_ok_button_text(TTR("Save & Reload"));
+ save_confirmation->set_text(unsaved_status);
+ } else {
+ save_confirmation->set_ok_button_text(TTR("Save & Quit"));
+ save_confirmation->set_text(unsaved_status);
+ }
+ save_confirmation->reset_size();
+ save_confirmation->popup_centered();
+ plugin_to_save = editor_data.get_editor_plugin(i);
+ break;
+ }
+ }
+
+ if (plugin_to_save) {
+ break;
+ }
+
_discard_changes();
break;
}
@@ -3029,13 +3061,21 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) {
if (!editor_data.get_edited_scene_root(i)) {
continue;
}
+
+ String scene_filename = editor_data.get_edited_scene_root(i)->get_scene_file_path();
+ if (p_valid_filename && scene_filename.is_empty()) {
+ continue;
+ }
+
bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(i));
if (unsaved) {
- String scene_filename = editor_data.get_edited_scene_root(i)->get_scene_file_path();
- if (p_valid_filename && scene_filename.is_empty()) {
- continue;
- }
return i;
+ } else {
+ for (int j = 0; j < editor_data.get_editor_plugin_count(); j++) {
+ if (!editor_data.get_editor_plugin(j)->get_unsaved_status(scene_filename).is_empty()) {
+ return i;
+ }
+ }
}
}
return -1;
@@ -3190,7 +3230,7 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
if (icon.is_valid()) {
tb->set_icon(icon);
// Make sure the control is updated if the icon is reimported.
- icon->connect("changed", callable_mp((Control *)tb, &Control::update_minimum_size));
+ icon->connect_changed(callable_mp((Control *)tb, &Control::update_minimum_size));
} else if (singleton->gui_base->has_theme_icon(p_editor->get_name(), SNAME("EditorIcons"))) {
tb->set_icon(singleton->gui_base->get_theme_icon(p_editor->get_name(), SNAME("EditorIcons")));
}
@@ -3326,6 +3366,11 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
return;
}
+ String plugin_version;
+ if (cf->has_section_key("plugin", "version")) {
+ plugin_version = cf->get_value("plugin", "version");
+ }
+
if (!cf->has_section_key("plugin", "script")) {
show_warning(vformat(TTR("Unable to find script field for addon plugin at: '%s'."), addon_path));
return;
@@ -3371,6 +3416,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
EditorPlugin *ep = memnew(EditorPlugin);
ep->set_script(scr);
+ ep->set_plugin_version(plugin_version);
addon_name_to_plugin[addon_path] = ep;
add_editor_plugin(ep, p_config_changed);
@@ -4234,7 +4280,7 @@ void EditorNode::_pick_main_scene_custom_action(const String &p_custom_action_na
}
}
-Ref<Texture2D> EditorNode::_get_class_or_script_icon(const String &p_class, const Ref<Script> &p_script, const String &p_fallback) {
+Ref<Texture2D> EditorNode::_get_class_or_script_icon(const String &p_class, const Ref<Script> &p_script, const String &p_fallback, bool p_fallback_script_to_theme) {
ERR_FAIL_COND_V_MSG(p_class.is_empty(), nullptr, "Class name cannot be empty.");
EditorData &ed = EditorNode::get_editor_data();
@@ -4244,6 +4290,16 @@ Ref<Texture2D> EditorNode::_get_class_or_script_icon(const String &p_class, cons
if (script_icon.is_valid()) {
return script_icon;
}
+
+ if (p_fallback_script_to_theme) {
+ // Look for the base type in the editor theme.
+ // This is only relevant for built-in classes.
+ String base_type;
+ p_script->get_language()->get_global_class_name(p_script->get_path(), &base_type);
+ if (gui_base && gui_base->has_theme_icon(base_type, SNAME("EditorIcons"))) {
+ return gui_base->get_theme_icon(base_type, SNAME("EditorIcons"));
+ }
+ }
}
// Script was not valid or didn't yield any useful values, try the class name
@@ -4296,7 +4352,7 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
scr = EditorNode::get_editor_data().script_class_load_script(p_class);
}
- return _get_class_or_script_icon(p_class, scr, p_fallback);
+ return _get_class_or_script_icon(p_class, scr, p_fallback, true);
}
bool EditorNode::is_object_of_custom_type(const Object *p_object, const StringName &p_class) {
@@ -4376,6 +4432,9 @@ String EditorNode::_get_system_info() const {
godot_version += " " + hash;
}
+#ifdef LINUXBSD_ENABLED
+ const String display_server = OS::get_singleton()->get_environment("XDG_SESSION_TYPE").capitalize().replace(" ", ""); // `replace` is necessary, because `capitalize` introduces a whitespace between "x" and "11".
+#endif // LINUXBSD_ENABLED
String driver_name = GLOBAL_GET("rendering/rendering_device/driver");
String rendering_method = GLOBAL_GET("rendering/renderer/rendering_method");
@@ -4407,17 +4466,18 @@ String EditorNode::_get_system_info() const {
const int processor_count = OS::get_singleton()->get_processor_count();
// Prettify
- if (driver_name == "vulkan") {
- driver_name = "Vulkan";
- } else if (driver_name == "opengl3") {
- driver_name = "GLES3";
- }
if (rendering_method == "forward_plus") {
rendering_method = "Forward+";
} else if (rendering_method == "mobile") {
rendering_method = "Mobile";
} else if (rendering_method == "gl_compatibility") {
rendering_method = "Compatibility";
+ driver_name = GLOBAL_GET("rendering/gl_compatibility/driver");
+ }
+ if (driver_name == "vulkan") {
+ driver_name = "Vulkan";
+ } else if (driver_name == "opengl3") {
+ driver_name = "GLES3";
}
// Join info.
@@ -4428,6 +4488,11 @@ String EditorNode::_get_system_info() const {
} else {
info.push_back(distribution_name);
}
+#ifdef LINUXBSD_ENABLED
+ if (!display_server.is_empty()) {
+ info.push_back(display_server);
+ }
+#endif // LINUXBSD_ENABLED
info.push_back(vformat("%s (%s)", driver_name, rendering_method));
String graphics;
@@ -5275,21 +5340,29 @@ void EditorNode::_save_central_editor_layout_to_config(Ref<ConfigFile> p_config_
void EditorNode::_load_central_editor_layout_from_config(Ref<ConfigFile> p_config_file) {
// Bottom panel.
- if (p_config_file->has_section_key(EDITOR_NODE_CONFIG_SECTION, "center_split_offset")) {
- int center_split_offset = p_config_file->get_value(EDITOR_NODE_CONFIG_SECTION, "center_split_offset");
- center_split->set_split_offset(center_split_offset);
- }
-
+ bool has_active_tab = false;
if (p_config_file->has_section_key(EDITOR_NODE_CONFIG_SECTION, "selected_bottom_panel_item")) {
int selected_bottom_panel_item_idx = p_config_file->get_value(EDITOR_NODE_CONFIG_SECTION, "selected_bottom_panel_item");
if (selected_bottom_panel_item_idx >= 0 && selected_bottom_panel_item_idx < bottom_panel_items.size()) {
// Make sure we don't try to open contextual editors which are not enabled in the current context.
if (bottom_panel_items[selected_bottom_panel_item_idx].button->is_visible()) {
_bottom_panel_switch(true, selected_bottom_panel_item_idx);
+ has_active_tab = true;
}
}
}
+ if (p_config_file->has_section_key(EDITOR_NODE_CONFIG_SECTION, "center_split_offset")) {
+ int center_split_offset = p_config_file->get_value(EDITOR_NODE_CONFIG_SECTION, "center_split_offset");
+ center_split->set_split_offset(center_split_offset);
+
+ // If there is no active tab we need to collapse the panel.
+ if (!has_active_tab) {
+ bottom_panel_items[0].control->show(); // _bottom_panel_switch() can collapse only visible tabs.
+ _bottom_panel_switch(false, 0);
+ }
+ }
+
// Debugger tab.
if (p_config_file->has_section_key(EDITOR_NODE_CONFIG_SECTION, "selected_default_debugger_tab_idx")) {
@@ -5537,19 +5610,36 @@ void EditorNode::_scene_tab_closed(int p_tab, int p_option) {
return;
}
- bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(p_tab));
- if (unsaved) {
+ String scene_filename = scene->get_scene_file_path();
+ String unsaved_message;
+
+ if (EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(p_tab))) {
+ if (scene_filename.is_empty()) {
+ unsaved_message = TTR("This scene was never saved.");
+ } else {
+ unsaved_message = vformat(TTR("Scene \"%s\" has unsaved changes."), scene_filename);
+ }
+ } else {
+ // Check if any plugin has unsaved changes in that scene.
+ for (int i = 0; i < editor_data.get_editor_plugin_count(); i++) {
+ unsaved_message = editor_data.get_editor_plugin(i)->get_unsaved_status(scene_filename);
+ if (!unsaved_message.is_empty()) {
+ break;
+ }
+ }
+ }
+
+ if (!unsaved_message.is_empty()) {
if (get_current_tab() != p_tab) {
set_current_scene(p_tab);
}
- String scene_filename = scene->get_scene_file_path();
if (current_menu_option == RELOAD_CURRENT_PROJECT) {
save_confirmation->set_ok_button_text(TTR("Save & Reload"));
- save_confirmation->set_text(vformat(TTR("Save changes to '%s' before reloading?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
+ save_confirmation->set_text(unsaved_message + "\n\n" + TTR("Save before reloading?"));
} else {
save_confirmation->set_ok_button_text(TTR("Save & Close"));
- save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
+ save_confirmation->set_text(unsaved_message + "\n\n" + TTR("Save before closing?"));
}
save_confirmation->reset_size();
save_confirmation->popup_centered();
@@ -6732,7 +6822,8 @@ EditorNode::EditorNode() {
// No scripting by default if in editor.
ScriptServer::set_scripting_enabled(false);
- EditorHelp::generate_doc(); // Before any editor classes are created.
+ EditorSettings::ensure_class_registered();
+ EditorHelp::generate_doc();
SceneState::set_disable_placeholders(true);
ResourceLoader::clear_translation_remaps(); // Using no remaps if in editor.
ResourceLoader::clear_path_remaps();
@@ -7119,7 +7210,7 @@ EditorNode::EditorNode() {
dock_select->set_v_size_flags(Control::SIZE_EXPAND_FILL);
dock_vb->add_child(dock_select);
- if (!SceneTree::get_singleton()->get_root()->is_embedding_subwindows() && EDITOR_GET("interface/multi_window/enable")) {
+ if (!SceneTree::get_singleton()->get_root()->is_embedding_subwindows() && !EDITOR_GET("interface/editor/single_window_mode") && EDITOR_GET("interface/multi_window/enable")) {
dock_float = memnew(Button);
dock_float->set_icon(theme->get_icon("MakeFloating", "EditorIcons"));
dock_float->set_text(TTR("Make Floating"));
@@ -7747,6 +7838,7 @@ EditorNode::EditorNode() {
log = memnew(EditorLog);
Button *output_button = add_bottom_panel_item(TTR("Output"), log);
+ output_button->set_theme_type_variation("BottomPanelButton");
log->set_tool_button(output_button);
center_split->connect("resized", callable_mp(this, &EditorNode::_vp_resized));
@@ -8109,6 +8201,9 @@ EditorNode::~EditorNode() {
memdelete(progress_hb);
EditorSettings::destroy();
+
+ GDExtensionEditorPlugins::editor_node_add_plugin = nullptr;
+ GDExtensionEditorPlugins::editor_node_remove_plugin = nullptr;
}
/*
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 65f85a76c9..86b4847e5b 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -382,6 +382,7 @@ private:
AcceptDialog *save_accept = nullptr;
EditorAbout *about = nullptr;
AcceptDialog *warning = nullptr;
+ EditorPlugin *plugin_to_save = nullptr;
int overridden_default_layout = -1;
Ref<ConfigFile> default_layout;
@@ -687,7 +688,7 @@ private:
void _feature_profile_changed();
bool _is_class_editor_disabled_by_feature_profile(const StringName &p_class);
- Ref<Texture2D> _get_class_or_script_icon(const String &p_class, const Ref<Script> &p_script, const String &p_fallback = "Object");
+ Ref<Texture2D> _get_class_or_script_icon(const String &p_class, const Ref<Script> &p_script, const String &p_fallback = "Object", bool p_fallback_script_to_theme = false);
void _pick_main_scene_custom_action(const String &p_custom_action_name);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 4232eacd76..2d4c07b263 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -51,6 +51,7 @@
#include "editor/scene_tree_dock.h"
#include "scene/3d/camera_3d.h"
#include "scene/gui/popup_menu.h"
+#include "scene/resources/image_texture.h"
#include "servers/rendering_server.h"
void EditorPlugin::add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon) {
@@ -306,6 +307,14 @@ const Ref<Texture2D> EditorPlugin::get_icon() const {
return icon;
}
+String EditorPlugin::get_plugin_version() const {
+ return plugin_version;
+}
+
+void EditorPlugin::set_plugin_version(const String &p_version) {
+ plugin_version = p_version;
+}
+
bool EditorPlugin::has_main_screen() const {
bool success = false;
GDVIRTUAL_CALL(_has_main_screen, success);
@@ -340,7 +349,12 @@ void EditorPlugin::clear() {
GDVIRTUAL_CALL(_clear);
}
-// if editor references external resources/scenes, save them
+String EditorPlugin::get_unsaved_status(const String &p_for_scene) const {
+ String ret;
+ GDVIRTUAL_CALL(_get_unsaved_status, p_for_scene, ret);
+ return ret;
+}
+
void EditorPlugin::save_external_data() {
GDVIRTUAL_CALL(_save_external_data);
}
@@ -577,6 +591,7 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_script_create_dialog"), &EditorPlugin::get_script_create_dialog);
ClassDB::bind_method(D_METHOD("add_debugger_plugin", "script"), &EditorPlugin::add_debugger_plugin);
ClassDB::bind_method(D_METHOD("remove_debugger_plugin", "script"), &EditorPlugin::remove_debugger_plugin);
+ ClassDB::bind_method(D_METHOD("get_plugin_version"), &EditorPlugin::get_plugin_version);
GDVIRTUAL_BIND(_forward_canvas_gui_input, "event");
GDVIRTUAL_BIND(_forward_canvas_draw_over_viewport, "viewport_control");
@@ -593,6 +608,7 @@ void EditorPlugin::_bind_methods() {
GDVIRTUAL_BIND(_get_state);
GDVIRTUAL_BIND(_set_state, "state");
GDVIRTUAL_BIND(_clear);
+ GDVIRTUAL_BIND(_get_unsaved_status, "for_scene");
GDVIRTUAL_BIND(_save_external_data);
GDVIRTUAL_BIND(_apply_changes);
GDVIRTUAL_BIND(_get_breakpoints);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 69789a4d4f..7dcf62144d 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -61,6 +61,7 @@ class EditorPlugin : public Node {
bool force_draw_over_forwarding_enabled = false;
String last_main_screen_name;
+ String plugin_version;
void _editor_project_settings_changed();
@@ -88,6 +89,7 @@ protected:
GDVIRTUAL0RC(Dictionary, _get_state)
GDVIRTUAL1(_set_state, Dictionary)
GDVIRTUAL0(_clear)
+ GDVIRTUAL1RC(String, _get_unsaved_status, String)
GDVIRTUAL0(_save_external_data)
GDVIRTUAL0(_apply_changes)
GDVIRTUAL0RC(Vector<String>, _get_breakpoints)
@@ -167,6 +169,8 @@ public:
virtual String get_name() const;
virtual const Ref<Texture2D> get_icon() const;
+ virtual String get_plugin_version() const;
+ virtual void set_plugin_version(const String &p_version);
virtual bool has_main_screen() const;
virtual void make_visible(bool p_visible);
virtual void selected_notify() {} //notify that it was raised by the user, not the editor
@@ -175,6 +179,7 @@ public:
virtual Dictionary get_state() const; //save editor state so it can't be reloaded when reloading scene
virtual void set_state(const Dictionary &p_state); //restore editor state (likely was saved with the scene)
virtual void clear(); // clear any temporary data in the editor, reset it (likely new scene or load another scene)
+ virtual String get_unsaved_status(const String &p_for_scene = "") const;
virtual void save_external_data(); // if editor references external resources/scenes, save them
virtual void apply_changes(); // if changes are pending in editor, apply them
virtual void get_breakpoints(List<String> *p_breakpoints);
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index 1e582992d1..7f57619ac8 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -101,9 +101,18 @@ void EditorPluginSettings::update_plugins() {
String description = cf->get_value("plugin", "description");
String scr = cf->get_value("plugin", "script");
+ const PackedInt32Array boundaries = TS->string_get_word_breaks(description, "", 80);
+ String wrapped_description;
+
+ for (int j = 0; j < boundaries.size(); j += 2) {
+ const int start = boundaries[j];
+ const int end = boundaries[j + 1];
+ wrapped_description += "\n" + description.substr(start, end - start + 1).rstrip("\n");
+ }
+
TreeItem *item = plugin_list->create_item(root);
item->set_text(0, name);
- item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + scr + "\n" + TTR("Description:") + " " + description);
+ item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + scr + "\n" + TTR("Description:") + " " + wrapped_description);
item->set_metadata(0, path);
item->set_text(1, version);
item->set_metadata(1, scr);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 04a019a407..77d6ec9ab2 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -621,7 +621,7 @@ void EditorPropertyClassName::update_property() {
}
void EditorPropertyClassName::_property_selected() {
- dialog->popup_create(true);
+ dialog->popup_create(true, true, get_edited_property_value(), get_edited_property());
}
void EditorPropertyClassName::_dialog_created() {
@@ -772,7 +772,7 @@ void EditorPropertyFlags::setup(const Vector<String> &p_options) {
const int flag_index = flags.size(); // Index of the next element (added by the code below).
// Value for a flag can be explicitly overridden.
- Vector<String> text_split = p_options[i].split(":");
+ Vector<String> text_split = option.split(":");
if (text_split.size() != 1) {
current_val = text_split[1].to_int();
} else {
@@ -782,7 +782,7 @@ void EditorPropertyFlags::setup(const Vector<String> &p_options) {
// Create a CheckBox for the current flag.
CheckBox *cb = memnew(CheckBox);
- cb->set_text(option);
+ cb->set_text(text_split[0]);
cb->set_clip_text(true);
cb->connect("pressed", callable_mp(this, &EditorPropertyFlags::_flag_toggled).bind(flag_index));
add_focusable(cb);
@@ -3622,7 +3622,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
return editor;
} else if (p_hint == PROPERTY_HINT_TYPE_STRING) {
EditorPropertyClassName *editor = memnew(EditorPropertyClassName);
- editor->setup("Object", p_hint_text);
+ editor->setup(p_hint_text, p_hint_text);
return editor;
} else if (p_hint == PROPERTY_HINT_LOCALE_ID) {
EditorPropertyLocale *editor = memnew(EditorPropertyLocale);
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 8920ad10dc..ea7e1549f5 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -41,6 +41,10 @@
#include "editor/plugins/editor_resource_conversion_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/scene_tree_dock.h"
+#include "scene/gui/button.h"
+#include "scene/gui/texture_rect.h"
+#include "scene/resources/gradient_texture.h"
+#include "scene/resources/image_texture.h"
void EditorResourcePicker::_update_resource() {
String resource_path;
@@ -218,7 +222,7 @@ void EditorResourcePicker::_update_menu_items() {
edited_resource->get_property_list(&property_list);
bool has_subresources = false;
for (PropertyInfo &p : property_list) {
- if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script")) {
+ if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script") && ((Object *)edited_resource->get(p.name) != nullptr)) {
has_subresources = true;
break;
}
@@ -350,7 +354,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
}
Ref<Resource> unique_resource = edited_resource->duplicate();
- ERR_FAIL_COND(unique_resource.is_null());
+ ERR_FAIL_COND(unique_resource.is_null()); // duplicate() may fail.
edited_resource = unique_resource;
emit_signal(SNAME("resource_changed"), edited_resource);
@@ -362,12 +366,30 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
return;
}
- Ref<Resource> unique_resource = edited_resource->duplicate(true);
- ERR_FAIL_COND(unique_resource.is_null());
+ if (!duplicate_resources_dialog) {
+ duplicate_resources_dialog = memnew(ConfirmationDialog);
+ add_child(duplicate_resources_dialog);
+ duplicate_resources_dialog->set_title(TTR("Make Unique (Recursive)"));
+ duplicate_resources_dialog->connect("confirmed", callable_mp(this, &EditorResourcePicker::_duplicate_selected_resources));
- edited_resource = unique_resource;
- emit_signal(SNAME("resource_changed"), edited_resource);
- _update_resource();
+ VBoxContainer *vb = memnew(VBoxContainer);
+ duplicate_resources_dialog->add_child(vb);
+
+ Label *label = memnew(Label(TTR("Select resources to make unique:")));
+ vb->add_child(label);
+
+ duplicate_resources_tree = memnew(Tree);
+ vb->add_child(duplicate_resources_tree);
+ duplicate_resources_tree->set_columns(2);
+ duplicate_resources_tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ }
+
+ duplicate_resources_tree->clear();
+ TreeItem *root = duplicate_resources_tree->create_item();
+ _gather_resources_to_duplicate(edited_resource, root);
+
+ duplicate_resources_dialog->reset_size();
+ duplicate_resources_dialog->popup_centered(Vector2(500, 400) * EDSCALE);
} break;
case OBJ_MENU_SAVE: {
@@ -808,6 +830,11 @@ void EditorResourcePicker::_notification(int p_what) {
}
}
+void EditorResourcePicker::set_assign_button_min_size(const Size2i &p_size) {
+ assign_button_min_size = p_size;
+ assign_button->set_custom_minimum_size(assign_button_min_size);
+}
+
void EditorResourcePicker::set_base_type(const String &p_base_type) {
base_type = p_base_type;
@@ -920,6 +947,89 @@ void EditorResourcePicker::_ensure_resource_menu() {
edit_menu->connect("popup_hide", callable_mp((BaseButton *)edit_button, &BaseButton::set_pressed).bind(false));
}
+void EditorResourcePicker::_gather_resources_to_duplicate(const Ref<Resource> p_resource, TreeItem *p_item, const String &p_property_name) const {
+ p_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+
+ String res_name = p_resource->get_name();
+ if (res_name.is_empty() && !p_resource->is_built_in()) {
+ res_name = p_resource->get_path().get_file();
+ }
+
+ if (res_name.is_empty()) {
+ p_item->set_text(0, p_resource->get_class());
+ } else {
+ p_item->set_text(0, vformat("%s (%s)", p_resource->get_class(), res_name));
+ }
+
+ p_item->set_icon(0, EditorNode::get_singleton()->get_object_icon(p_resource.ptr()));
+ p_item->set_editable(0, true);
+
+ Array meta;
+ meta.append(p_resource);
+ p_item->set_metadata(0, meta);
+
+ if (!p_property_name.is_empty()) {
+ p_item->set_text(1, p_property_name);
+ }
+
+ static Vector<String> unique_exceptions = { "Image", "Shader", "Mesh", "FontFile" };
+ if (!unique_exceptions.has(p_resource->get_class())) {
+ // Automatically select resource, unless it's something that shouldn't be duplicated.
+ p_item->set_checked(0, true);
+ }
+
+ List<PropertyInfo> plist;
+ p_resource->get_property_list(&plist);
+
+ for (const PropertyInfo &E : plist) {
+ if (!(E.usage & PROPERTY_USAGE_STORAGE) || E.type != Variant::OBJECT || E.hint != PROPERTY_HINT_RESOURCE_TYPE) {
+ continue;
+ }
+
+ Ref<Resource> res = p_resource->get(E.name);
+ if (res.is_null()) {
+ continue;
+ }
+
+ TreeItem *child = p_item->create_child();
+ _gather_resources_to_duplicate(res, child, E.name);
+
+ meta = child->get_metadata(0);
+ // Remember property name.
+ meta.append(E.name);
+
+ if ((E.usage & PROPERTY_USAGE_NEVER_DUPLICATE)) {
+ // The resource can't be duplicated, but make it appear on the list anyway.
+ child->set_checked(0, false);
+ child->set_editable(0, false);
+ }
+ }
+}
+
+void EditorResourcePicker::_duplicate_selected_resources() {
+ for (TreeItem *item = duplicate_resources_tree->get_root(); item; item = item->get_next_in_tree()) {
+ if (!item->is_checked(0)) {
+ continue;
+ }
+
+ Array meta = item->get_metadata(0);
+ Ref<Resource> res = meta[0];
+ Ref<Resource> unique_resource = res->duplicate();
+ ERR_FAIL_COND(unique_resource.is_null()); // duplicate() may fail.
+ meta[0] = unique_resource;
+
+ if (meta.size() == 1) { // Root.
+ edited_resource = unique_resource;
+ emit_signal(SNAME("resource_changed"), edited_resource);
+ _update_resource();
+ } else {
+ Array parent_meta = item->get_parent()->get_metadata(0);
+ Ref<Resource> parent = parent_meta[0];
+ parent->set(meta[1], unique_resource);
+ }
+ }
+}
+
EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) {
assign_button = memnew(Button);
assign_button->set_flat(true);
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
index a302e24957..856ef974d3 100644
--- a/editor/editor_resource_picker.h
+++ b/editor/editor_resource_picker.h
@@ -32,12 +32,15 @@
#define EDITOR_RESOURCE_PICKER_H
#include "scene/gui/box_container.h"
-#include "scene/gui/button.h"
-#include "scene/gui/popup_menu.h"
-#include "scene/gui/texture_rect.h"
+class Button;
+class ConfirmationDialog;
class EditorFileDialog;
class EditorQuickOpen;
+class PopupMenu;
+class TextureRect;
+class Tree;
+class TreeItem;
class EditorResourcePicker : public HBoxContainer {
GDCLASS(EditorResourcePicker, HBoxContainer);
@@ -56,6 +59,9 @@ class EditorResourcePicker : public HBoxContainer {
EditorFileDialog *file_dialog = nullptr;
EditorQuickOpen *quick_open = nullptr;
+ ConfirmationDialog *duplicate_resources_dialog = nullptr;
+ Tree *duplicate_resources_tree = nullptr;
+
Size2i assign_button_min_size = Size2i(1, 1);
enum MenuOption {
@@ -99,6 +105,8 @@ class EditorResourcePicker : public HBoxContainer {
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
void _ensure_resource_menu();
+ void _gather_resources_to_duplicate(const Ref<Resource> p_resource, TreeItem *p_item, const String &p_property_name = "") const;
+ void _duplicate_selected_resources();
protected:
virtual void _update_resource();
@@ -107,10 +115,7 @@ protected:
static void _bind_methods();
void _notification(int p_what);
- void set_assign_button_min_size(const Size2i &p_size) {
- assign_button_min_size = p_size;
- assign_button->set_custom_minimum_size(assign_button_min_size);
- }
+ void set_assign_button_min_size(const Size2i &p_size);
GDVIRTUAL1(_set_create_options, Object *)
GDVIRTUAL1R(bool, _handle_menu_selected, int)
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index f5da9da8e7..38a78babfb 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -40,6 +40,7 @@
#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "scene/resources/image_texture.h"
bool EditorResourcePreviewGenerator::handles(const String &p_type) const {
bool success = false;
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index 84835094bb..925039139b 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -35,7 +35,9 @@
#include "core/os/thread.h"
#include "core/templates/safe_refcount.h"
#include "scene/main/node.h"
-#include "scene/resources/texture.h"
+
+class ImageTexture;
+class Texture2D;
class EditorResourcePreviewGenerator : public RefCounted {
GDCLASS(EditorResourcePreviewGenerator, RefCounted);
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index beccf0f2ec..cf6a8f1368 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_settings.h"
#include "editor/export/editor_export.h"
#include "editor/export/editor_export_platform.h"
+#include "scene/resources/image_texture.h"
void EditorRunNative::_notification(int p_what) {
switch (p_what) {
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 8634b94858..285be7e7ae 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -597,7 +597,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Completion
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/completion/idle_parse_delay", 2.0, "0.1,10,0.01")
_initial_set("text_editor/completion/auto_brace_complete", true);
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/completion/code_complete_delay", 0.3, "0.01,5,0.01")
+ _initial_set("text_editor/completion/code_complete_enabled", true);
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/completion/code_complete_delay", 0.3, "0.01,5,0.01,or_greater")
_initial_set("text_editor/completion/put_callhint_tooltip_below_current_line", true);
_initial_set("text_editor/completion/complete_file_paths", true);
_initial_set("text_editor/completion/add_type_hints", false);
@@ -679,14 +680,15 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/2d/grid_color", Color(1.0, 1.0, 1.0, 0.07));
_initial_set("editors/2d/guides_color", Color(0.6, 0.0, 0.8));
_initial_set("editors/2d/smart_snapping_line_color", Color(0.9, 0.1, 0.1));
- _initial_set("editors/2d/bone_width", 5);
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/2d/bone_width", 5.0, "0.01,20,0.01,or_greater")
_initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.7));
_initial_set("editors/2d/bone_color2", Color(0.6, 0.6, 0.6, 0.7));
_initial_set("editors/2d/bone_selected_color", Color(0.9, 0.45, 0.45, 0.7));
_initial_set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.7));
_initial_set("editors/2d/bone_outline_color", Color(0.35, 0.35, 0.35, 0.5));
- _initial_set("editors/2d/bone_outline_size", 2);
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/2d/bone_outline_size", 2.0, "0.01,8,0.01,or_greater")
_initial_set("editors/2d/viewport_border_color", Color(0.4, 0.4, 1.0, 0.4));
+ _initial_set("editors/2d/use_integer_zoom_by_default", false);
// Panning
// Enum should be in sync with ControlScheme in ViewPanner.
@@ -707,7 +709,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Animation
_initial_set("editors/animation/autorename_animation_tracks", true);
- _initial_set("editors/animation/confirm_insert_track", true);
_initial_set("editors/animation/default_create_bezier_tracks", false);
_initial_set("editors/animation/default_create_reset_tracks", true);
_initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0));
@@ -877,6 +878,13 @@ EditorSettings *EditorSettings::get_singleton() {
return singleton.ptr();
}
+void EditorSettings::ensure_class_registered() {
+ ClassDB::APIType prev_api = ClassDB::get_current_api();
+ ClassDB::set_current_api(ClassDB::API_EDITOR);
+ GDREGISTER_CLASS(EditorSettings); // Otherwise it can't be unserialized.
+ ClassDB::set_current_api(prev_api);
+}
+
void EditorSettings::create() {
// IMPORTANT: create() *must* create a valid EditorSettings singleton,
// as the rest of the engine code will assume it. As such, it should never
@@ -887,7 +895,7 @@ void EditorSettings::create() {
return;
}
- GDREGISTER_CLASS(EditorSettings); // Otherwise it can't be unserialized.
+ ensure_class_registered();
String config_file_path;
Ref<ConfigFile> extra_config = memnew(ConfigFile);
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index 660a9501a2..55ac6c5a15 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -117,6 +117,7 @@ public:
static EditorSettings *get_singleton();
+ static void ensure_class_registered();
static void create();
void setup_language();
void setup_network();
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 2ff53dd9f1..3302b1dc41 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -36,6 +36,10 @@
#include "editor/editor_icons.gen.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "scene/resources/image_texture.h"
+#include "scene/resources/style_box_flat.h"
+#include "scene/resources/style_box_line.h"
+#include "scene/resources/style_box_texture.h"
#include "modules/modules_enabled.gen.h" // For svg.
#ifdef MODULE_SVG_ENABLED
@@ -244,8 +248,7 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float
// Generating upsampled icons is slower, and the benefit is hardly visible
// with integer editor scales.
const bool upsample = !Math::is_equal_approx(Math::round(p_scale), p_scale);
- ImageLoaderSVG img_loader;
- Error err = img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_colors);
+ Error err = ImageLoaderSVG::create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_colors);
ERR_FAIL_COND_V_MSG(err != OK, Ref<ImageTexture>(), "Failed generating icon, unsupported or invalid SVG data in editor theme.");
if (p_saturation != 1.0) {
img->adjust_bcs(1.0, 1.0, p_saturation);
@@ -1276,6 +1279,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("h_separation", "Tree", 6 * EDSCALE);
theme->set_constant("guide_width", "Tree", border_width);
theme->set_constant("item_margin", "Tree", 3 * default_margin_size * EDSCALE);
+ theme->set_constant("inner_item_margin_bottom", "Tree", (default_margin_size + extra_spacing) * EDSCALE);
+ theme->set_constant("inner_item_margin_left", "Tree", (default_margin_size + extra_spacing) * EDSCALE);
+ theme->set_constant("inner_item_margin_right", "Tree", (default_margin_size + extra_spacing) * EDSCALE);
+ theme->set_constant("inner_item_margin_top", "Tree", (default_margin_size + extra_spacing) * EDSCALE);
theme->set_constant("button_margin", "Tree", default_margin_size * EDSCALE);
theme->set_constant("scroll_border", "Tree", 40 * EDSCALE);
theme->set_constant("scroll_speed", "Tree", 12);
@@ -1446,6 +1453,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("panel", "TabContainer", style_content_panel);
// Bottom panel.
+ theme->set_type_variation("BottomPanelButton", "Button");
+ // Add separation for the warning/error icon.
+ theme->set_constant("h_separation", "BottomPanelButton", 6 * EDSCALE);
Ref<StyleBoxFlat> style_bottom_panel = style_content_panel->duplicate();
style_bottom_panel->set_corner_radius_all(corner_radius * EDSCALE);
theme->set_stylebox("BottomPanel", "EditorStyles", style_bottom_panel);
@@ -1602,6 +1612,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_window->set_border_width(SIDE_TOP, 24 * EDSCALE);
style_window->set_expand_margin(SIDE_TOP, 24 * EDSCALE);
theme->set_stylebox("embedded_border", "Window", style_window);
+ theme->set_stylebox("embedded_unfocused_border", "Window", style_window);
theme->set_color("title_color", "Window", font_color);
theme->set_icon("close", "Window", theme->get_icon(SNAME("GuiClose"), SNAME("EditorIcons")));
@@ -1785,7 +1796,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("outline_size", "ProgressBar", 0);
// GraphEdit
- theme->set_stylebox("bg", "GraphEdit", style_tree_bg);
+ theme->set_stylebox("panel", "GraphEdit", style_tree_bg);
if (dark_theme) {
theme->set_color("grid_major", "GraphEdit", Color(1.0, 1.0, 1.0, 0.15));
theme->set_color("grid_minor", "GraphEdit", Color(1.0, 1.0, 1.0, 0.07));
@@ -1796,18 +1807,20 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("selection_fill", "GraphEdit", theme->get_color(SNAME("box_selection_fill_color"), SNAME("Editor")));
theme->set_color("selection_stroke", "GraphEdit", theme->get_color(SNAME("box_selection_stroke_color"), SNAME("Editor")));
theme->set_color("activity", "GraphEdit", accent_color);
- theme->set_icon("minus", "GraphEdit", theme->get_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
- theme->set_icon("more", "GraphEdit", theme->get_icon(SNAME("ZoomMore"), SNAME("EditorIcons")));
- theme->set_icon("reset", "GraphEdit", theme->get_icon(SNAME("ZoomReset"), SNAME("EditorIcons")));
- theme->set_icon("snap", "GraphEdit", theme->get_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
- theme->set_icon("minimap", "GraphEdit", theme->get_icon(SNAME("GridMinimap"), SNAME("EditorIcons")));
+
+ theme->set_icon("zoom_out", "GraphEdit", theme->get_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
+ theme->set_icon("zoom_in", "GraphEdit", theme->get_icon(SNAME("ZoomMore"), SNAME("EditorIcons")));
+ theme->set_icon("zoom_reset", "GraphEdit", theme->get_icon(SNAME("ZoomReset"), SNAME("EditorIcons")));
+ theme->set_icon("grid_toggle", "GraphEdit", theme->get_icon(SNAME("GridToggle"), SNAME("EditorIcons")));
+ theme->set_icon("minimap_toggle", "GraphEdit", theme->get_icon(SNAME("GridMinimap"), SNAME("EditorIcons")));
+ theme->set_icon("snapping_toggle", "GraphEdit", theme->get_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
theme->set_icon("layout", "GraphEdit", theme->get_icon(SNAME("GridLayout"), SNAME("EditorIcons")));
// GraphEditMinimap
Ref<StyleBoxFlat> style_minimap_bg = make_flat_stylebox(dark_color_1, 0, 0, 0, 0);
style_minimap_bg->set_border_color(dark_color_3);
style_minimap_bg->set_border_width_all(1);
- theme->set_stylebox("bg", "GraphEditMinimap", style_minimap_bg);
+ theme->set_stylebox("panel", "GraphEditMinimap", style_minimap_bg);
Ref<StyleBoxFlat> style_minimap_camera;
Ref<StyleBoxFlat> style_minimap_node;
@@ -1887,8 +1900,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("frame", "GraphNode", graphsb);
theme->set_stylebox("selected_frame", "GraphNode", graphsbselected);
- theme->set_stylebox("comment", "GraphNode", graphsbcomment);
- theme->set_stylebox("comment_focus", "GraphNode", graphsbcommentselected);
theme->set_stylebox("breakpoint", "GraphNode", graphsbbreakpoint);
theme->set_stylebox("position", "GraphNode", graphsbposition);
theme->set_stylebox("slot", "GraphNode", graphsbslot);
@@ -1910,7 +1921,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("close", "GraphNode", theme->get_icon(SNAME("GuiCloseCustomizable"), SNAME("EditorIcons")));
theme->set_icon("resizer", "GraphNode", theme->get_icon(SNAME("GuiResizer"), SNAME("EditorIcons")));
- theme->set_icon("port", "GraphNode", theme->get_icon(SNAME("GuiGraphNodePort"), SNAME("EditorIcons")));
+ Ref<ImageTexture> port_icon = theme->get_icon(SNAME("GuiGraphNodePort"), SNAME("EditorIcons"));
+ // The true size is 24x24 This is necessary for sharp port icons at high zoom levels in GraphEdit (up to ~200%).
+ port_icon->set_size_override(Size2(12, 12));
+ theme->set_icon("port", "GraphNode", port_icon);
theme->set_font("title_font", "GraphNode", theme->get_font(SNAME("main_bold_msdf"), SNAME("EditorFonts")));
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
index fd2d51be32..abfbd5e7c0 100644
--- a/editor/editor_undo_redo_manager.cpp
+++ b/editor/editor_undo_redo_manager.cpp
@@ -264,6 +264,7 @@ void EditorUndoRedoManager::commit_action(bool p_execute) {
pending_action.action_name == prev_action.action_name && pending_action.action_name == pre_prev_action.action_name) {
pending_action = Action();
is_committing = false;
+ emit_signal(SNAME("history_changed"));
return;
}
} break;
@@ -272,6 +273,7 @@ void EditorUndoRedoManager::commit_action(bool p_execute) {
if (pending_action.merge_mode == prev_action.merge_mode && pending_action.action_name == prev_action.action_name) {
pending_action = Action();
is_committing = false;
+ emit_signal(SNAME("history_changed"));
return;
}
} break;
diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp
index 106f793210..6c4fb480d7 100644
--- a/editor/export/editor_export.cpp
+++ b/editor/export/editor_export.cpp
@@ -90,11 +90,12 @@ void EditorExport::_save() {
String option_section = "preset." + itos(i) + ".options";
- for (const PropertyInfo &E : preset->get_properties()) {
- if (E.usage & PROPERTY_USAGE_SECRET) {
- credentials->set_value(option_section, E.name, preset->get(E.name));
+ for (const KeyValue<StringName, Variant> &E : preset->values) {
+ PropertyInfo *prop = preset->properties.getptr(E.key);
+ if (prop && prop->usage & PROPERTY_USAGE_SECRET) {
+ credentials->set_value(option_section, E.key, E.value);
} else {
- config->set_value(option_section, E.name, preset->get(E.name));
+ config->set_value(option_section, E.key, E.value);
}
}
}
@@ -116,6 +117,7 @@ void EditorExport::_bind_methods() {
void EditorExport::add_export_platform(const Ref<EditorExportPlatform> &p_platform) {
export_platforms.push_back(p_platform);
+ should_update_presets = true;
}
int EditorExport::get_export_platform_count() {
@@ -169,11 +171,13 @@ void EditorExport::remove_export_preset(int p_idx) {
void EditorExport::add_export_plugin(const Ref<EditorExportPlugin> &p_plugin) {
if (!export_plugins.has(p_plugin)) {
export_plugins.push_back(p_plugin);
+ should_update_presets = true;
}
}
void EditorExport::remove_export_plugin(const Ref<EditorExportPlugin> &p_plugin) {
export_plugins.erase(p_plugin);
+ should_update_presets = true;
}
Vector<Ref<EditorExportPlugin>> EditorExport::get_export_plugins() {
@@ -314,8 +318,11 @@ void EditorExport::load_config() {
credentials->get_section_keys(option_section, &options);
for (const String &E : options) {
- Variant value = credentials->get_value(option_section, E);
- preset->set(E, value);
+ // Drop values for secret properties that no longer exist, or during the next save they would end up in the regular config file.
+ if (preset->get_properties().has(E)) {
+ Variant value = credentials->get_value(option_section, E);
+ preset->set(E, value);
+ }
}
}
@@ -332,7 +339,8 @@ void EditorExport::update_export_presets() {
for (int i = 0; i < export_platforms.size(); i++) {
Ref<EditorExportPlatform> platform = export_platforms[i];
- bool should_update = platform->should_update_export_options();
+ bool should_update = should_update_presets;
+ should_update |= platform->should_update_export_options();
for (int j = 0; j < export_plugins.size(); j++) {
should_update |= export_plugins.write[j]->_should_update_export_options(platform);
}
@@ -342,12 +350,13 @@ void EditorExport::update_export_presets() {
platform->get_export_options(&options);
for (int j = 0; j < export_plugins.size(); j++) {
- export_plugins.write[j]->_get_export_options(platform, &options);
+ export_plugins[j]->_get_export_options(platform, &options);
}
platform_options[platform->get_name()] = options;
}
}
+ should_update_presets = false;
bool export_presets_updated = false;
for (int i = 0; i < export_presets.size(); i++) {
@@ -357,19 +366,16 @@ void EditorExport::update_export_presets() {
List<EditorExportPlatform::ExportOption> options = platform_options[preset->get_platform()->get_name()];
- // Copy the previous preset values
- HashMap<StringName, Variant> previous_values = preset->values;
-
- // Clear the preset properties and values prior to reloading
+ // Clear the preset properties prior to reloading, keep the values to preserve options from plugins that may be currently disabled.
preset->properties.clear();
- preset->values.clear();
preset->update_visibility.clear();
for (const EditorExportPlatform::ExportOption &E : options) {
- preset->properties.push_back(E.option);
-
StringName option_name = E.option.name;
- preset->values[option_name] = previous_values.has(option_name) ? previous_values[option_name] : E.default_value;
+ preset->properties[option_name] = E.option;
+ if (!preset->has(option_name)) {
+ preset->values[option_name] = E.default_value;
+ }
preset->update_visibility[option_name] = E.update_visibility;
}
}
diff --git a/editor/export/editor_export.h b/editor/export/editor_export.h
index 343686a4cf..55dee0c468 100644
--- a/editor/export/editor_export.h
+++ b/editor/export/editor_export.h
@@ -45,6 +45,7 @@ class EditorExport : public Node {
Timer *save_timer = nullptr;
bool block_save = false;
+ bool should_update_presets = false;
static EditorExport *singleton;
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 00fbd85166..5ee9b187a2 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -45,6 +45,7 @@
#include "editor/export/editor_export.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor_export_plugin.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/packed_scene.h"
static int _get_pad(int p_alignment, int p_n) {
@@ -329,9 +330,10 @@ Ref<EditorExportPreset> EditorExportPlatform::create_preset() {
}
for (const ExportOption &E : options) {
- preset->properties.push_back(E.option);
- preset->values[E.option.name] = E.default_value;
- preset->update_visibility[E.option.name] = E.update_visibility;
+ StringName option_name = E.option.name;
+ preset->properties[option_name] = E.option;
+ preset->values[option_name] = E.default_value;
+ preset->update_visibility[option_name] = E.update_visibility;
}
return preset;
@@ -988,7 +990,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
struct SortByName {
bool operator()(const Ref<EditorExportPlugin> &left, const Ref<EditorExportPlugin> &right) const {
- return left->_get_name() < right->_get_name();
+ return left->get_name() < right->get_name();
}
};
@@ -1031,14 +1033,14 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
if (export_plugins.write[i]->_begin_customize_resources(Ref<EditorExportPlatform>(this), features_psa)) {
customize_resources_plugins.push_back(export_plugins[i]);
- custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash);
+ custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->get_name().hash64(), custom_resources_hash);
uint64_t hash = export_plugins[i]->_get_customization_configuration_hash();
custom_resources_hash = hash_murmur3_one_64(hash, custom_resources_hash);
}
if (export_plugins.write[i]->_begin_customize_scenes(Ref<EditorExportPlatform>(this), features_psa)) {
customize_scenes_plugins.push_back(export_plugins[i]);
- custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash);
+ custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->get_name().hash64(), custom_resources_hash);
uint64_t hash = export_plugins[i]->_get_customization_configuration_hash();
custom_scene_hash = hash_murmur3_one_64(hash, custom_scene_hash);
}
@@ -1798,6 +1800,24 @@ bool EditorExportPlatform::can_export(const Ref<EditorExportPreset> &p_preset, S
if (!templates_error.is_empty()) {
r_error += templates_error;
}
+
+ String export_plugins_warning;
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ Ref<EditorExportPlatform> export_platform = Ref<EditorExportPlatform>(this);
+ if (!export_plugins[i]->supports_platform(export_platform)) {
+ continue;
+ }
+
+ String plugin_warning = export_plugins.write[i]->_has_valid_export_configuration(export_platform, p_preset);
+ if (!plugin_warning.is_empty()) {
+ export_plugins_warning += plugin_warning;
+ }
+ }
+
+ if (!export_plugins_warning.is_empty()) {
+ r_error += export_plugins_warning;
+ }
#endif
String project_configuration_error;
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index 121e00ccae..763836e3ec 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -40,6 +40,7 @@ struct EditorProgress;
#include "editor_export_shared_object.h"
#include "scene/gui/rich_text_label.h"
#include "scene/main/node.h"
+#include "scene/resources/image_texture.h"
class EditorExportPlugin;
diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp
index df1026d0ed..ec34ffd1df 100644
--- a/editor/export/editor_export_platform_pc.cpp
+++ b/editor/export/editor_export_platform_pc.cpp
@@ -31,6 +31,7 @@
#include "editor_export_platform_pc.h"
#include "core/config/project_settings.h"
+#include "scene/resources/image_texture.h"
void EditorExportPlatformPC::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
if (p_preset->get("texture_format/bptc")) {
diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp
index 4e2c1a9af7..6576960b9a 100644
--- a/editor/export/editor_export_plugin.cpp
+++ b/editor/export/editor_export_plugin.cpp
@@ -132,6 +132,27 @@ Variant EditorExportPlugin::get_option(const StringName &p_name) const {
return export_preset->get(p_name);
}
+String EditorExportPlugin::_has_valid_export_configuration(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset) {
+ String warning;
+ if (!supports_platform(p_export_platform)) {
+ warning += vformat(TTR("Plugin \"%s\" is not supported on \"%s\""), get_name(), p_export_platform->get_name());
+ warning += "\n";
+ return warning;
+ }
+
+ set_export_preset(p_preset);
+ List<EditorExportPlatform::ExportOption> options;
+ _get_export_options(p_export_platform, &options);
+ for (const EditorExportPlatform::ExportOption &E : options) {
+ String option_warning = _get_export_option_warning(p_export_platform, E.option.name);
+ if (!option_warning.is_empty()) {
+ warning += option_warning + "\n";
+ }
+ }
+
+ return warning;
+}
+
void EditorExportPlugin::_export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features) {
GDVIRTUAL_CALL(_export_file, p_path, p_type, p_features);
}
@@ -184,12 +205,54 @@ void EditorExportPlugin::_end_customize_resources() {
GDVIRTUAL_CALL(_end_customize_resources);
}
-String EditorExportPlugin::_get_name() const {
+String EditorExportPlugin::get_name() const {
String ret;
GDVIRTUAL_REQUIRED_CALL(_get_name, ret);
return ret;
}
+bool EditorExportPlugin::supports_platform(const Ref<EditorExportPlatform> &p_export_platform) const {
+ bool ret = false;
+ GDVIRTUAL_CALL(_supports_platform, p_export_platform, ret);
+ return ret;
+}
+
+PackedStringArray EditorExportPlugin::get_android_dependencies(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
+ PackedStringArray ret;
+ GDVIRTUAL_CALL(_get_android_dependencies, p_export_platform, p_debug, ret);
+ return ret;
+}
+
+PackedStringArray EditorExportPlugin::get_android_dependencies_maven_repos(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
+ PackedStringArray ret;
+ GDVIRTUAL_CALL(_get_android_dependencies_maven_repos, p_export_platform, p_debug, ret);
+ return ret;
+}
+
+PackedStringArray EditorExportPlugin::get_android_libraries(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
+ PackedStringArray ret;
+ GDVIRTUAL_CALL(_get_android_libraries, p_export_platform, p_debug, ret);
+ return ret;
+}
+
+String EditorExportPlugin::get_android_manifest_activity_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
+ String ret;
+ GDVIRTUAL_CALL(_get_android_manifest_activity_element_contents, p_export_platform, p_debug, ret);
+ return ret;
+}
+
+String EditorExportPlugin::get_android_manifest_application_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
+ String ret;
+ GDVIRTUAL_CALL(_get_android_manifest_application_element_contents, p_export_platform, p_debug, ret);
+ return ret;
+}
+
+String EditorExportPlugin::get_android_manifest_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
+ String ret;
+ GDVIRTUAL_CALL(_get_android_manifest_element_contents, p_export_platform, p_debug, ret);
+ return ret;
+}
+
PackedStringArray EditorExportPlugin::_get_export_features(const Ref<EditorExportPlatform> &p_platform, bool p_debug) const {
PackedStringArray ret;
GDVIRTUAL_CALL(_get_export_features, p_platform, p_debug, ret);
@@ -216,6 +279,12 @@ bool EditorExportPlugin::_should_update_export_options(const Ref<EditorExportPla
return ret;
}
+String EditorExportPlugin::_get_export_option_warning(const Ref<EditorExportPlatform> &p_export_platform, const String &p_option_name) const {
+ String ret;
+ GDVIRTUAL_CALL(_get_export_option_warning, p_export_platform, p_option_name, ret);
+ return ret;
+}
+
void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
}
@@ -257,9 +326,19 @@ void EditorExportPlugin::_bind_methods() {
GDVIRTUAL_BIND(_get_export_options, "platform");
GDVIRTUAL_BIND(_should_update_export_options, "platform");
+ GDVIRTUAL_BIND(_get_export_option_warning, "platform", "option");
GDVIRTUAL_BIND(_get_export_features, "platform", "debug");
GDVIRTUAL_BIND(_get_name);
+
+ GDVIRTUAL_BIND(_supports_platform, "platform");
+
+ GDVIRTUAL_BIND(_get_android_dependencies, "platform", "debug");
+ GDVIRTUAL_BIND(_get_android_dependencies_maven_repos, "platform", "debug");
+ GDVIRTUAL_BIND(_get_android_libraries, "platform", "debug");
+ GDVIRTUAL_BIND(_get_android_manifest_activity_element_contents, "platform", "debug");
+ GDVIRTUAL_BIND(_get_android_manifest_application_element_contents, "platform", "debug");
+ GDVIRTUAL_BIND(_get_android_manifest_element_contents, "platform", "debug");
}
EditorExportPlugin::EditorExportPlugin() {
diff --git a/editor/export/editor_export_plugin.h b/editor/export/editor_export_plugin.h
index 120141b347..7d866ce37e 100644
--- a/editor/export/editor_export_plugin.h
+++ b/editor/export/editor_export_plugin.h
@@ -42,6 +42,7 @@ class EditorExportPlugin : public RefCounted {
friend class EditorExport;
friend class EditorExportPlatform;
+ friend class EditorExportPreset;
Ref<EditorExportPreset> export_preset;
@@ -85,6 +86,8 @@ class EditorExportPlugin : public RefCounted {
void _export_begin_script(const Vector<String> &p_features, bool p_debug, const String &p_path, int p_flags);
void _export_end_script();
+ String _has_valid_export_configuration(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset);
+
protected:
void set_export_preset(const Ref<EditorExportPreset> &p_preset);
Ref<EditorExportPreset> get_export_preset() const;
@@ -125,9 +128,19 @@ protected:
GDVIRTUAL2RC(PackedStringArray, _get_export_features, const Ref<EditorExportPlatform> &, bool);
GDVIRTUAL1RC(TypedArray<Dictionary>, _get_export_options, const Ref<EditorExportPlatform> &);
GDVIRTUAL1RC(bool, _should_update_export_options, const Ref<EditorExportPlatform> &);
+ GDVIRTUAL2RC(String, _get_export_option_warning, const Ref<EditorExportPlatform> &, String);
GDVIRTUAL0RC(String, _get_name)
+ GDVIRTUAL1RC(bool, _supports_platform, const Ref<EditorExportPlatform> &);
+
+ GDVIRTUAL2RC(PackedStringArray, _get_android_dependencies, const Ref<EditorExportPlatform> &, bool);
+ GDVIRTUAL2RC(PackedStringArray, _get_android_dependencies_maven_repos, const Ref<EditorExportPlatform> &, bool);
+ GDVIRTUAL2RC(PackedStringArray, _get_android_libraries, const Ref<EditorExportPlatform> &, bool);
+ GDVIRTUAL2RC(String, _get_android_manifest_activity_element_contents, const Ref<EditorExportPlatform> &, bool);
+ GDVIRTUAL2RC(String, _get_android_manifest_application_element_contents, const Ref<EditorExportPlatform> &, bool);
+ GDVIRTUAL2RC(String, _get_android_manifest_element_contents, const Ref<EditorExportPlatform> &, bool);
+
virtual bool _begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features); // Return true if this plugin does property export customization
virtual Ref<Resource> _customize_resource(const Ref<Resource> &p_resource, const String &p_path); // If nothing is returned, it means do not touch (nothing changed). If something is returned (either the same or a different resource) it means changes are made.
@@ -142,10 +155,20 @@ protected:
virtual PackedStringArray _get_export_features(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
virtual void _get_export_options(const Ref<EditorExportPlatform> &p_export_platform, List<EditorExportPlatform::ExportOption> *r_options) const;
virtual bool _should_update_export_options(const Ref<EditorExportPlatform> &p_export_platform) const;
-
- virtual String _get_name() const;
+ virtual String _get_export_option_warning(const Ref<EditorExportPlatform> &p_export_platform, const String &p_option_name) const;
public:
+ virtual String get_name() const;
+
+ virtual bool supports_platform(const Ref<EditorExportPlatform> &p_export_platform) const;
+
+ virtual PackedStringArray get_android_dependencies(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
+ virtual PackedStringArray get_android_dependencies_maven_repos(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
+ virtual PackedStringArray get_android_libraries(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
+ virtual String get_android_manifest_activity_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
+ virtual String get_android_manifest_application_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
+ virtual String get_android_manifest_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
+
Vector<String> get_ios_frameworks() const;
Vector<String> get_ios_embedded_frameworks() const;
Vector<String> get_ios_project_static_libs() const;
diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp
index 2aca19a2ad..dfc0c23afc 100644
--- a/editor/export/editor_export_preset.cpp
+++ b/editor/export/editor_export_preset.cpp
@@ -31,9 +31,9 @@
#include "editor_export.h"
bool EditorExportPreset::_set(const StringName &p_name, const Variant &p_value) {
- if (values.has(p_name)) {
- values[p_name] = p_value;
- EditorExport::singleton->save_presets();
+ values[p_name] = p_value;
+ EditorExport::singleton->save_presets();
+ if (update_visibility.has(p_name)) {
if (update_visibility[p_name]) {
notify_property_list_changed();
}
@@ -57,13 +57,32 @@ void EditorExportPreset::_bind_methods() {
}
String EditorExportPreset::_get_property_warning(const StringName &p_name) const {
- return platform->get_export_option_warning(this, p_name);
+ String warning = platform->get_export_option_warning(this, p_name);
+ if (!warning.is_empty()) {
+ warning += "\n";
+ }
+
+ // Get property warning from editor export plugins.
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ if (!export_plugins[i]->supports_platform(platform)) {
+ continue;
+ }
+
+ export_plugins.write[i]->set_export_preset(Ref<EditorExportPreset>(this));
+ String plugin_warning = export_plugins[i]->_get_export_option_warning(platform, p_name);
+ if (!plugin_warning.is_empty()) {
+ warning += plugin_warning + "\n";
+ }
+ }
+
+ return warning;
}
void EditorExportPreset::_get_property_list(List<PropertyInfo> *p_list) const {
- for (const PropertyInfo &E : properties) {
- if (platform->get_export_option_visibility(this, E.name)) {
- p_list->push_back(E);
+ for (const KeyValue<StringName, PropertyInfo> &E : properties) {
+ if (platform->get_export_option_visibility(this, E.key)) {
+ p_list->push_back(E.value);
}
}
}
diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h
index 194858b4e8..8b59da06dd 100644
--- a/editor/export/editor_export_preset.h
+++ b/editor/export/editor_export_preset.h
@@ -70,7 +70,7 @@ private:
friend class EditorExport;
friend class EditorExportPlatform;
- List<PropertyInfo> properties;
+ HashMap<StringName, PropertyInfo> properties;
HashMap<StringName, Variant> values;
HashMap<StringName, bool> update_visibility;
@@ -154,7 +154,8 @@ public:
Variant get_or_env(const StringName &p_name, const String &p_env_var, bool *r_valid = nullptr) const;
- const List<PropertyInfo> &get_properties() const { return properties; }
+ const HashMap<StringName, PropertyInfo> &get_properties() const { return properties; }
+ const HashMap<StringName, Variant> &get_values() const { return values; }
EditorExportPreset();
};
diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp
index e551b0531a..42e4b6f6f6 100644
--- a/editor/export/export_template_manager.cpp
+++ b/editor/export/export_template_manager.cpp
@@ -669,11 +669,8 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_
f->store_line(VERSION_FULL_CONFIG);
}
- // Create the android plugins directory.
- Error err = da->make_dir_recursive("android/plugins");
- ERR_FAIL_COND_V(err != OK, err);
-
- err = da->make_dir_recursive("android/build");
+ // Create the android build directory.
+ Error err = da->make_dir_recursive("android/build");
ERR_FAIL_COND_V(err != OK, err);
{
// Add an empty .gdignore file to avoid scan.
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index 8009b3038c..7c7762e0fd 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -577,8 +577,8 @@ void ProjectExportDialog::_duplicate_preset() {
preset->set_exclude_filter(current->get_exclude_filter());
preset->set_custom_features(current->get_custom_features());
- for (const PropertyInfo &E : current->get_properties()) {
- preset->set(E.name, current->get(E.name));
+ for (const KeyValue<StringName, Variant> &E : current->get_values()) {
+ preset->set(E.key, E.value);
}
EditorExport::get_singleton()->add_export_preset(preset);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index dd8fde496f..1ff68b7d36 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2617,8 +2617,10 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
if (!to_dir.is_empty()) {
Vector<String> fnames = drag_data["files"];
to_move.clear();
+ String target_dir = to_dir == "res://" ? to_dir : to_dir.trim_suffix("/");
+
for (int i = 0; i < fnames.size(); i++) {
- if (fnames[i].trim_suffix("/").get_base_dir() != to_dir.trim_suffix("/")) {
+ if (fnames[i].trim_suffix("/").get_base_dir() != target_dir) {
to_move.push_back(FileOrFolder(fnames[i], !fnames[i].ends_with("/")));
}
}
diff --git a/editor/gui/editor_toaster.cpp b/editor/gui/editor_toaster.cpp
index 866a6db2a6..f928a0fd30 100644
--- a/editor/gui/editor_toaster.cpp
+++ b/editor/gui/editor_toaster.cpp
@@ -35,6 +35,7 @@
#include "scene/gui/button.h"
#include "scene/gui/label.h"
#include "scene/gui/panel_container.h"
+#include "scene/resources/style_box_flat.h"
EditorToaster *EditorToaster::singleton = nullptr;
diff --git a/editor/gui/editor_toaster.h b/editor/gui/editor_toaster.h
index 4837756b4e..3e39d9d519 100644
--- a/editor/gui/editor_toaster.h
+++ b/editor/gui/editor_toaster.h
@@ -37,6 +37,7 @@
class Button;
class PanelContainer;
+class StyleBoxFlat;
class EditorToaster : public HBoxContainer {
GDCLASS(EditorToaster, HBoxContainer);
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index d1756df66c..fbe167814d 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -374,7 +374,14 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
tooltip += String("\n" + TTR("Type:") + " " + (custom_type != StringName() ? String(custom_type) : p_node->get_class()));
if (!p_node->get_editor_description().is_empty()) {
- tooltip += "\n\n" + p_node->get_editor_description();
+ const PackedInt32Array boundaries = TS->string_get_word_breaks(p_node->get_editor_description(), "", 80);
+ tooltip += "\n";
+
+ for (int i = 0; i < boundaries.size(); i += 2) {
+ const int start = boundaries[i];
+ const int end = boundaries[i + 1];
+ tooltip += "\n" + p_node->get_editor_description().substr(start, end - start + 1).rstrip("\n");
+ }
}
item->set_tooltip_text(0, tooltip);
@@ -1019,11 +1026,18 @@ void SceneTreeEditor::_renamed() {
}
}
- if (n->is_unique_name_in_owner() && get_tree()->get_edited_scene_root()->get_node_or_null("%" + new_name) != nullptr) {
- error->set_text(TTR("Another node already uses this unique name in the scene."));
- error->popup_centered();
- which->set_text(0, n->get_name());
- return;
+ if (n->is_unique_name_in_owner()) {
+ Node *existing = get_tree()->get_edited_scene_root()->get_node_or_null("%" + new_name);
+ if (existing == n) {
+ which->set_text(0, n->get_name());
+ return;
+ }
+ if (existing != nullptr) {
+ error->set_text(TTR("Another node already uses this unique name in the scene."));
+ error->popup_centered();
+ which->set_text(0, n->get_name());
+ return;
+ }
}
_rename_node(n, new_name);
@@ -1100,9 +1114,15 @@ void SceneTreeEditor::_update_selection(TreeItem *item) {
}
if (editor_selection->is_selected(n)) {
- item->select(0);
+ if (!item->is_selected(0)) {
+ item->select(0);
+ }
} else {
- item->deselect(0);
+ if (item->is_selected(0)) {
+ TreeItem *previous_cursor_item = tree->get_selected();
+ item->deselect(0);
+ previous_cursor_item->set_as_cursor(0);
+ }
}
TreeItem *c = item->get_first_child();
@@ -1188,8 +1208,11 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from
if (i < list_max) {
HBoxContainer *hb = memnew(HBoxContainer);
TextureRect *tf = memnew(TextureRect);
+ int icon_size = get_theme_constant(SNAME("class_icon_size"), SNAME("Editor"));
+ tf->set_custom_minimum_size(Size2(icon_size, icon_size));
+ tf->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
+ tf->set_expand_mode(TextureRect::EXPAND_IGNORE_SIZE);
tf->set_texture(icons[i]);
- tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
hb->add_child(tf);
Label *label = memnew(Label(selected_nodes[i]->get_name()));
hb->add_child(label);
diff --git a/editor/icons/AnimatedSprite2D.svg b/editor/icons/AnimatedSprite2D.svg
index b22aeadeb6..d0a3f248a5 100644
--- a/editor/icons/AnimatedSprite2D.svg
+++ b/editor/icons/AnimatedSprite2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#8da5f3"><path d="m7 0c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v6c1.108 0 2-.89199 2-2v-6c0-1.108-.89199-2-2-2z" fill-opacity=".39216"/><path d="m5 2c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2z" fill-opacity=".58824"/><path d="m3 4c-1.108 0-2 .89199-2 2v7c0 1.108.89199 2 2 2h7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2zm0 4c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm7 0c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm-6 4h5a2.5 2 0 0 1 -1.25 1.7324 2.5 2 0 0 1 -2.5 0 2.5 2 0 0 1 -1.25-1.7324z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#8da5f3"><path d="M7 0a2 2 0 0 0-2 2h7a2 2 0 0 1 2 2v6a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z" fill-opacity=".392"/><path d="M5 2a2 2 0 0 0-2 2h7a2 2 0 0 1 2 2v7a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2z" fill-opacity=".588"/><path d="M3 4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zM2 9a1 1 0 0 1 2 0v1a1 1 0 0 1-2 0zm7 0a1 1 0 0 1 2 0v1a1 1 0 0 1-2 0zm0 3a2.5 2 0 0 1-5 0z"/></g></svg>
diff --git a/editor/icons/AnimatedSprite3D.svg b/editor/icons/AnimatedSprite3D.svg
index 99520a3bc2..59ba788920 100644
--- a/editor/icons/AnimatedSprite3D.svg
+++ b/editor/icons/AnimatedSprite3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><path d="m7 0c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v6c1.108 0 2-.89199 2-2v-6c0-1.108-.89199-2-2-2z" fill-opacity=".39216"/><path d="m5 2c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2z" fill-opacity=".58824"/><path d="m3 4c-1.108 0-2 .89199-2 2v7c0 1.108.89199 2 2 2h7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2zm0 4c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm7 0c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm-6 4h5a2.5 2 0 0 1 -1.25 1.7324 2.5 2 0 0 1 -2.5 0 2.5 2 0 0 1 -1.25-1.7324z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><path d="M7 0a2 2 0 0 0-2 2h7a2 2 0 0 1 2 2v6a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z" fill-opacity=".392"/><path d="M5 2a2 2 0 0 0-2 2h7a2 2 0 0 1 2 2v7a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2z" fill-opacity=".588"/><path d="M3 4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zM2 9a1 1 0 0 1 2 0v1a1 1 0 0 1-2 0zm7 0a1 1 0 0 1 2 0v1a1 1 0 0 1-2 0zm0 3a2.5 2 0 0 1-5 0z"/></g></svg>
diff --git a/editor/icons/AssetLib.svg b/editor/icons/AssetLib.svg
index 22307efde3..6463c1a3b5 100644
--- a/editor/icons/AssetLib.svg
+++ b/editor/icons/AssetLib.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="2"><path d="m8 1v9l4-4"/><path d="m8 10-4-4"/><path d="m2 10v4h12v-4" stroke-linecap="round"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="2"><path d="M8 1v9l4-4m-4 4L4 6"/><path d="M2 10v4h12v-4" stroke-linecap="round"/></g></svg>
diff --git a/editor/icons/AutoKey.svg b/editor/icons/AutoKey.svg
index 877b00722f..5af089c4a8 100644
--- a/editor/icons/AutoKey.svg
+++ b/editor/icons/AutoKey.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><circle cx="8" cy="5" r="4"/><path d="m11 13c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1 .00001-.55228.44772-.99999 1-1h1v-2h-1c-1.6569 0-3 1.3431-3 3z"/><path d="m4 10c-1.6569 0-3 1.3431-3 3v3h2v-3c.0000096-.5523.44772-1 1-1h1v-2z"/><path d="m8 10c-3 0-3 3-3 3s0 3 3 3h1v-2h-1s-1 0-1-1h3 1s0-3-3-3zm-1 1h2v1h-2z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><circle cx="8" cy="5" r="4"/><path d="M11 13a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 0-2h1v-2h-1a3 3 0 0 0-3 3zm-7-3a3 3 0 0 0-3 3v3h2v-3a1 1 0 0 1 1-1h1v-2zm4 6h1v-2H8a1 1 0 0 1-1-1h4a3 3 0 1 0-3 3zm-1-4a1.08 1.08 0 0 1 2 0z"/></g></svg>
diff --git a/editor/icons/Bone.svg b/editor/icons/Bone.svg
index 46b068c0ec..16c232c71e 100644
--- a/editor/icons/Bone.svg
+++ b/editor/icons/Bone.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M10.478 1a2.466 2.466 0 0 0-2.094 3.824l-3.56 3.56a2.466 2.466 0 1 0-1.705 4.496 2.466 2.466 0 1 0 4.496-1.705l3.56-3.56a2.466 2.466 0 1 0 1.705-4.496A2.466 2.466 0 0 0 10.478 1z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.824 8.384a2.466 2.466 0 1 0-1.705 4.496 2.466 2.466 0 1 0 4.496-1.705l3.56-3.56a2.466 2.466 0 1 0 1.705-4.496 2.466 2.466 0 1 0-4.496 1.705z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Bone2D.svg b/editor/icons/Bone2D.svg
index 31515216c9..efa1d9d2cf 100644
--- a/editor/icons/Bone2D.svg
+++ b/editor/icons/Bone2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M10.478 1a2.466 2.466 0 0 0-2.094 3.824l-3.56 3.56a2.466 2.466 0 1 0-1.705 4.496 2.466 2.466 0 1 0 4.496-1.705l3.56-3.56a2.466 2.466 0 1 0 1.705-4.496A2.466 2.466 0 0 0 10.478 1z" fill="#8da5f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.824 8.384a2.466 2.466 0 1 0-1.705 4.496 2.466 2.466 0 1 0 4.496-1.705l3.56-3.56a2.466 2.466 0 1 0 1.705-4.496 2.466 2.466 0 1 0-4.496 1.705z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/BoneAttachment3D.svg b/editor/icons/BoneAttachment3D.svg
index 37bfd159df..2cc0adb906 100644
--- a/editor/icons/BoneAttachment3D.svg
+++ b/editor/icons/BoneAttachment3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M10.478 1a2.466 2.466 0 0 0-2.094 3.824l-3.56 3.56a2.466 2.466 0 1 0-1.705 4.496 2.466 2.466 0 1 0 4.496-1.705l3.56-3.56a2.466 2.466 0 1 0 1.705-4.496A2.466 2.466 0 0 0 10.478 1z" fill="#fc7f7f"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.824 8.384a2.466 2.466 0 1 0-1.705 4.496 2.466 2.466 0 1 0 4.496-1.705l3.56-3.56a2.466 2.466 0 1 0 1.705-4.496 2.466 2.466 0 1 0-4.496 1.705z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/ClassList.svg b/editor/icons/ClassList.svg
index 11713b125a..0316dfc942 100644
--- a/editor/icons/ClassList.svg
+++ b/editor/icons/ClassList.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1v1h-5v1h2v10h1 5v1h6v-3h-6v1h-5v-4h5v1h6v-3h-6v1h-5v-4h2v1h6v-3z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1v1h-5v1h2v10h6v1h6v-3h-6v1h-5v-4h5v1h6v-3h-6v1h-5v-4h2v1h6v-3z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/CopyNodePath.svg b/editor/icons/CopyNodePath.svg
index 68952bd2cf..457982bf14 100644
--- a/editor/icons/CopyNodePath.svg
+++ b/editor/icons/CopyNodePath.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><circle cx="3" cy="12"/><path d="M2 1a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V6l-5-5zm1 2h6v3c0 .554.446 1 1 1h3v6H3zm3 5-2 4h2l2-4zm4 0-2 4h2l2-4z"/></g></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 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V6l-5-5zm1 2h6v3a1 1 0 0 0 1 1h3v6H3zm3 5-2 4h2l2-4zm4 0-2 4h2l2-4z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/CryptoKey.svg b/editor/icons/CryptoKey.svg
index c5d1af1d23..e4faefabae 100644
--- a/editor/icons/CryptoKey.svg
+++ b/editor/icons/CryptoKey.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 4.233 4.233" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.397.34-.374.373-.375.374v.375l.188.187-1.497 1.496v.375l.374.374h.374l.187-.188.282-.092.092-.282.282-.093.093-.28.094-.28.28-.095.187-.187.187.187h.374l.375-.375.373-.373.001-.374-1.122-1.122zm.374.858a.264.264 0 1 1 .002.528.264.264 0 0 1 -.002-.528z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 4.233 4.233" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.397.34-.749.747v.375l.188.187L.339 3.145v.375l.374.374h.374l.187-.188.282-.092.092-.282.282-.093.187-.56.28-.095.187-.187.187.187h.374l.748-.748.001-.374L2.772.34zm.374.858a.264.264 0 1 1 .002.528.264.264 0 0 1-.002-.528z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/EditorPositionUnselected.svg b/editor/icons/EditorPositionUnselected.svg
index 30aaa77659..e99bafd258 100644
--- a/editor/icons/EditorPositionUnselected.svg
+++ b/editor/icons/EditorPositionUnselected.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 0v4.4199a4.2662 4.0576 0 0 0 -1.709 1.5801h-4.291v4h4.2949a4.2662 4.0576 0 0 0 1.7051 1.582v4.418h4v-4.4199a4.2662 4.0576 0 0 0 1.709-1.5801h4.291v-4h-4.2949a4.2662 4.0576 0 0 0 -1.7051-1.582v-4.418z" fill-opacity=".41077"/><path d="m7 1v3.0605a4.2662 4.0576 0 0 1 1-.11914 4.2662 4.0576 0 0 1 1 .11914v-3.0605zm1 4.0801a2.9201 2.9201 0 0 0 -2.9199 2.9199 2.9201 2.9201 0 0 0 2.9199 2.9199 2.9201 2.9201 0 0 0 2.9199-2.9199 2.9201 2.9201 0 0 0 -2.9199-2.9199zm-7 1.9199v2h2.8691a4.2662 4.0576 0 0 1 -.13477-1 4.2662 4.0576 0 0 1 .13672-1h-2.8711zm11.131 0a4.2662 4.0576 0 0 1 .13477 1 4.2662 4.0576 0 0 1 -.13672 1h2.8711v-2h-2.8691zm-5.1309 4.9395v3.0605h2v-3.0605a4.2662 4.0576 0 0 1 -1 .11914 4.2662 4.0576 0 0 1 -1-.11914z" fill="#d6d6d6"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M6 0v4.42A4.266 4.058 0 0 0 4.291 6H0v4h4.295A4.266 4.058 0 0 0 6 11.582V16h4v-4.42A4.266 4.058 0 0 0 11.709 10H16V6h-4.295A4.266 4.058 0 0 0 10 4.418V0z" fill-opacity=".411"/><path d="M7 1v3.06a4.266 4.058 0 0 1 2 0V1zm1 4.08a2.92 2.92 0 0 0 0 5.84 2.92 2.92 0 0 0 0-5.84zM1 7v2h2.87a4.266 4.058 0 0 1 .001-2H1zm11.131 0a4.266 4.058 0 0 1-.002 2H15V7h-2.869zm-5.13 4.94V15h2v-3.06a4.266 4.058 0 0 1-2 0z" fill="#d6d6d6"/></svg>
diff --git a/editor/icons/Enum.svg b/editor/icons/Enum.svg
index 45d2c7e24c..03b9b4ae5f 100644
--- a/editor/icons/Enum.svg
+++ b/editor/icons/Enum.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-.5304.0000801-1.0391.21085-1.4141.58594-.37509.37501-.58586.88366-.58594 1.4141v1c-.2652.0000401-.51953.10542-.70703.29297-.18755.18751-.29293.44183-.29297.70703.00004008.2652.10542.51953.29297.70703.18751.18755.44183.29293.70703.29297v1c.0000801.5304.21085 1.0391.58594 1.4141.37501.37509.88366.58586 1.4141.58594h1v-2h-1v-4h1v-2zm3 0v8h4v-2h-2v-1h2v-2h-2v-1h2v-2zm6 0v2h1v4h-1v2h1c.5304-.0000803 1.0391-.21085 1.4141-.58594.37509-.37501.58586-.88366.58594-1.4141v-1c.2652-.0000401.51953-.10542.70703-.29297.18755-.18751.29293-.44183.29297-.70703-.00004-.2652-.10542-.51953-.29297-.70703-.1875-.18755-.44183-.29293-.70703-.29297v-1c-.00008-.5304-.21085-1.0391-.58594-1.4141-.37501-.37509-.88366-.58586-1.4141-.58594z" fill="#e0e0e0"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 2a2 2 0 0 0-2 2v1a1 1 0 0 0 0 2v1a2 2 0 0 0 2 2h1V8H3V4h1V2zm3 0v8h4V8H8V7h2V5H8V4h2V2zm6 0v2h1v4h-1v2h1a2 2 0 0 0 2-2V7a1 1 0 0 0 0-2V4a2 2 0 0 0-2-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/ExpandBottomDock.svg b/editor/icons/ExpandBottomDock.svg
index 636d4f8b83..61120ec14f 100644
--- a/editor/icons/ExpandBottomDock.svg
+++ b/editor/icons/ExpandBottomDock.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m4.2130251 4.516057-3.5355339 3.5355339h2.5356849v4.9737171h1.9998394v-4.9737171h2.5356849l-3.5355339-3.5355339z"/><path d="m11.907306 4.6119359-3.5355342 3.5355339h2.5356852v4.9737172h1.999839v-4.9737172h2.535685l-3.535534-3.5355339z"/><path d="m1.288136 1.370074h14v1.830509h-14z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4 4.5 1 8h2v5h2V8h2zm8 0L9 8h2v5h2V8h2zM1 1h14v2H1z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/ExternalLink.svg b/editor/icons/ExternalLink.svg
index 506f36bd0a..a5042900b5 100644
--- a/editor/icons/ExternalLink.svg
+++ b/editor/icons/ExternalLink.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.939 8.939 5.5-5.5L7.999 1h7v7L12.56 5.561l-5.5 5.5zM12 15H4a3.079 3.079 0 0 1-3-3V4a3.04 3.04 0 0 1 3-3h2a1 1 0 0 1 0 2H4a1.04 1.04 0 0 0-1 1v8a1.083 1.083 0 0 0 1 1h8a1.068 1.068 0 0 0 1-1v-2a1 1 0 0 1 2 0v2a3.063 3.063 0 0 1-3 3z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 9 5.5-5.5L8 1h7v7l-2.5-2.5L7 11zm7 6H4a3 3 0 0 1-3-3V4a3 3 0 0 1 3-3h2a1 1 0 0 1 0 2H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Gizmo3DSamplePlayer.svg b/editor/icons/Gizmo3DSamplePlayer.svg
index dc379b6076..f6fe444e47 100644
--- a/editor/icons/Gizmo3DSamplePlayer.svg
+++ b/editor/icons/Gizmo3DSamplePlayer.svg
@@ -1 +1 @@
-<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M63.766 8.01a8.006 8.006 0 0 0-5.42 2.336l-.002.002-29.656 29.658H16c-4.37 0-8 3.63-8 8v32c0 4.37 3.63 8 8 8h12.688l29.656 29.656c2.4 2.398 5.98 2.866 8.717 1.732 2.737-1.133 4.938-3.996 4.94-7.388V16.002c-.004-4.456-3.78-8.121-8.233-7.992zM112 12.004c-4.37 0-8 3.63-8 8v88c0 4.371 3.63 8 8 8s8-3.629 8-8v-88c0-4.37-3.63-8-8-8zm-24 24c-4.37 0-8 3.63-8 8v40c0 4.371 3.63 8 8 8s8-3.629 8-8v-40c0-4.37-3.63-8-8-8z" fill-opacity=".294"/><path d="M63.883 12.004a4 4 0 0 0-2.71 1.168l-30.829 30.83H16a4 4 0 0 0-4 4v32a4 4 0 0 0 4 4h14.344l30.828 30.828c2.52 2.518 6.827.734 6.828-2.828V16a4 4 0 0 0-4.117-3.996zM112 16a4 4 0 0 0-4 4v88a4 4 0 0 0 4 4 4 4 0 0 0 4-4V20a4 4 0 0 0-4-4zM88 40a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4 4 4 0 0 0 4-4V44a4 4 0 0 0-4-4z" fill="#f7f5cf"/></svg>
+<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M63.766 8a8 8 0 0 0-5.42 2.336L28.682 40H16a8 8 0 0 0-8 8v32a8 8 0 0 0 8 8h12.682l29.664 29.664A8 8 0 0 0 72 112V16a8 8 0 0 0-8.234-8zM112 12a8 8 0 0 0-8 8v88a8 8 0 0 0 16 0V20a8 8 0 0 0-8-8zM88 36a8 8 0 0 0-8 8v40a8 8 0 0 0 16 0V44a8 8 0 0 0-8-8z" fill-opacity=".294"/><path d="M63.883 12.004a4 4 0 0 0-2.71 1.168l-30.829 30.83H16a4 4 0 0 0-4 4v32a4 4 0 0 0 4 4h14.344l30.828 30.828c2.52 2.518 6.827.734 6.828-2.828V16a4 4 0 0 0-4.117-3.996zM112 16a4 4 0 0 0-4 4v88a4 4 0 0 0 4 4 4 4 0 0 0 4-4V20a4 4 0 0 0-4-4zM88 40a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4 4 4 0 0 0 4-4V44a4 4 0 0 0-4-4z" fill="#f7f5cf"/></svg>
diff --git a/editor/icons/GizmoAudioListener3D.svg b/editor/icons/GizmoAudioListener3D.svg
index 66a1f8fd5d..e84124f66b 100644
--- a/editor/icons/GizmoAudioListener3D.svg
+++ b/editor/icons/GizmoAudioListener3D.svg
@@ -1 +1 @@
-<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M48 3.96c-24.252 0-44 19.746-44 43.998a4 4 0 0 0 4 4h16a4 4 0 0 0 4-4A19.94 19.94 0 0 1 48 27.96a19.94 19.94 0 0 1 20 19.998c0 13.174-3.206 16.05-7.68 19.78-2.06 1.716-4.628 3.22-7.596 5.364-1.446 1.044-3.33 2.468-5.098 4.7C45.662 80.282 44 83.782 44 87.958c0 4.78-.634 7.372-1.22 8.64-.588 1.266-.942 1.46-1.956 2.066-1.1.66-5.032 1.29-8.824 1.29l-.04.002H24a4 4 0 0 0-4 4v16a4 4 0 0 0 4 4h8.042c3.812 0 12.62.394 21.132-4.712 8.02-4.812 13.326-14.546 14.348-27.184 1.624-1.096 4.69-2.994 8.16-5.886C83.686 79.504 92 67.094 92 47.958 92 23.706 72.252 3.96 48 3.96zm63.614 8.004a4 4 0 0 0-2.188.534l-13.906 8.03A4 4 0 0 0 94.06 26a43.992 43.992 0 0 1 5.944 21.96 43.99 43.99 0 0 1-5.928 21.976 4 4 0 0 0 1.462 5.47l13.89 8.014a4 4 0 0 0 5.464-1.466 68.01 68.01 0 0 0 0-67.996 4 4 0 0 0-3.278-1.996z" fill-opacity=".294"/><path d="M48 7.96A40 39.998 0 0 0 8 47.958h16A24 24 0 0 1 48 23.96a24 24 0 0 1 24 23.998c0 14-4.33 18.86-9.12 22.852-2.396 1.996-5.038 3.53-7.814 5.536-1.388 1-2.866 2.126-4.304 3.94C49.322 82.102 48 84.958 48 87.958c0 10.22-2.54 12.59-5.118 14.138-2.578 1.546-6.882 1.86-10.882 1.86h-8v16h8c4 0 11.696.31 19.116-4.14 7.06-4.238 12.2-13.28 12.696-26 .184-.166.148-.156.62-.498 1.724-1.244 5.084-3.21 8.688-6.214C80.33 77.096 88 65.958 88 47.958A40 39.998 0 0 0 48 7.96zm63.426 8L97.52 23.992a48 47.998 0 0 1 6.484 23.966 48 47.998 0 0 1-6.468 23.984l13.89 8.014a64 63.996 0 0 0 0-63.996z" fill="#f7f5cf"/></svg>
+<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M48 4A44 44 0 0 0 4 48a4 4 0 0 0 4 4h16a4 4 0 0 0 4-4 20 20 0 0 1 40 0c0 13.174-3.206 16.05-7.68 19.78-2.06 1.716-4.628 3.22-7.596 5.364-1.446 1.044-3.33 2.468-5.098 4.7C45.662 80.282 44 83.782 44 87.958c0 4.78-.634 7.372-1.22 8.64-.588 1.266-.942 1.46-1.956 2.066-1.1.66-5.032 1.29-8.824 1.29l-.04.002H24a4 4 0 0 0-4 4v16a4 4 0 0 0 4 4h8.042c3.812 0 12.62.394 21.132-4.712 8.02-4.812 13.326-14.546 14.348-27.184 1.624-1.096 4.69-2.994 8.16-5.886C83.686 79.504 92 67.094 92 47.958a44 44 0 0 0-44-44zm63.614 8.004a4 4 0 0 0-2.188.534l-13.906 8.03A4 4 0 0 0 94.06 26a44 44 0 0 1 .016 43.936 4 4 0 0 0 1.462 5.47l13.89 8.014a4 4 0 0 0 5.464-1.466 68 68 0 0 0 0-68 4 4 0 0 0-3.278-2z" fill-opacity=".294"/><path d="M48 8A40 40 0 0 0 8 48h16a24 24 0 0 1 48 0c0 14-4.33 18.86-9.12 22.852-2.396 1.996-5.038 3.53-7.814 5.536-1.388 1-2.866 2.126-4.304 3.94-1.44 1.774-2.762 4.63-2.762 7.63 0 10.22-2.54 12.59-5.118 14.138-2.578 1.546-6.882 1.86-10.882 1.86h-8v16h8c4 0 11.696.31 19.116-4.14 7.06-4.238 12.2-13.28 12.696-26 .184-.166.148-.156.62-.498 1.724-1.244 5.084-3.21 8.688-6.214C80.33 77.096 88 65.958 88 47.958A40 40 0 0 0 48 8zm63.426 8L97.52 24a48 48 0 0 1 .016 47.942l13.89 8a64 64 0 0 0 0-64z" fill="#f7f5cf"/></svg>
diff --git a/editor/icons/GizmoCPUParticles3D.svg b/editor/icons/GizmoCPUParticles3D.svg
index 391c126c28..3dae7ade80 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="M35.504 1.282c-3.57 0-6.435 2.948-6.435 6.602v4.39c0 .889.17 1.726.478 2.499H19.465c-3.57 0-6.435 2.931-6.435 6.585v7.97c-.341-.057-.649-.203-1.006-.203h-4.29c-3.57 0-6.452 2.948-6.452 6.602v3.225c0 3.653 2.881 6.585 6.452 6.585h4.29c.358 0 .664-.146 1.006-.203v38.497c-.341-.057-.649-.203-1.006-.203h-4.29c-3.57 0-6.452 2.949-6.452 6.602v3.225c0 3.654 2.881 6.585 6.452 6.585h4.29c.358 0 .664-.145 1.006-.202v9.725c0 3.654 2.865 6.602 6.435 6.602h9.604v3.951c0 3.654 2.864 6.602 6.435 6.602h3.151c3.57 0 6.452-2.948 6.452-6.602v-3.95h37.225v3.95c0 3.654 2.865 6.602 6.435 6.602h3.152c3.57 0 6.451-2.948 6.451-6.602v-3.95h10.726c3.57 0 6.451-2.95 6.451-6.603v-9.607c.15.01.277.084.43.084h4.29c3.57 0 6.451-2.931 6.451-6.585V90.23c0-3.653-2.881-6.601-6.452-6.601h-4.29c-.152 0-.28.073-.429.084v-38.26c.15.01.277.084.43.084h4.29c3.57 0 6.451-2.932 6.451-6.585v-3.225c0-3.654-2.881-6.602-6.452-6.602h-4.29c-.152 0-.28.074-.429.084v-7.851c0-3.654-2.88-6.585-6.451-6.585h-11.22a6.7 6.7 0 0 0 .494-2.5v-4.39c0-3.653-2.88-6.601-6.451-6.601h-3.152c-3.57 0-6.435 2.948-6.435 6.602v4.39c0 .889.17 1.726.478 2.499H44.612c.31-.773.495-1.61.495-2.5v-4.39c0-3.653-2.881-6.601-6.452-6.601z" fill="#f7f5cf" stroke="#b3b3b3" stroke-width="2.564"/><path d="M62.861 21.662a27.707 31.503 0 0 1 27.144 25.411 18.472 18.902 0 0 1 15.956 18.691 18.472 18.902 0 0 1-18.48 18.894H38.225a18.472 18.902 0 0 1-18.464-18.894 18.472 18.902 0 0 1 15.923-18.708A27.707 31.503 0 0 1 62.86 21.662zM38.226 90.956a6.157 6.3 0 0 1 6.155 6.298 6.157 6.3 0 0 1-6.155 6.315 6.157 6.3 0 0 1-6.154-6.315 6.157 6.3 0 0 1 6.154-6.298zm49.254 0a6.157 6.3 0 0 1 6.171 6.298 6.157 6.3 0 0 1-6.17 6.315 6.157 6.3 0 0 1-6.156-6.315 6.157 6.3 0 0 1 6.155-6.298zm-24.619 6.298a6.157 6.3 0 0 1 6.155 6.315 6.157 6.3 0 0 1-6.155 6.298 6.157 6.3 0 0 1-6.154-6.298 6.157 6.3 0 0 1 6.154-6.315z" 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" 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>
diff --git a/editor/icons/GizmoDirectionalLight.svg b/editor/icons/GizmoDirectionalLight.svg
index c736e86dee..c913e649f7 100644
--- a/editor/icons/GizmoDirectionalLight.svg
+++ b/editor/icons/GizmoDirectionalLight.svg
@@ -1 +1 @@
-<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M64 4c-4.432 0-8 3.568-8 8v16c0 4.432 3.568 8 8 8s8-3.568 8-8V12c0-4.432-3.568-8-8-8zM27.23 19.223c-2.045 0-4.09.785-5.656 2.352a7.98 7.98 0 0 0 0 11.312L32.886 44.2c3.134 3.134 8.18 3.134 11.314 0s3.134-8.181 0-11.314L32.886 21.575a7.975 7.975 0 0 0-5.656-2.352zm73.539 0c-2.045 0-4.09.785-5.656 2.352L83.799 32.887c-3.134 3.134-3.134 8.18 0 11.314s8.18 3.134 11.314 0l11.312-11.314a7.98 7.98 0 0 0 0-11.312 7.975 7.975 0 0 0-5.656-2.352zM63.999 40a24 24 0 0 0-24 24 24 24 0 0 0 24 24 24 24 0 0 0 24-24 24 24 0 0 0-24-24zm-52 16c-4.432 0-8 3.568-8 8s3.568 8 8 8h16c4.432 0 8-3.568 8-8s-3.568-8-8-8zm88 0c-4.432 0-8 3.568-8 8s3.568 8 8 8h16c4.432 0 8-3.568 8-8s-3.568-8-8-8zM38.544 81.449a7.977 7.977 0 0 0-5.658 2.35L21.574 95.113a7.98 7.98 0 0 0 0 11.312 7.98 7.98 0 0 0 11.312 0L44.2 95.113a7.983 7.983 0 0 0 0-11.314 7.973 7.973 0 0 0-5.656-2.35zm50.91 0a7.97 7.97 0 0 0-5.656 2.35 7.983 7.983 0 0 0 0 11.314l11.314 11.312c3.134 3.133 8.178 3.133 11.312 0s3.134-8.179 0-11.312L95.112 83.799a7.977 7.977 0 0 0-5.658-2.35zM63.999 92c-4.432 0-8 3.568-8 8v16c0 4.432 3.568 8 8 8s8-3.568 8-8v-16c0-4.432-3.568-8-8-8z" fill-opacity=".294"/><path d="M64 8c-2.216 0-4 1.784-4 4v16c0 2.216 1.784 4 4 4s4-1.784 4-4V12c0-2.216-1.784-4-4-4zM27.23 23.227a3.987 3.987 0 0 0-2.828 1.176 3.99 3.99 0 0 0 0 5.656l11.312 11.314c1.567 1.567 4.091 1.567 5.658 0s1.567-4.091 0-5.658L30.058 24.403a3.987 3.987 0 0 0-2.828-1.176zm73.539 0a3.987 3.987 0 0 0-2.828 1.176L86.627 35.715c-1.567 1.567-1.567 4.091 0 5.658s4.091 1.567 5.658 0l11.313-11.314a3.99 3.99 0 0 0 0-5.656 3.987 3.987 0 0 0-2.828-1.176zM63.999 44c-11.046 0-20 8.954-20 20s8.954 20 20 20 20-8.954 20-20-8.954-20-20-20zm-52 16c-2.216 0-4 1.784-4 4s1.784 4 4 4h16c2.216 0 4-1.784 4-4s-1.784-4-4-4zm88 0c-2.216 0-4 1.784-4 4s1.784 4 4 4h16c2.216 0 4-1.784 4-4s-1.784-4-4-4zM38.544 85.453a3.99 3.99 0 0 0-2.83 1.174L24.402 97.94a3.99 3.99 0 0 0 0 5.656 3.99 3.99 0 0 0 5.656 0l11.314-11.313a3.993 3.993 0 0 0 0-5.658 3.985 3.985 0 0 0-2.828-1.174zm50.91 0c-1.022 0-2.045.39-2.828 1.174a3.993 3.993 0 0 0 0 5.658l11.314 11.313a3.99 3.99 0 0 0 5.656 0 3.99 3.99 0 0 0 0-5.656L92.283 86.628a3.99 3.99 0 0 0-2.83-1.174zM63.999 96c-2.216 0-4 1.784-4 4v16c0 2.216 1.784 4 4 4s4-1.784 4-4v-16c0-2.216-1.784-4-4-4z" fill="#fff"/></svg>
+<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M64 4a8 8 0 0 0-8 8v16a8 8 0 0 0 16 0V12a8 8 0 0 0-8-8zM27.23 19.223a8 8 0 0 0-5.656 13.664L32.886 44.2A8 8 0 0 0 44.2 32.886L32.886 21.575a7.975 7.975 0 0 0-5.656-2.352zm73.539 0a8 8 0 0 0-5.656 2.352L83.799 32.887a8 8 0 0 0 11.314 11.314l11.312-11.314a8 8 0 0 0-5.656-13.664zM64 40a24 24 0 0 0 0 48 24 24 0 0 0 0-48zM12 56a8 8 0 0 0 0 16h16a8 8 0 0 0 0-16zm88 0a8 8 0 0 0 0 16h16a8 8 0 0 0 0-16zM38.544 81.449a8 8 0 0 0-5.658 2.35L21.574 95.113a7.98 7.98 0 0 0 11.312 11.312L44.2 95.113a8 8 0 0 0-5.656-13.664zm50.91 0a8 8 0 0 0-5.656 13.664l11.314 11.312a8 8 0 0 0 11.312-11.312L95.112 83.799a8 8 0 0 0-5.658-2.35zM64 92a8 8 0 0 0-8 8v16a8 8 0 0 0 15.999 0v-16a8 8 0 0 0-8-8z" fill-opacity=".294"/><path d="M64 8a4 4 0 0 0-4 4v16a4 4 0 0 0 8 0V12a4 4 0 0 0-4-4zM27.23 23.227a4 4 0 0 0-2.828 6.832l11.312 11.314a4 4 0 0 0 5.658-5.658L30.058 24.403a4 4 0 0 0-2.828-1.176zm73.539 0a4 4 0 0 0-2.828 1.176L86.627 35.715a4 4 0 0 0 5.658 5.658l11.313-11.314a4 4 0 0 0-2.828-6.832zM64 44a20 20 0 0 0 0 40 20 20 0 0 0 0-40zM12 60a4 4 0 0 0 0 8h16a4 4 0 0 0 0-8zm88 0a1 1 0 0 0 0 8h16a1 1 0 0 0 0-8zM38.544 85.453a4 4 0 0 0-2.83 1.174L24.402 97.94a4 4 0 0 0 5.656 5.656l11.314-11.313a4 4 0 0 0-2.828-6.832zm50.91 0a4 4 0 0 0-2.828 6.832l11.314 11.313a4 4 0 0 0 5.656-5.656L92.283 86.628a4 4 0 0 0-2.83-1.174zM64 96a4 4 0 0 0-4 4v16a4 4 0 0 0 8 0v-16a4 4 0 0 0-4-4z" fill="#fff"/></svg>
diff --git a/editor/icons/GizmoSpotLight.svg b/editor/icons/GizmoSpotLight.svg
index c943ed7a7b..3c986aedd4 100644
--- a/editor/icons/GizmoSpotLight.svg
+++ b/editor/icons/GizmoSpotLight.svg
@@ -1 +1 @@
-<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M52 4c-6.579 0-12 5.421-12 12v26.625c-12.263 7.282-19.978 19.75-20 33.369L19.994 80h28.578C50.372 86.863 56.6 92 64 92s13.628-5.137 15.428-12h28.576L108 75.996c-.015-13.625-7.732-26.099-20-33.385V16c0-6.579-5.42-12-12-12zM40.311 82.016a8.033 8.033 0 0 0-4.559 1.055l-10.393 6c-3.778 2.181-5.111 7.15-2.93 10.93 2.182 3.778 7.151 5.111 10.93 2.93l10.394-6c3.78-2.183 5.108-7.153 2.927-10.93a8.033 8.033 0 0 0-6.369-3.985zm47.379 0A8.032 8.032 0 0 0 81.32 86c-2.18 3.778-.851 8.748 2.929 10.93l10.393 6c3.779 2.182 8.748.85 10.93-2.93 2.182-3.779.849-8.747-2.93-10.93l-10.393-6a8.033 8.033 0 0 0-4.559-1.054zM64.001 96c-4.363 0-8 3.637-8 8v12c0 4.363 3.637 8 8 8s8-3.637 8-8v-12c0-4.363-3.637-8-8-8z" fill-opacity=".294"/><path d="M52 8c-4.432 0-8 3.568-8 8v28.875A40 36 0 0 0 24 76h28a12 12 0 0 0 12 12 12 12 0 0 0 12-12h28a40 36 0 0 0-20-31.141V16c0-4.432-3.568-8-8-8zM40.031 86.006a3.987 3.987 0 0 0-2.28.53l-10.392 6c-1.92 1.107-2.573 3.545-1.465 5.464s3.546 2.573 5.465 1.465l10.393-6A3.992 3.992 0 0 0 43.215 88a3.99 3.99 0 0 0-3.184-1.994zm47.938 0A3.99 3.99 0 0 0 84.785 88a3.992 3.992 0 0 0 1.463 5.465l10.393 6c1.92 1.108 4.357.454 5.465-1.465s.454-4.357-1.465-5.465l-10.393-6a3.987 3.987 0 0 0-2.279-.529zM64 100c-2.216 0-4 1.784-4 4v12c0 2.216 1.784 4 4 4s4-1.784 4-4v-12c0-2.216-1.784-4-4-4z" fill="#fff"/></svg>
+<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M52 4a12 12 0 0 0-12 12v26.625A38 38 0 0 0 20 76v4h28.578a16 16 0 0 0 30.856 0H108v-4a38 38 0 0 0-20-33.385V16A12 12 0 0 0 76 4zM40.311 82a8 8 0 0 0-4.559 1.055l-10.393 6a8 8 0 0 0 8 13.86l10.394-6A8 8 0 0 0 40.311 82zm47.379 0a8 8 0 0 0-3.441 14.93l10.393 6a8 8 0 0 0 8-13.86l-10.393-6a8 8 0 0 0-4.559-1.054zM64 96a8 8 0 0 0-8 8v12a8 8 0 0 0 16 0v-12a8 8 0 0 0-8-8z" fill-opacity=".294"/><path d="M52 8a8 8 0 0 0-8 8v28.875A40 36 0 0 0 24 76h28a12 12 0 0 0 24 0h28a40 36 0 0 0-20-31.141V16a8 8 0 0 0-8-8zM40.031 86a4 4 0 0 0-2.28.53l-10.392 6a4 4 0 0 0 4 6.929l10.393-6a4 4 0 0 0-1.721-7.453zm47.938 0a4 4 0 0 0-1.721 7.465l10.393 6a4 4 0 0 0 4-6.93l-10.393-6a4 4 0 0 0-2.279-.529zM64 100a4 4 0 0 0-4 4v12a4 4 0 0 0 8 0v-12a4 4 0 0 0-4-4z" fill="#fff"/></svg>
diff --git a/editor/icons/GizmoVoxelGI.svg b/editor/icons/GizmoVoxelGI.svg
index 92e84bc67e..b4aa912663 100644
--- a/editor/icons/GizmoVoxelGI.svg
+++ b/editor/icons/GizmoVoxelGI.svg
@@ -1 +1 @@
-<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M12 4a8 8 0 0 0-8 8v104a8 8 0 0 0 8 8h64v-16H20V20h88v7.768A36 36 0 0 0 92 24a36 36 0 0 0-36 36 36 36 0 0 0 16 29.9V98a9.977 9.977 0 0 0 8 9.8V124h24v-16.2a9.977 9.977 0 0 0 8-9.8v-8.088A36 36 0 0 0 128 60a36 36 0 0 0-19.523-32H124V12a8 8 0 0 0-8-8H12zm28.25 17.996A7.984 7.984 0 0 0 33.11 26a7.983 7.983 0 0 0 2.93 10.928l10.392 6c3.838 2.216 8.712.91 10.928-2.928s.91-8.712-2.928-10.928l-10.393-6a7.99 7.99 0 0 0-3.789-1.076zM92 44a16 16 0 0 1 16 16 16 16 0 0 1-16 16 16 16 0 0 1-16-16 16 16 0 0 1 16-16zm-60 8c-4.432 0-8 3.568-8 8s3.568 8 8 8h12c4.432 0 8-3.568 8-8s-3.568-8-8-8zm18.221 23.996a7.991 7.991 0 0 0-3.79 1.076l-10.392 6c-3.838 2.216-5.146 7.09-2.93 10.928s7.092 5.144 10.93 2.928l10.393-6A7.982 7.982 0 0 0 57.36 80a7.98 7.98 0 0 0-7.139-4.004z" fill-opacity=".294"/><path d="M12 8a4 4 0 0 0-4 4v104a4 4 0 0 0 4 4h60v-8H16V16h96v8h8V12a4 4 0 0 0-4-4zm27.715 17.951a3.843 3.843 0 0 0-3.066 1.92l-.149.258a3.844 3.844 0 0 0 1.41 5.261l10.648 6.149a3.844 3.844 0 0 0 5.262-1.41l.149-.258a3.844 3.844 0 0 0-1.41-5.262L41.91 26.461a3.84 3.84 0 0 0-2.195-.51zM92 28a32 32 0 0 0-32 32 32 32 0 0 0 16 27.668V96c0 4.432 3.568 8 8 8h16c4.432 0 8-3.568 8-8v-8.323A32 32 0 0 0 124 60a32 32 0 0 0-32-32zm0 12a20 20 0 0 1 20 20 20 20 0 0 1-20 20 20 20 0 0 1-20-20 20 20 0 0 1 20-20zM31.852 56A3.843 3.843 0 0 0 28 59.85v.297A3.843 3.843 0 0 0 31.852 64h12.297a3.843 3.843 0 0 0 3.852-3.852v-.297A3.843 3.843 0 0 0 44.149 56zm18.902 23.95a3.84 3.84 0 0 0-2.195.51L37.91 86.61a3.844 3.844 0 0 0-1.41 5.262l.148.257a3.844 3.844 0 0 0 5.262 1.41l10.648-6.148a3.844 3.844 0 0 0 1.41-5.261l-.149-.258a3.842 3.842 0 0 0-3.066-1.92zM84 112v8h16v-8z" fill="#f7f5cf"/></svg>
+<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M12 4a8 8 0 0 0-8 8v104a8 8 0 0 0 8 8h64v-16H20V20h88v7.768A36 36 0 0 0 72 89.9V98a9.977 9.977 0 0 0 8 9.8V124h24v-16.2a9.977 9.977 0 0 0 8-9.8v-8.088A36 36 0 0 0 108.477 28H124V12a8 8 0 0 0-8-8H12zm28.25 18a8 8 0 0 0-4.21 14.928l10.392 6a8 8 0 0 0 8-13.856l-10.393-6a8 8 0 0 0-3.789-1.076zM92 44a16 16 0 0 1 0 32 16 16 0 0 1 0-32zm-60 8a8 8 0 0 0 0 16h12a8 8 0 0 0 0-16zm18.221 24a8 8 0 0 0-3.79 1.076l-10.392 6a8 8 0 0 0 8 13.856l10.393-6a8 8 0 0 0-4.211-14.936z" fill-opacity=".294"/><path d="M12 8a4 4 0 0 0-4 4v104a4 4 0 0 0 4 4h60v-8H16V16h96v8h8V12a4 4 0 0 0-4-4zm27.715 17.951a3.843 3.843 0 0 0-3.066 1.92l-.149.258a3.844 3.844 0 0 0 1.41 5.261l10.648 6.149a3.844 3.844 0 0 0 5.262-1.41l.149-.258a3.844 3.844 0 0 0-1.41-5.262L41.91 26.461a3.84 3.84 0 0 0-2.195-.51zM92 28a32 32 0 0 0-32 32 32 32 0 0 0 16 27.668V96a8 8 0 0 0 8 8h16a8 8 0 0 0 8-8v-8.323A32 32 0 0 0 124 60a32 32 0 0 0-32-32zm0 12a20 20 0 0 1 0 40 20 20 0 0 1 0-40zM31.852 56a4 4 0 0 0 0 8h12.297a4 4 0 0 0 0-8zm18.902 23.95a4 4 0 0 0-2.195.51L37.91 86.61a4 4 0 0 0 3.852 6.672l10.648-6.148a4 4 0 0 0-1.656-7.181zM84 112v8h16v-8z" fill="#f7f5cf"/></svg>
diff --git a/editor/icons/GridToggle.svg b/editor/icons/GridToggle.svg
new file mode 100644
index 0000000000..595952c3af
--- /dev/null
+++ b/editor/icons/GridToggle.svg
@@ -0,0 +1 @@
+<svg viewBox="0 0 16 16" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 0v2H0v1h2v4H0v1h2v4H0v1h2v2h1v-2h3.125A5.5 5 0 016 12H3V8h4v1.143a5.5 5 0 011-.99V8h.223A5.5 5 0 0111.5 7H8V3h4v4h-.5a5.5 5 0 013.297 1H15V7h-2V3h2V2h-2V0h-1v2H8V0H7v2H3V0H2zm1 3h4v4H3V3zm4 11.857V15h.117A5.5 5 0 017 14.857z" fill="#e0e0e0"/><path d="M11.485 8.261c-1.648 0-3.734 1.256-4.485 3.68a.645.645 0 00-.004.367C7.721 14.846 9.873 16 11.486 16c1.612 0 3.764-1.154 4.489-3.692a.645.645 0 000-.356c-.71-2.443-2.842-3.691-4.49-3.691zm0 1.29a2.58 2.58 0 012.58 2.58 2.58 2.58 0 01-2.58 2.58 2.58 2.58 0 01-2.58-2.58 2.58 2.58 0 012.58-2.58zm0 1.29a1.29 1.29 0 00-1.29 1.29 1.29 1.29 0 001.29 1.29 1.29 1.29 0 001.29-1.29 1.29 1.29 0 00-1.29-1.29z" fill="#e0e0e0" /></svg>
diff --git a/editor/icons/GuiGraphNodePort.svg b/editor/icons/GuiGraphNodePort.svg
index d04dabcfc3..04645d97b7 100644
--- a/editor/icons/GuiGraphNodePort.svg
+++ b/editor/icons/GuiGraphNodePort.svg
@@ -1 +1 @@
-<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><circle cx="5" cy="5" fill="#fff" r="5"/></svg>
+<svg height="24" width="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" fill="#fff" r="10"/></svg>
diff --git a/editor/icons/GuiIndeterminate.svg b/editor/icons/GuiIndeterminate.svg
index 2174686f7a..ce4b204fdd 100644
--- a/editor/icons/GuiIndeterminate.svg
+++ b/editor/icons/GuiIndeterminate.svg
@@ -1 +1 @@
-<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M3.333 1A2.334 2.334 0 0 0 1 3.333v9.334A2.334 2.334 0 0 0 3.333 15h9.334A2.334 2.334 0 0 0 15 12.667V3.333A2.334 2.334 0 0 0 12.667 1z" fill="#699ce8"/><path d="M3 7h10v2H3z" fill="#fff"/></svg>
+<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="1" rx="2.33" height="14" width="14" fill="#699ce8"/><path d="M3 7h10v2H3z" fill="#fff"/></svg>
diff --git a/editor/icons/GuiSpinboxUpdown.svg b/editor/icons/GuiSpinboxUpdown.svg
index 5bfa6a1c09..70cfec1988 100644
--- a/editor/icons/GuiSpinboxUpdown.svg
+++ b/editor/icons/GuiSpinboxUpdown.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9844 1.002a1.0001 1.0001 0 0 0 -.69141.29102l-4 4a1.0001 1.0001 0 1 0 1.4141 1.4141l3.293-3.293 3.293 3.293a1.0001 1.0001 0 1 0 1.4141-1.4141l-4-4a1.0001 1.0001 0 0 0 -.72266-.29102zm4.0059 7.9844a1.0001 1.0001 0 0 0 -.69726.30664l-3.293 3.293-3.293-3.293a1.0001 1.0001 0 0 0 -.7168-.30273 1.0001 1.0001 0 0 0 -.69727 1.7168l4 4a1.0001 1.0001 0 0 0 1.4141 0l4-4a1.0001 1.0001 0 0 0 -.7168-1.7207z" fill="#e0e0e0" fill-opacity=".78431"/></svg>
+<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m4 6 4-4 4 4m0 4-4 4-4-4" fill="none" stroke="#e0e0e0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".784"/></svg>
diff --git a/editor/icons/GuiSpinboxUpdownDisabled.svg b/editor/icons/GuiSpinboxUpdownDisabled.svg
index 332c5e7bf8..6868a6f6ff 100644
--- a/editor/icons/GuiSpinboxUpdownDisabled.svg
+++ b/editor/icons/GuiSpinboxUpdownDisabled.svg
@@ -1 +1 @@
-<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.984 1.002c-.259.004-.507.108-.691.291l-4 4c-.398.383-.41 1.016-.027 1.414s1.016.41 1.414.027l.027-.027 3.293-3.293 3.293 3.293c.383.398 1.016.41 1.414.027s.41-1.016.027-1.414c-.01-.009-.018-.018-.027-.027l-4-4c-.191-.19-.452-.296-.723-.291zm4.006 7.984c-.264.006-.514.117-.697.307l-3.293 3.293-3.293-3.293c-.188-.193-.447-.303-.717-.303-.552 0-1 .448-1 1 0 .271.109.529.303.717l4 4c.391.391 1.023.391 1.414 0l4-4c.398-.383.41-1.016.027-1.414-.193-.202-.463-.313-.744-.307z" fill="#b3b3b3" fill-opacity=".7843"/></svg>
+<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m4 6 4-4 4 4m0 4-4 4-4-4" fill="none" stroke="#b3b3b3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".784"/></svg>
diff --git a/editor/icons/GuiTabMenu.svg b/editor/icons/GuiTabMenu.svg
index e031054f81..c4346ed8fb 100644
--- a/editor/icons/GuiTabMenu.svg
+++ b/editor/icons/GuiTabMenu.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m 8 0 A 2 2 0 0 0 8 4 A 2 2 0 0 0 8 0 z m 0 6 A 2 2 0 0 0 8 10 A 2 2 0 0 0 8 6 z m 0 6 A 2 2 0 0 0 8 16 A 2 2 0 0 0 8 12 z" fill="#e0e0e0" fill-opacity=".39216"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 0a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4z" fill="#e0e0e0" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/GuiTabMenuHl.svg b/editor/icons/GuiTabMenuHl.svg
index fa5b060a9b..c6d28dfa56 100644
--- a/editor/icons/GuiTabMenuHl.svg
+++ b/editor/icons/GuiTabMenuHl.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m 8 0 A 2 2 0 0 0 8 4 A 2 2 0 0 0 8 0 z m 0 6 A 2 2 0 0 0 8 10 A 2 2 0 0 0 8 6 z m 0 6 A 2 2 0 0 0 8 16 A 2 2 0 0 0 8 12 z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 0a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/GuiVisibilityHidden.svg b/editor/icons/GuiVisibilityHidden.svg
index ed164ea8c0..3a5c959b1d 100644
--- a/editor/icons/GuiVisibilityHidden.svg
+++ b/editor/icons/GuiVisibilityHidden.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.9609 7.7266-1.9219.54883c.31999 1.12.8236 2.0593 1.4316 2.8398l-.83398.83398 1.4141 1.4141.84375-.84375c.98585.74762 2.0766 1.2067 3.1055 1.3867v1.0938h2v-1.0938c1.0288-.17998 2.1196-.6391 3.1055-1.3867l.84375.84375 1.4141-1.4141-.83398-.83398c.60804-.78055 1.1117-1.7199 1.4316-2.8398l-1.9219-.54883c-.8756 3.0646-3.5391 4.2734-5.0391 4.2734s-4.1635-1.2088-5.0391-4.2734z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.96 7.727-1.921.548c.32 1.12.824 2.06 1.432 2.84l-.834.834 1.414 1.414.843-.843c.986.747 2.077 1.206 3.106 1.386V15h2v-1.094c1.029-.18 2.12-.639 3.105-1.386l.844.843 1.414-1.414-.834-.834a8.285 8.285 0 0 0 1.432-2.84l-1.922-.548C12.163 10.79 9.499 12 7.999 12s-4.163-1.209-5.038-4.273z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/HSlider.svg b/editor/icons/HSlider.svg
index c876afa843..a583dfe3f2 100644
--- a/editor/icons/HSlider.svg
+++ b/editor/icons/HSlider.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 3c-.55228 0-1 .44772-1 1v2c0 .55228.44772 1 1 1s1-.44772 1-1v-2c0-.55228-.44772-1-1-1zm12 0c-.55228 0-1 .44772-1 1v2c0 .55228.44772 1 1 1s1-.44772 1-1v-2c0-.55228-.44772-1-1-1zm-6 1c-.55228 0-1 .44772-1 1s.44772 1 1 1 1-.44772 1-1-.44772-1-1-1zm5 5c-1.1046 0-2 .89543-2 2 0 1.1046.89543 2 2 2 1.0099-.000337 1.8611-.75351 1.9844-1.7559.04003-.16104.03936-.32952-.002-.49024-.12404-1.0008-.97388-1.7527-1.9824-1.7539zm-11 1c-1.3523-.019125-1.3523 2.0191 0 2h7.1309c-.085635-.32648-.1296-.66248-.13086-1 .00189-.3376.046518-.67361.13281-1z" fill="#8eef97"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1 11a2 2 0 0 0 4 0 2 2 0 0 0-4 0zm0-5a1 1 0 0 0 2 0V4a1 1 0 0 0-2 0zm5.867 4a4 4 0 0 1 0 2h7.13a1 1 0 0 0 0-2zM7 5a1 1 0 1 0 2 0 1 1 0 0 0-2 0zm6 1a1 1 0 0 0 2 0V4a1 1 0 0 0-2 0z" fill="#8eef97"/></svg>
diff --git a/editor/icons/Heart.svg b/editor/icons/Heart.svg
index 00edf90729..c4b21b6e43 100644
--- a/editor/icons/Heart.svg
+++ b/editor/icons/Heart.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 14c-.1249999 0-.25-.046875-.34375-.140625l-4.875-4.703125c-.0625-.054687-1.7812496-1.6249999-1.7812496-3.5 0-2.2890626 1.3984372-3.6562499 3.7343748-3.6562499 1.3671873 0 2.6484373 1.390625 3.2656248 1.9999999.6171875-.6093749 1.8984375-1.9999999 3.265625-1.9999999 2.335938 0 3.734375 1.3671873 3.734375 3.6562499 0 1.8750001-1.71875 3.4453125-1.789062 3.5156251l-4.867188 4.6874999c-.09375.09375-.2187499.140625-.34375.140625z" fill="#fc7f7f"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 14a.485.485 0 0 1-.344-.14L2.781 9.155C2.72 9.102 1 7.531 1 5.656 1 3.367 2.398 2 4.734 2 6.102 2 7.383 3.39 8 4c.617-.61 1.898-2 3.266-2C13.602 2 15 3.367 15 5.656c0 1.875-1.719 3.446-1.79 3.516l-4.866 4.687A.485.485 0 0 1 8 14z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/Help.svg b/editor/icons/Help.svg
index b2a52e8ad9..ecb9d3e359 100644
--- a/editor/icons/Help.svg
+++ b/editor/icons/Help.svg
@@ -1 +1 @@
-<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M5.029 1C4.03.989 3.02 1.312 2 2v7c2.017-1.353 4.017-1.314 6 0 1.983-1.314 3.983-1.353 6 0V2c-1.02-.688-2.03-1.011-3.029-1-.662.007-1.318.173-1.971.463V6H8V2c-.982-.645-1.971-.989-2.971-1zM0 10v6h2a3 3 0 0 0 0-6zm5 3a3 3 0 0 0 6 0 3 3 0 0 0-6 0zm9 3h1v-2h-1a1 1 0 0 1 0-2h1v-2h-1a3 3 0 0 0 0 6zM2 12a1 1 0 0 1 0 2zm6 0a1 1 0 0 1 0 2 1 1 0 0 1 0-2z" fill="#e0e0e0" fill-opacity=".59"/></svg>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M8 2C6 .7 4 .7 2 2v7c2-1.3 4-1.3 6 0 2-1.3 4-1.3 6 0V2C12 .7 10.2.9 9 1.5V6H8zm-8 8v6h2a3 3 0 0 0 0-6zm5 3a3 3 0 0 0 6 0 3 3 0 0 0-6 0zm9 3h1v-2h-1a1 1 0 0 1 0-2h1v-2h-1a3 3 0 0 0 0 6zM2 12a1 1 0 0 1 0 2zm6 0a1 1 0 0 1 0 2 1 1 0 0 1 0-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/IOSDeviceWired.svg b/editor/icons/IOSDeviceWired.svg
new file mode 100644
index 0000000000..15bb0b4523
--- /dev/null
+++ b/editor/icons/IOSDeviceWired.svg
@@ -0,0 +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>
diff --git a/editor/icons/IOSDeviceWireless.svg b/editor/icons/IOSDeviceWireless.svg
new file mode 100644
index 0000000000..91fc679460
--- /dev/null
+++ b/editor/icons/IOSDeviceWireless.svg
@@ -0,0 +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>
diff --git a/editor/icons/IOSSimulator.svg b/editor/icons/IOSSimulator.svg
new file mode 100644
index 0000000000..59ab11a8a5
--- /dev/null
+++ b/editor/icons/IOSSimulator.svg
@@ -0,0 +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>
diff --git a/editor/icons/Info.svg b/editor/icons/Info.svg
new file mode 100644
index 0000000000..1a16f74069
--- /dev/null
+++ b/editor/icons/Info.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M8 1a7 7 0 0 0 0 14A7 7 0 0 0 8 1m1 12H7v-2h2v2M4.5 6a3.5 3.4 0 1 1 7 0C11.3 8.9 9 8.5 9 10H7c.1-2.6 2.4-2.8 2.5-4a1.5 1.4 0 0 0-3 0z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/KeyInvalid.svg b/editor/icons/KeyInvalid.svg
index fce600e6f0..519f25513f 100644
--- a/editor/icons/KeyInvalid.svg
+++ b/editor/icons/KeyInvalid.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg"><path d="M.464 1.879 2.586 4 .464 6.122 1.88 7.536 4 5.414l2.121 2.122 1.414-1.414L5.415 4l2.119-2.121L6.121.465 4 2.586 1.879.465.464 1.879z" fill="#ff5f5f"/></svg>
+<svg height="8" viewBox="0 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg"><path d="M.464 1.879 2.585 4 .464 6.121l1.414 1.414 2.121-2.121L6.12 7.535l1.414-1.414L5.413 4l2.121-2.121L6.12.465 3.999 2.586 1.878.465z" fill="#ff5f5f"/></svg>
diff --git a/editor/icons/KeyPosition.svg b/editor/icons/KeyPosition.svg
index c0fa703462..37ba41f996 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 1c-.195 0-.38964.07519-.53906.22461l-3.2363 3.2363c-.29884.29884-.29884.77929 0 1.0781l3.2363 3.2363c.29884.29884.77929.29884 1.0781 0l3.2363-3.2363c.29884-.29884.29884-.77929 0-1.0781l-3.2363-3.2363c-.14942-.14942-.34406-.22461-.53906-.22461zm-7 7v5c0 1.6569 1.3471 3.114 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1v-5zm7 2c-1.645 0-3 1.355-3 3s1.355 3 3 3 3-1.355 3-3-1.355-3-3-3zm3 3c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1 .00001-.55228.44772-.99999 1-1h1v-2h-1c-1.6569 0-3 1.3431-3 3zm-3-1c.56413 0 1 .4359 1 1 0 .5642-.43587 1-1 1s-1-.4358-1-1c0-.5641.43587-1 1-1z" fill="#e0e0e0"/></svg>
+<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>
diff --git a/editor/icons/KeyScale.svg b/editor/icons/KeyScale.svg
index 5caf80e68e..c7b55028ab 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 1c-.195 0-.38964.07519-.53906.22461l-3.2363 3.2363c-.29884.29884-.29884.77929 0 1.0781l3.2363 3.2363c.29884.29884.77929.29884 1.0781 0l3.2363-3.2363c.29884-.29884.29884-.77929 0-1.0781l-3.2363-3.2363c-.14942-.14942-.34406-.22461-.53906-.22461zm3 7v5c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1v-5zm-8 2c-.71466-.0001-1.3751.3811-1.7324 1-.35727.6188-.35727 1.3812 0 2 .35733.6189 1.0178 1.0001 1.7324 1h-2v2h2c.71466.0001 1.3751-.3811 1.7324-1 .35727-.6188.35727-1.3812 0-2-.35733-.6189-1.0178-1.0001-1.7324-1h2v-2zm6 0c-1.6569 0-3 1.3431-3 3s1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1 .0000096-.55228.44772-.99999 1-1h1v-2z" fill="#e0e0e0"/></svg>
+<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>
diff --git a/editor/icons/Load.svg b/editor/icons/Load.svg
index a049454ebb..a4a6b30d2d 100644
--- a/editor/icons/Load.svg
+++ b/editor/icons/Load.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 .8954-2 2v9c0 1.1046.89543 2 2 2h9c1.1046 0 1.8184-.91043 2-2l1-6c.003977-.18354-.042648-.3412-.13477-.5-.17849-.30916-.50825-.49972-.86523-.5h-8c-.35698.0002824-.68674.19084-.86523.5-.092118.1588-.13874.3399-.13477.52344l-1 5.9766c-.091144.54473-.44772 1-1 1s-1-.4477-1-1v-9c0-.5523.44772-1 1-1h2c.55228 0 1 .4477 1 1a1 1 0 0 0 .29297.70703 1 1 0 0 0 .70703.29297h4 1a1 1 0 0 0 -.29297-.70703 1 1 0 0 0 -.70703-.29297h-4c0-1.1046-.89543-2-2-2h-2z" fill="#e0e0e0"/></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 2h9c1.105 0 1.818-.91 2-2l1-6a1 1 0 0 0-1-1H6c-.552 0-.909.455-1 1l-1 6c-.091.545-.448 1-1 1a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1 1 1 0 0 0 1 1h5a1 1 0 0 0-1-1H7a2 2 0 0 0-2-2H3z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/LockViewport.svg b/editor/icons/LockViewport.svg
index e1d26bc4b0..c29d1415a3 100644
--- a/editor/icons/LockViewport.svg
+++ b/editor/icons/LockViewport.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 0a6 6 0 0 0 -6 6v1h-1v9h14v-9h-1v-1a6 6 0 0 0 -6-6zm0 4c1.1046 0 2 .89543 2 2v1h-4v-1c0-1.1046.89543-2 2-2z" fill-opacity=".39216" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"/><path d="m8 1a5 5 0 0 0 -5 5v2h-1v7h12v-7h-1v-2a5 5 0 0 0 -5-5zm0 2a3 3 0 0 1 3 3v2h-6v-2a3 3 0 0 1 3-3zm-1 7h2v3h-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 6v1H1v9h14V7h-1V6A6 6 0 0 0 2 6zm8 0v1H6V6a1 1 0 0 1 4 0z" fill-opacity=".392"/><path d="M3 6v2H2v7h12V8h-1V6A5 5 0 0 0 3 6zm8 0v2H5V6a3 3 0 0 1 6 0zm-4 4h2v3H7z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Loop.svg b/editor/icons/Loop.svg
index 9bbf168189..cef695602f 100644
--- a/editor/icons/Loop.svg
+++ b/editor/icons/Loop.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1v2h-2a5 5 0 0 0 -5 5 5 5 0 0 0 1.0039 2.9961l1.4355-1.4355a3 3 0 0 1 -.43945-1.5605 3 3 0 0 1 3-3h2v2l2-1.5 2-1.5-2-1.5-2-1.5zm5.9961 4.0039-1.4355 1.4355a3 3 0 0 1 .43945 1.5605 3 3 0 0 1 -3 3h-2v-2l-2 1.5-2 1.5 2 1.5 2 1.5v-2h2a5 5 0 0 0 5-5 5 5 0 0 0 -1.0039-2.9961z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 1v2H6a5 5 0 0 0-4 8l1.414-1.414A3 3 0 0 1 6 5h2v2l4-3-4-3zm6 4-1.414 1.414A3 3 0 0 1 10 11H8V9l-4 3 4 3v-2h2a5 5 0 0 0 4-8z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/MatchCase.svg b/editor/icons/MatchCase.svg
index 0787b0aa56..62e8bc9218 100644
--- a/editor/icons/MatchCase.svg
+++ b/editor/icons/MatchCase.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1c-2.2091-.00000066-4.069 1.7919-4 4v10h2v-4h4v4h2v-10c0-2.2091-1.7909-4-4-4zm5 11c0 1.6569 1.3431 3 3 3 .3409-.0014.67908-.0608 1-.17578v.17578h2v-6c0-1.6569-1.3431-3-3-3h-1v2h1c.55228 0 1 .44772 1 1v.17383c-.32104-.11432-.65921-.1731-1-.17383-1.6569 0-3 1.3431-3 3zm-5-9c1.1046-.0000001 1.914.89879 2 2v4h-4v-4c0-1.1046.89543-2 2-2zm8 8c.55228 0 1 .44772 1 1s-.44772 1-1 1-1-.44772-1-1 .44772-1 1-1z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4 1a4 4 0 0 0-4 4v10h2v-4h4v4h2V5a4 4 0 0 0-4-4zm5 11a3 3 0 0 0 4 2.824V15h2V9a3 3 0 0 0-3-3h-1v2h1a1 1 0 0 1 1 1v.174A3 3 0 0 0 9 12zM4 3a2 2 0 0 1 2 2v4H2V5a2 2 0 0 1 2-2zm8 8a1 1 0 1 1 0 2 1 1 0 0 1 0-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/MeshLibrary.svg b/editor/icons/MeshLibrary.svg
index 5d64acd97e..62a2b3efcc 100644
--- a/editor/icons/MeshLibrary.svg
+++ b/editor/icons/MeshLibrary.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h2.2695v-2h-2.2715a2 2 0 0 0 -.72852-.73047v-5.8555l3 3v-.41406a2.0002 2.0002 0 0 1 .80859-1.6055l-2.3945-2.3945h5.8574a2 2 0 0 0 .72852.73047v1.2695a2.0002 2.0002 0 0 1 .99805.27148 2.0002 2.0002 0 0 1 1.002-.27148v-1.2715a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm6 7v1 5 1h5c.55228 0 1-.4477 1-1v-5c0-.5523-.44772-1-1-1v4l-1-1-1 1v-4z" fill="#ffca5f"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.729 2A2 2 0 1 0 2 4.73v6.542A2 2 0 1 0 4.73 14H7v-2H4.728A2 2 0 0 0 4 11.27V5.414l3 3V8a2 2 0 0 1 .809-1.606L5.414 4h5.858a2 2 0 0 0 .728.73V6a2 2 0 0 1 1 .271A2 2 0 0 1 14 6V4.728A2 2 0 1 0 11.27 2zM9 8v7h5a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v4l-1-1-1 1V8z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/MeshTexture.svg b/editor/icons/MeshTexture.svg
index f85bc433e3..a3337cf8d5 100644
--- a/editor/icons/MeshTexture.svg
+++ b/editor/icons/MeshTexture.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.729 2A2 2 0 1 0 2 4.73v6.541A2 2 0 1 0 4.73 14h6.541a2 2 0 1 0 2.698-2.75H14V4.729A2 2 0 1 0 11.27 2H4.729zm6.542 2a2 2 0 0 0 .729.729v6.542a2 2 0 0 0-.729.729H4.729A2 2 0 0 0 4 11.271V4.729A2 2 0 0 0 4.729 4zM8.812 6.25v.701H8v.7H6.375v.699h-.813v.699H4.75v.701h6.5v-1.4h-.813v-1.4h-.812v-.7h-.813z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.729 2A2 2 0 1 0 2 4.73v6.541A2 2 0 1 0 4.73 14h6.541a2 2 0 1 0 2.698-2.75H14V4.729A2 2 0 1 0 11.27 2H4.729zm6.542 2a2 2 0 0 0 .729.729v6.542a2 2 0 0 0-.729.729H4.729A2 2 0 0 0 4 11.271V4.729A2 2 0 0 0 4.729 4zM8.812 6.25v.701H8v.7H6.375v.699h-.813v.699H4.75v.701h6.5v-1.4h-.813v-1.4h-.812v-.7z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/MethodOverrideAndSlot.svg b/editor/icons/MethodOverrideAndSlot.svg
index d3bd9f0253..eb9729b04d 100644
--- a/editor/icons/MethodOverrideAndSlot.svg
+++ b/editor/icons/MethodOverrideAndSlot.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 4.2333332 4.2333332" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.15761184 3.636193h.37155483l.004252-.7093212c.0027092-.6681099.12999225-1.1321001.92674393-1.1328214h.1273374l.0042585-.7357171 1.3186582 1.006832-1.3229167 1.0700676v-.8531081h-.1260545c-.2888876 0-.3972562.2847204-.4031411.6391525 0 .2833012.0000193.4455045.0000289.7134508h1.2412654v.4907171h-2.14198686z" fill="#5fb2ff"/><path d="m2.38125.79375h1.5875v2.6458333h-1.5875v-.5291666h1.0583333v-1.5875h-1.0583333z" fill="#5fff97"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M.5 13.5H2V11c0-2.5.5-4.2 3.5-4.2H6V4l5 3.8-5 3.8V9h-.5C4.25 9 4 10 4 11v2.5h4.5v2h-8z" fill="#5fb2ff"/><path d="M9 3h6v10H9v-2h4V5H9z" fill="#5fff97"/></svg>
diff --git a/editor/icons/NodeInfo.svg b/editor/icons/NodeInfo.svg
index 4e3f0c42d0..732bccf0d0 100644
--- a/editor/icons/NodeInfo.svg
+++ b/editor/icons/NodeInfo.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm-1 3h2v2h-2zm0 3h2v5h-2z" fill="#fff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 1a7 7 0 0 0 0 14A7 7 0 0 0 8 1zM7 4h2v2H7zm0 3h2v5H7z" fill="#fff"/></svg>
diff --git a/editor/icons/ORMMaterial3D.svg b/editor/icons/ORMMaterial3D.svg
index e09208155d..a70c44fe7d 100644
--- a/editor/icons/ORMMaterial3D.svg
+++ b/editor/icons/ORMMaterial3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3.1191406-3.7636719 1.8808594 3.7636719 1.8828125 3.763672-1.8828125z" fill="#80ff45"/><path d="m3 6.6191406v2.3808594 1.382812l1.234375.617188 2.765625 1.382812v-1.382812-2-.3808594l-3.2382812-1.6191406z" fill="#ff4545"/><path d="m13 6.6191406-.761719.3808594-3.238281 1.6191406v3.7636714l2.765625-1.382812 1.234375-.617188v-1.382812z" fill="#45d7ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M7.75 3.375 4 5.25l3.75 1.875L11.5 5.25z" fill="#80ff45"/><path d="M3.375 6.5v3.75L7 12.063v-3.75z" fill="#ff4545"/><path d="M12.125 6.5 8.5 8.313v3.75l3.625-1.813z" fill="#45d7ff"/></svg>
diff --git a/editor/icons/Play.svg b/editor/icons/Play.svg
index a220cbb3d7..385d5013b1 100644
--- a/editor/icons/Play.svg
+++ b/editor/icons/Play.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.988 3c-.547.01-.987.451-.988.998v8a1 1 0 0 0 1.555.832l6-4a1 1 0 0 0 0-1.664l-6-4A1 1 0 0 0 4.988 3z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4 12a1 1 0 0 0 1.555.832l6-4a1 1 0 0 0 0-1.664l-6-4A1 1 0 0 0 4 4z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Popup.svg b/editor/icons/Popup.svg
index c25cc5b256..a6cfe0715f 100644
--- a/editor/icons/Popup.svg
+++ b/editor/icons/Popup.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm4 2h2v6h-2zm0 8h2v2h-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm4 2h2v6H7zm0 8h2v2H7z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/ProgressBar.svg b/editor/icons/ProgressBar.svg
index 5c49563f23..894def26d8 100644
--- a/editor/icons/ProgressBar.svg
+++ b/editor/icons/ProgressBar.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 3c-1.1046 0-2 .89543-2 2v6c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-6c0-1.1046-.89543-2-2-2zm0 2h10v6h-10zm1 1v4h1v-4zm2 0v4h1v-4zm2 0v4h1v-4z" fill="#8eef97"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm0 2h10v6H3zm1 1v4h1V6zm2 0v4h1V6zm2 0v4h1V6z" fill="#8eef97"/></svg>
diff --git a/editor/icons/ProxyTexture.svg b/editor/icons/ProxyTexture.svg
index 5435e72a1b..5fe39f4da8 100644
--- a/editor/icons/ProxyTexture.svg
+++ b/editor/icons/ProxyTexture.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h4v-4zm6 0v2h6v8h-6v4h7a1 1 0 0 0 1-1v-12a1 1 0 0 0 -1-1zm2 4v1h-1v1h-1v3h1 2 2v-2h-1v-2h-1v-1zm-8 1v4h4v-4zm0 5v4h4v-4z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1 1v4h4V1zm6 0v2h6v8H7v4h7a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zm2 4v1H8v1H7v3h5V8h-1V6h-1V5zM1 6v4h4V6zm0 5v4h4v-4z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Rename.svg b/editor/icons/Rename.svg
index 853f68b2e1..bd6dad207b 100644
--- a/editor/icons/Rename.svg
+++ b/editor/icons/Rename.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2v2h2v8h-2v2h2c.55228 0 1-.4477 1-1 0 .5523.44772 1 1 1h2v-2h-2v-8h2v-2h-2c-.55228 0-1 .44772-1 1 0-.55228-.44772-1-1-1z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M5 2v2h2v8H5v2h2a1 1 0 0 0 1-1 1 1 0 0 0 1 1h2v-2H9V4h2V2H9a1 1 0 0 0-1 1 1 1 0 0 0-1-1z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/ShaderGlobalsOverride.svg b/editor/icons/ShaderGlobalsOverride.svg
index 3a4e4cfb2c..8ac50f05b2 100644
--- a/editor/icons/ShaderGlobalsOverride.svg
+++ b/editor/icons/ShaderGlobalsOverride.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v12c.0000552.5523.44774.9999 1 1h12c.55226-.0001.99994-.4477 1-1v-8l-5-5zm1 2h6v3c0 .554.44599 1 1 1h3v6h-10zm1 1v1h3v-1zm0 2v1h2v-1zm3 0v1h1v-1zm-2 3 3 3 3-3z" 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 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V6l-5-5zm1 2h6v3a1 1 0 0 0 1 1h3v6H3zm1 1v1h3V4zm0 2v1h2V6zm3 0v1h1V6zM5 9l3 3 3-3z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Sort.svg b/editor/icons/Sort.svg
index a7f01fd24e..da18d50010 100644
--- a/editor/icons/Sort.svg
+++ b/editor/icons/Sort.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1v2h6v-2zm-5.0156.0019531a1.0001 1.0001 0 0 0 -.69141.29102l-2 2a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l.29297-.29297v7.1719l-.29297-.29297a1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l2 2a1.0001 1.0001 0 0 0 1.4141 0l2-2a1 1 0 0 0 0-1.4141 1 1 0 0 0 -1.4141 0l-.29297.29297v-7.1719l.29297.29297a1 1 0 0 0 1.4141 0 1 1 0 0 0 0-1.4141l-2-2a1.0001 1.0001 0 0 0 -.72266-.29102zm5.0156 5.998v2h4v-2zm0 6v2h2v-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M9 1v2h6V1zM4 1a1 1 0 0 0-.691.291l-2 2a1 1 0 0 0 1.414 1.414l.293-.293v7.172l-.293-.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l2-2a1 1 0 0 0-1.414-1.414l-.293.293V4.412l.293.293a1 1 0 0 0 1.414-1.414l-2-2A1 1 0 0 0 4 1zm5 6v2h4V7zm0 6v2h2v-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/SpotLight3D.svg b/editor/icons/SpotLight3D.svg
index 27c318257a..0d43545d04 100644
--- a/editor/icons/SpotLight3D.svg
+++ b/editor/icons/SpotLight3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a1 1 0 0 0 -1 1v3.6934c-1.7861.86608-3 2.4605-3 4.3066h4a2 2 0 0 0 2 2 2 2 0 0 0 2-2h4c0-1.8462-1.2139-3.4406-3-4.3066v-3.6934a1 1 0 0 0 -1-1zm-1.0977 9.6348-1.7324 1 1 1.7305 1.7324-1zm6.1953 0-1 1.7305 1.7324 1 1-1.7305zm-4.0977 2.3652v2h2v-2z" fill="#fc7f7f"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M6 1a1 1 0 0 0-1 1v3.693A5 5 0 0 0 2 10h4a2 2 0 0 0 4 0h4a5 5 0 0 0-3-4.307V2a1 1 0 0 0-1-1zm-1.098 9.635-1.732 1 1 1.73 1.732-1zm6.196 0-1 1.73 1.732 1 1-1.73zM7 13v2h2v-2z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/SpriteFrames.svg b/editor/icons/SpriteFrames.svg
index 8ab0ec2c00..a6aecc46bc 100644
--- a/editor/icons/SpriteFrames.svg
+++ b/editor/icons/SpriteFrames.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.108 0-2 .89199-2 2v6c0 1.108.89199 2 2 2h6c1.108 0 2-.89199 2-2v-6c0-1.108-.89199-2-2-2zm10 0v2h2v-2zm-10 4c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm6 0c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm4 0v2h2v-2zm-9 4h2 2a2 1 0 0 1 -1 .86523 2 1 0 0 1 -2 0 2 1 0 0 1 -1-.86523zm9 0v2h2v-2zm-12 4v2h2v-2zm4 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2v-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm10 0v2h2V1zM2 6a1 1 0 0 1 2 0v1a1 1 0 0 1-2 0zm6 0a1 1 0 0 1 2 0v1a1 1 0 0 1-2 0zm5-1v2h2V5zM4 9h4a2 1 0 0 1-4 0zm9 0v2h2V9zM1 13v2h2v-2zm4 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2v-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/SpriteSheet.svg b/editor/icons/SpriteSheet.svg
index a162037f99..2e2c512d38 100644
--- a/editor/icons/SpriteSheet.svg
+++ b/editor/icons/SpriteSheet.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 2h2v2H3zm4 0h2v2H7zm4 0h2v2h-2zM3 7h2v2H3zm4 0h2v2H7zm4 0h2v2h-2zm-8 4h2v2H3zm4 0h2v2H7zm4 0h2v2h-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/TextureButton.svg b/editor/icons/TextureButton.svg
index 8d3d1c52ce..39ec6722f9 100644
--- a/editor/icons/TextureButton.svg
+++ b/editor/icons/TextureButton.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1v2h6v10h-4v2h6v-14zm-5 1v3.1328l-1.4453-.96484-1.1094 1.6641 3 2c.3359.2239.77347.2239 1.1094 0l3-2-1.1094-1.6641-1.4453.96484v-3.1328zm7 4v1h-1v1h-1v1h1v2h2 2v-2h-1v-2h-1v-1zm-7.5 4c-.831 0-1.5.669-1.5 1.5v.5 1h-1v2h8v-2h-1v-1-.5c0-.831-.669-1.5-1.5-1.5z" fill="#8eef97"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 1v2h6v10h-4v2h6V1zM3 2v3.133l-1.445-.965-1.11 1.664 3 2a1 1 0 0 0 1.11 0l3-2-1.11-1.664L5 5.133V2zm7 4v1H9v1H8v1h1v2h4V9h-1V7h-1V6zm-7.5 4A1.5 1.5 0 0 0 1 11.5V13H0v2h8v-2H7v-1.5A1.5 1.5 0 0 0 5.5 10z" fill="#8eef97"/></svg>
diff --git a/editor/icons/ToolPan.svg b/editor/icons/ToolPan.svg
index 36ad59a449..a51e3e76a7 100644
--- a/editor/icons/ToolPan.svg
+++ b/editor/icons/ToolPan.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M11 2a1 1 0 0 0-2 0v6H8V3a1 1 0 0 0-2 0v8.05l-2.5-1.8A1 1 0 0 0 1.875 11L6 15h6a2 2 0 0 0 2-2V4a1 1 0 0 0-2 0v4h-1V2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M11 2a1 1 0 0 0-2 0v6H8V3a1 1 0 0 0-2 0v8.05l-2.5-1.8A1 1 0 0 0 1.875 11L6 15h6a2 2 0 0 0 2-2V4a1 1 0 0 0-2 0v4h-1z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Tools.svg b/editor/icons/Tools.svg
index 81e7385945..e1183db0b1 100644
--- a/editor/icons/Tools.svg
+++ b/editor/icons/Tools.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1-1 2 1 2v4h-2v3 .5c0 1.385 1.115 2.5 2.5 2.5s2.5-1.115 2.5-2.5v-1-2.5h-2v-4l1-2-1-2zm6 .17383a3 3 0 0 0 -2 2.8262 3 3 0 0 0 2 2.8262v6.1738 1c0 .554.446 1 1 1s1-.446 1-1v-4-3.1758a3 3 0 0 0 2-2.8242 3 3 0 0 0 -2-2.8242v2.8242a1 1 0 0 1 -1 1 1 1 0 0 1 -1-1v-2.8262z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4 1 3 3l1 2v4H2v3.5a2.5 2.5 0 0 0 5 0V9H5V5l1-2-1-2zm6 .174a3 3 0 0 0 0 5.652V14a1 1 0 0 0 2 0V6.824a3 3 0 0 0 0-5.648V4a1 1 0 0 1-2 0V1.174z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/TouchScreenButton.svg b/editor/icons/TouchScreenButton.svg
index 731743694d..183f414e9a 100644
--- a/editor/icons/TouchScreenButton.svg
+++ b/editor/icons/TouchScreenButton.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a1 1 0 0 0 -1 1v2a1 1 0 0 0 1 1h2v-1h-1-1v-2h8v2h-2v1h2a1 1 0 0 0 1-1v-2a1 1 0 0 0 -1-1zm4 2a1 1 0 0 0 -1 1v7 .033203l-2.4746-1.8086c-.52015-.3803-1.1948-.4556-1.6504 0-.45566.4556-.45561 1.1948 0 1.6504l4.125 4.125h6c1.1046 0 2-.8954 2-2v-5h-6v-4a1 1 0 0 0 -1-1z" fill="#8da5f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2V4H3V2h8v2H9v1h2a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zm5 7V4a1 1 0 0 0-2 0v7.05l-2.5-1.8A1 1 0 0 0 1.875 11L6 15h6a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/TrackCapture.svg b/editor/icons/TrackCapture.svg
index b3d5f09eff..6251330b12 100644
--- a/editor/icons/TrackCapture.svg
+++ b/editor/icons/TrackCapture.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e1da5b"><path d="m2.1665128.99764963c-.422625 0-.763672.34104737-.763672.76367187v4.5742187c0 .4226242.341047.7617192.763672.7617192h4.472656c.422625 0 .763672-.339095.763672-.7617192v-.9882812h-3.300781c-.1662 0-.298828-.3390943-.298828-.7617188v-1.2246094c0-.4226244.132628-.7636718.298828-.7636718h3.300781v-.8359375c0-.4226245-.341047-.76367187-.763672-.76367187z"/><path d="m9.1827441 4.7953408c.5166221-1.0415625 1.0955249-2.2117429 1.2864509-2.600401l.347137-.7066511.679654.00665.679654.00665.956945 2.3125c.526319 1.271875 1.007254 2.4334375 1.068744 2.5812497l.1118.26875h-.597215-.597214l-.332849-.6437497-.332849-.64375h-1.133826-1.133825l-.3786749.6561133-.3786747.6561134-.5922856.000137-.592285.000136zm3.1779349-.369483c.0042-.00346-.233487-.4884588-.528245-1.0777779l-.535922-1.0714891-.03691.0875c-.0203.048125-.183516.425-.362699.8375-.179182.4125-.355738.85125-.392346.975-.03661.12375-.07127.2390723-.07703.2562715-.0083.024853.188215.027989.957503.015278.532385-.0088.971429-.018823.975651-.022283z" stroke="#e1da5b" stroke-width=".803"/></g></svg>
+<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-.75H3.4c-.3 0-.4-.2-.4-1v-.5c0-.8.1-1 .4-1H7V2a1 1 0 0 0-1-1zm5.5 6h2l.75-1.5h2L13 7h2l-3-6h-1.5zm3.75-4 .5 1h-1z" fill="#e1da5b"/></svg>
diff --git a/editor/icons/TrackContinuous.svg b/editor/icons/TrackContinuous.svg
index 951a13a28e..b48e67af76 100644
--- a/editor/icons/TrackContinuous.svg
+++ b/editor/icons/TrackContinuous.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 6c6 0 6-4 12-4" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
+<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 6c6 0 6-4 12-4" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2"/></svg>
diff --git a/editor/icons/TransitionImmediate.svg b/editor/icons/TransitionImmediate.svg
index 638675a349..b39aaa77c4 100644
--- a/editor/icons/TransitionImmediate.svg
+++ b/editor/icons/TransitionImmediate.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2.988 3c-.547.01-.987.451-.988.998v8a1 1 0 0 0 1.555.832l6-4a1 1 0 0 0 0-1.664l-6-4A1 1 0 0 0 2.988 3z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 12a1 1 0 0 0 1.555.832l6-4a1 1 0 0 0 0-1.664l-6-4A1 1 0 0 0 2 4z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/TransitionImmediateAuto.svg b/editor/icons/TransitionImmediateAuto.svg
index a4ee688469..6118e86250 100644
--- a/editor/icons/TransitionImmediateAuto.svg
+++ b/editor/icons/TransitionImmediateAuto.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2.988 3c-.547.01-.987.451-.988.998v8a1 1 0 0 0 1.555.832l6-4a1 1 0 0 0 0-1.664l-6-4A1 1 0 0 0 2.988 3z" fill="#77ce57"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 12a1 1 0 0 0 1.555.832l6-4a1 1 0 0 0 0-1.664l-6-4A1 1 0 0 0 2 4z" fill="#77ce57"/></svg>
diff --git a/editor/icons/Transpose.svg b/editor/icons/Transpose.svg
deleted file mode 100644
index 41b88ea667..0000000000
--- a/editor/icons/Transpose.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h7v-7h7v-7zm2 2h3v3h-3zm0 5h3v5h-3zm12 2-5 5h5z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Tree.svg b/editor/icons/Tree.svg
index a6c8ace55f..2316bd9498 100644
--- a/editor/icons/Tree.svg
+++ b/editor/icons/Tree.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v13c.0000552.55226.44774.99994 1 1h13v-2h-12v-6h2v3c.0000552.55226.44774.99994 1 1h9v-2h-8v-2h8v-2h-12v-2h12v-2z" fill="#8eef97"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1 1v13a1 1 0 0 0 1 1h13v-2H3V7h2v3a1 1 0 0 0 1 1h9V9H7V7h8V5H3V3h12V1z" fill="#8eef97"/></svg>
diff --git a/editor/icons/VSlider.svg b/editor/icons/VSlider.svg
index 16fafe1162..f013e766d0 100644
--- a/editor/icons/VSlider.svg
+++ b/editor/icons/VSlider.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm5 0c-.55228 0-1 .44772-1 1s.44772 1 1 1h2c.55228 0 1-.44772 1-1s-.44772-1-1-1zm-4 5.8672c-.32639.086294-.6624.13092-1 .13281-.33752-.0012549-.67352-.045224-1-.13086v5 1.1309 1c-.019125 1.3523 2.0191 1.3523 2 0v-1-1.1328-5zm5 .13281c-.55228 0-1 .44772-1 1s.44772 1 1 1 1-.44772 1-1-.44772-1-1-1zm-1 6c-.55228 0-1 .44772-1 1s.44772 1 1 1h2c.55228 0 1-.44772 1-1s-.44772-1-1-1z" fill="#8eef97"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M5 1a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm5 0a1 1 0 0 0 0 2h2a1 1 0 0 0 0-2zM6 6.867a4 4 0 0 1-2 0v7.13a1 1 0 0 0 2 0zM11 7a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-1 6a1 1 0 0 0 0 2h2a1 1 0 0 0 0-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/VehicleBody3D.svg b/editor/icons/VehicleBody3D.svg
index 5e21f40c85..631f877cc5 100644
--- a/editor/icons/VehicleBody3D.svg
+++ b/editor/icons/VehicleBody3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 3a1 1 0 0 0 -1 1l-1 3h-2v4h1.0508c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h2.1016c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h1.0508v-4h-4v-4zm1 1h4v3h-4zm-1.5 6a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5zm7 0a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5z" fill="#fc7f7f"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M5 3a1 1 0 0 0-1 .75L3 7H1v4h1.05A2.5 2.5 0 0 1 4.5 9a2.5 2.5 0 0 1 2.45 2h2.1a2.5 2.5 0 0 1 2.45-2 2.5 2.5 0 0 1 2.45 2H15V7h-4V3zm1 1h4v3H6zm-1.5 6a1.5 1.5 0 0 0 0 3 1.5 1.5 0 0 0 0-3zm7 0a1.5 1.5 0 0 0 0 3 1.5 1.5 0 0 0 0-3z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/ViewportTexture.svg b/editor/icons/ViewportTexture.svg
index a5b1e4ab07..c3d97a8805 100644
--- a/editor/icons/ViewportTexture.svg
+++ b/editor/icons/ViewportTexture.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-.5304.0000801-1.0391.21085-1.4141.58594-.37509.37501-.58586.88366-.58594 1.4141v8c.0000803.5304.21085 1.0391.58594 1.4141.37501.37509.88366.58586 1.4141.58594h10c1.1046 0 2-.89543 2-2v-8c0-1.1046-.89543-2-2-2h-10zm0 1h10c.55228.0000096.99999.44772 1 1v8c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-8c.0000096-.55228.44772-.99999 1-1zm6 3v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-1-1h-1v-1z" fill="#e0e0e0"/></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 2v8a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H3zm0 1h10a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm6 3v1H8v1H6v1H5v1H4v1h8V9h-1V7h-1V6z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/VisualShaderNodeBooleanUniform.svg b/editor/icons/VisualShaderNodeBooleanUniform.svg
index b4a7043fb3..f31f945f55 100644
--- a/editor/icons/VisualShaderNodeBooleanUniform.svg
+++ b/editor/icons/VisualShaderNodeBooleanUniform.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 .02734375c-1.108 0-2 .892-2 2.00000005v1.9726562h2v2a3 3 0 0 1 2.5 1.3457031 3 3 0 0 1 2.5-1.3457031 3 3 0 0 1 2 .7675781 3 3 0 0 1 2-.7675781 3 3 0 0 1 2 .7695312v-2.7695312h2v5a1 1 0 0 0 1 1v-7.9726562c0-1.10800005-.892-2.00000005-2-2.00000005zm0 7.97265625v2a1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm5 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm4 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-6.5 2.654297a3 3 0 0 1 -2.5 1.345703h-2v2.027344c0 1.108.892 2 2 2h12c1.108 0 2-.892 2-2v-2.027344a3 3 0 0 1 -2.5-1.345703 3 3 0 0 1 -2.5 1.345703 3 3 0 0 1 -2-.767578 3 3 0 0 1 -2 .767578 3 3 0 0 1 -2.5-1.345703z" fill="#6f91f0" stroke-linecap="square" stroke-opacity=".75" stroke-width="2"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 0a2 2 0 0 0-2 2v2h2v2a3 3 0 0 1 2.5 1.346A3 3 0 0 1 9 6.768a3 3 0 0 1 4 0V4h2v5a1 1 0 0 0 1 1V2a2 2 0 0 0-2-2zm0 8v2a1 1 0 0 0 0-2zm5 0a1 1 0 0 0 0 2 1 1 0 0 0 0-2zm4 0a1 1 0 0 0 0 2 1 1 0 0 0 0-2zm-6.5 2.654A3 3 0 0 1 2 12H0v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2a3 3 0 0 1-2.5-1.346 3 3 0 0 1-4.5.578 3 3 0 0 1-4.5-.578z" fill="#6f91f0"/></svg>
diff --git a/editor/icons/VisualShaderNodeCubemap.svg b/editor/icons/VisualShaderNodeCubemap.svg
index 3cf870e711..e28552c36d 100644
--- a/editor/icons/VisualShaderNodeCubemap.svg
+++ b/editor/icons/VisualShaderNodeCubemap.svg
@@ -1 +1 @@
-<svg height="14" viewBox="0 0 14 14" width="14" xmlns="http://www.w3.org/2000/svg"><path d="M7 3.514 4.31 4.857 7 6.201l2.69-1.344zM3.428 6.012v2.69l2.857 1.427V7.44zm7.144 0-2.857 1.43v2.687L10.572 8.7z" fill="#eac968"/></svg>
+<svg height="14" viewBox="0 0 14 14" width="14" xmlns="http://www.w3.org/2000/svg"><path d="M7 3.5 4 5l3 1.5L10 5zM3.5 6v3l2.9 1.45v-3zm7 0L7.6 7.45v3L10.5 9z" fill="#eac968"/></svg>
diff --git a/editor/icons/VisualShaderNodeExpression.svg b/editor/icons/VisualShaderNodeExpression.svg
index 710ba818b7..ecee759562 100644
--- a/editor/icons/VisualShaderNodeExpression.svg
+++ b/editor/icons/VisualShaderNodeExpression.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#cf68ea"><path d="m4.859536 3.0412379c-2.0539867 0-3.7190721 1.6650852-3.7190721 3.719072v6.1984521h2.4793814v-2.479381h2.4793814v-2.4793803h-2.4793814v-1.2396908c0-.6846622.5550285-1.2396907 1.2396907-1.2396907h1.2396907v-2.4793813z"/><path d="m7.5889175 3.0000003 2.5000005 4.9999997-2.5000005 5h2.5000005l1.135249-2.727 1.36475 2.727h2.499999l-2.499999-5 2.499999-4.9999997h-2.499999l-1.13525 2.7269998-1.364749-2.7269998zm7.4999985 9.9999997v-6.25z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.86 3.041a3.72 3.72 0 0 0-3.72 3.72v6.198h2.48v-2.48H6.1V8H3.62V6.76a1.24 1.24 0 0 1 1.24-1.24H6.1V3.042zM7.589 3l2.5 5-2.5 5h2.5l1.135-2.727L12.59 13h2.5l-2.5-5 2.5-5h-2.5l-1.135 2.727L10.089 3z" fill="#cf68ea"/></svg>
diff --git a/editor/icons/VisualShaderNodeGlobalExpression.svg b/editor/icons/VisualShaderNodeGlobalExpression.svg
index 0cafffb152..5e967ea571 100644
--- a/editor/icons/VisualShaderNodeGlobalExpression.svg
+++ b/editor/icons/VisualShaderNodeGlobalExpression.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#35d4f4"><path d="m4.859536 3.0412379c-2.0539867 0-3.7190721 1.6650852-3.7190721 3.719072v6.1984521h2.4793814v-2.479381h2.4793814v-2.4793803h-2.4793814v-1.2396908c0-.6846622.5550285-1.2396907 1.2396907-1.2396907h1.2396907v-2.4793813z"/><path d="m7.5889175 3.0000003 2.5000005 4.9999997-2.5000005 5h2.5000005l1.135249-2.727 1.36475 2.727h2.499999l-2.499999-5 2.499999-4.9999997h-2.499999l-1.13525 2.7269998-1.364749-2.7269998zm7.4999985 9.9999997v-6.25z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.86 3.041a3.72 3.72 0 0 0-3.72 3.72v6.198h2.48v-2.48H6.1V8H3.62V6.76a1.24 1.24 0 0 1 1.24-1.24H6.1V3.042zM7.589 3l2.5 5-2.5 5h2.5l1.135-2.727L12.59 13h2.5l-2.5-5 2.5-5h-2.5l-1.135 2.727L10.089 3z" fill="#35d4f4"/></svg>
diff --git a/editor/icons/VisualShaderNodeTransformUniform.svg b/editor/icons/VisualShaderNodeTransformUniform.svg
index 5d3e6977e0..507b616eff 100644
--- a/editor/icons/VisualShaderNodeTransformUniform.svg
+++ b/editor/icons/VisualShaderNodeTransformUniform.svg
@@ -1 +1 @@
-<svg height="14" viewBox="0 0 14 14" width="14" xmlns="http://www.w3.org/2000/svg"><path d="m2 0c-1.1045695 0-2 .8954-2 2v10c0 1.1046.8954305 2 2 2h10c1.104569 0 2-.8954 2-2v-10c0-1.1046-.895431-2-2-2zm-1 1h1 2v1h-2v10h2v1h-2-1v-1-10zm9 0h3v11 1h-3v-1h2v-10h-2zm-.0292969 2a1.0001 1.0001 0 0 1 1.0292969 1v7h-2v-4.5859375l-1.2929688 1.2929687a1.0001 1.0001 0 0 1 -1.4140624 0l-1.2929688-1.2929687v4.5859375h-2v-7a1.0001 1.0001 0 0 1 .984375-.9980469 1.0001 1.0001 0 0 1 .7226562.2910157l2.2929688 2.2929687 2.2929688-2.2929687a1.0001 1.0001 0 0 1 .6777343-.2929688z" fill="#ea686c"/></svg>
+<svg height="14" viewBox="0 0 14 14" width="14" xmlns="http://www.w3.org/2000/svg"><path d="M2 0a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zM1 1h3v1H2v10h2v1H1zm9 0h3v12h-3v-1h2V2h-2zm1 10H9V6.414L7.707 7.707a1 1 0 0 1-1.414 0L5 6.414V11H3V4a1 1 0 0 1 1.707-.707L7 5.586l2.293-2.293A1 1 0 0 1 11 4z" fill="#ea686c"/></svg>
diff --git a/editor/icons/VoxelGIData.svg b/editor/icons/VoxelGIData.svg
index 51b66ca899..a4eb17418d 100644
--- a/editor/icons/VoxelGIData.svg
+++ b/editor/icons/VoxelGIData.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 1v12a1 1 0 0 0 1 1h4v-2H3V3h9V1zm2 3v2h2V4zm7 0a4 4 0 0 0-2 7.459V12a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-.541A4 4 0 0 0 11 4zm0 2a2 2 0 0 1 0 4 2 2 0 0 1 0-4zM4 7v2h2V7zm0 3v2h2v-2zm6 4v1h2v-1z" 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 1v12a1 1 0 0 0 1 1h4v-2H3V3h9V1zm7 11a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-.541a4 4 0 1 0-4 0zm2-6a2 2 0 0 1 0 4 2 2 0 0 1 0-4zm-1 8v1h2v-1zM4 4h2v2H4zm0 3h2v2H4zm0 3h2v2H4z" fill="#e0e0e0"/></svg>
diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp
index abf56c7ef8..1f7fbd8c59 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -395,7 +395,7 @@ void AudioStreamImportSettings::_seek_to(real_t p_x) {
void AudioStreamImportSettings::edit(const String &p_path, const String &p_importer, const Ref<AudioStream> &p_stream) {
if (!stream.is_null()) {
- stream->disconnect("changed", callable_mp(this, &AudioStreamImportSettings::_audio_changed));
+ stream->disconnect_changed(callable_mp(this, &AudioStreamImportSettings::_audio_changed));
}
importer = p_importer;
@@ -408,7 +408,7 @@ void AudioStreamImportSettings::edit(const String &p_path, const String &p_impor
_duration_label->set_text(text);
if (!stream.is_null()) {
- stream->connect("changed", callable_mp(this, &AudioStreamImportSettings::_audio_changed));
+ stream->connect_changed(callable_mp(this, &AudioStreamImportSettings::_audio_changed));
_preview->queue_redraw();
_indicator->queue_redraw();
color_rect->queue_redraw();
diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp
index cbd00f0f6b..8e04ce4c7e 100644
--- a/editor/import/resource_importer_imagefont.cpp
+++ b/editor/import/resource_importer_imagefont.cpp
@@ -111,7 +111,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin
int chr_width = chr_cell_width - char_margin.position.x - char_margin.size.x;
int chr_height = chr_cell_height - char_margin.position.y - char_margin.size.y;
- ERR_FAIL_COND_V_MSG(chr_width <= 0 || chr_height <= 0, ERR_FILE_CANT_READ, TTR("Character margin too bit."));
+ ERR_FAIL_COND_V_MSG(chr_width <= 0 || chr_height <= 0, ERR_FILE_CANT_READ, TTR("Character margin too big."));
Ref<FontFile> font;
font.instantiate();
diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp
index 89a0f4ca3c..3c27864eff 100644
--- a/editor/import/resource_importer_layered_texture.cpp
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -39,6 +39,7 @@
#include "editor/editor_node.h"
#include "editor/import/resource_importer_texture.h"
#include "editor/import/resource_importer_texture_settings.h"
+#include "scene/resources/compressed_texture.h"
#include "scene/resources/texture.h"
String ResourceImporterLayeredTexture::get_importer_name() const {
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index a6e0916160..677b2e78bd 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -313,8 +313,9 @@ String ResourceImporterScene::get_preset_name(int p_idx) const {
static bool _teststr(const String &p_what, const String &p_str) {
String what = p_what;
- //remove trailing spaces and numbers, some apps like blender add ".number" to duplicates so also compensate for this
- while (what.length() && (is_digit(what[what.length() - 1]) || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) {
+ // Remove trailing spaces and numbers, some apps like blender add ".number" to duplicates
+ // (dot is replaced with _ as invalid character) so also compensate for this.
+ while (what.length() && (is_digit(what[what.length() - 1]) || what[what.length() - 1] <= 32 || what[what.length() - 1] == '_')) {
what = what.substr(0, what.length() - 1);
}
@@ -333,8 +334,9 @@ static bool _teststr(const String &p_what, const String &p_str) {
static String _fixstr(const String &p_what, const String &p_str) {
String what = p_what;
- //remove trailing spaces and numbers, some apps like blender add ".number" to duplicates so also compensate for this
- while (what.length() && (is_digit(what[what.length() - 1]) || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) {
+ // Remove trailing spaces and numbers, some apps like blender add ".number" to duplicates
+ // (dot is replaced with _ as invalid character) so also compensate for this.
+ while (what.length() && (is_digit(what[what.length() - 1]) || what[what.length() - 1] <= 32 || what[what.length() - 1] == '_')) {
what = what.substr(0, what.length() - 1);
}
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index e81e836e9e..57139a511f 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -39,6 +39,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/import/resource_importer_texture_settings.h"
+#include "scene/resources/compressed_texture.h"
void ResourceImporterTexture::_texture_reimport_roughness(const Ref<CompressedTexture2D> &p_tex, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_channel) {
ERR_FAIL_COND(p_tex.is_null());
@@ -789,11 +790,16 @@ bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) co
ResourceImporterTexture *ResourceImporterTexture::singleton = nullptr;
ResourceImporterTexture::ResourceImporterTexture() {
- singleton = this;
+ if (!singleton) {
+ singleton = this;
+ }
CompressedTexture2D::request_3d_callback = _texture_reimport_3d;
CompressedTexture2D::request_roughness_callback = _texture_reimport_roughness;
CompressedTexture2D::request_normal_callback = _texture_reimport_normal;
}
ResourceImporterTexture::~ResourceImporterTexture() {
+ if (singleton == this) {
+ singleton = nullptr;
+ }
}
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index 5a85160690..d437f23740 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -36,8 +36,10 @@
#include "core/io/resource_saver.h"
#include "core/math/geometry_2d.h"
#include "editor/editor_atlas_packer.h"
+#include "scene/resources/atlas_texture.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/mesh.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/mesh_texture.h"
String ResourceImporterTextureAtlas::get_importer_name() const {
return "texture_atlas";
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
index 92d287c54f..28105d7420 100644
--- a/editor/import/scene_import_settings.cpp
+++ b/editor/import/scene_import_settings.cpp
@@ -64,7 +64,7 @@ class SceneImportSettingsData : public Object {
current[p_name] = p_value;
- // SceneImportSettings must decide if a new collider should be generated or not
+ // SceneImportSettings must decide if a new collider should be generated or not.
if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE) {
SceneImportSettings::get_singleton()->request_generate_collider();
}
@@ -350,8 +350,12 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
} else if (Object::cast_to<AnimationPlayer>(p_node)) {
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
+
+ animation_player = Object::cast_to<AnimationPlayer>(p_node);
+ animation_player->connect(SNAME("animation_finished"), callable_mp(this, &SceneImportSettings::_animation_finished));
} else if (Object::cast_to<Skeleton3D>(p_node)) {
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
+ skeletons.push_back(Object::cast_to<Skeleton3D>(p_node));
} else {
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
}
@@ -413,7 +417,7 @@ void SceneImportSettings::_update_scene() {
material_tree->clear();
mesh_tree->clear();
- //hidden roots
+ // Hidden roots.
material_tree->create_item();
mesh_tree->create_item();
@@ -432,7 +436,7 @@ void SceneImportSettings::_update_view_gizmos() {
MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(e.value.node);
if (mesh_node == nullptr || mesh_node->get_mesh().is_null()) {
- // Nothing to do
+ // Nothing to do.
continue;
}
@@ -591,7 +595,7 @@ void SceneImportSettings::open_settings(const String &p_path, bool p_for_animati
scene_import_settings_data->settings = nullptr;
scene_import_settings_data->path = p_path;
- // Visibility
+ // Visibility.
data_mode->set_tab_hidden(1, p_for_animation);
data_mode->set_tab_hidden(2, p_for_animation);
if (p_for_animation) {
@@ -691,12 +695,13 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
scene_import_settings_data->hide_options = false;
if (p_type == "Node") {
- node_selected->hide(); //always hide just in case
+ node_selected->hide(); // Always hide just in case.
mesh_preview->hide();
+ _reset_animation();
+
if (Object::cast_to<Node3D>(scene)) {
Object::cast_to<Node3D>(scene)->show();
}
- //NodeData &nd=node_map[p_id];
material_tree->deselect_all();
mesh_tree->deselect_all();
NodeData &nd = node_map[p_id];
@@ -734,12 +739,13 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
}
}
} else if (p_type == "Animation") {
- node_selected->hide(); //always hide just in case
+ node_selected->hide(); // Always hide just in case.
mesh_preview->hide();
+ _reset_animation(p_id);
+
if (Object::cast_to<Node3D>(scene)) {
Object::cast_to<Node3D>(scene)->show();
}
- //NodeData &nd=node_map[p_id];
material_tree->deselect_all();
mesh_tree->deselect_all();
AnimationData &ad = animation_map[p_id];
@@ -768,6 +774,7 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
mesh_preview->set_mesh(md.mesh);
mesh_preview->show();
+ _reset_animation();
material_tree->deselect_all();
@@ -780,6 +787,7 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
}
mesh_preview->show();
+ _reset_animation();
MaterialData &md = material_map[p_id];
@@ -836,7 +844,7 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
if (scene_import_settings_data->settings) {
for (const ResourceImporter::ImportOption &E : options) {
scene_import_settings_data->defaults[E.option.name] = E.default_value;
- //needed for visibility toggling (fails if something is missing)
+ // Needed for visibility toggling (fails if something is missing).
if (scene_import_settings_data->settings->has(E.option.name)) {
scene_import_settings_data->current[E.option.name] = (*scene_import_settings_data->settings)[E.option.name];
} else {
@@ -850,6 +858,127 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
scene_import_settings_data->notify_property_list_changed();
}
+void SceneImportSettings::_inspector_property_edited(const String &p_name) {
+ if (p_name == "settings/loop_mode") {
+ if (!animation_map.has(selected_id)) {
+ return;
+ }
+ HashMap<StringName, Variant> settings = animation_map[selected_id].settings;
+ if (settings.has(p_name)) {
+ animation_loop_mode = static_cast<Animation::LoopMode>((int)settings[p_name]);
+ } else {
+ animation_loop_mode = Animation::LoopMode::LOOP_NONE;
+ }
+ }
+}
+
+void SceneImportSettings::_reset_bone_transforms() {
+ for (Skeleton3D *skeleton : skeletons) {
+ skeleton->reset_bone_poses();
+ }
+}
+
+void SceneImportSettings::_play_animation() {
+ if (animation_player == nullptr) {
+ return;
+ }
+ StringName id = StringName(selected_id);
+ if (animation_player->has_animation(id)) {
+ if (animation_player->is_playing()) {
+ animation_player->pause();
+ animation_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ set_process(false);
+ } else {
+ animation_player->play(id);
+ animation_play_button->set_icon(get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")));
+ set_process(true);
+ }
+ }
+}
+
+void SceneImportSettings::_stop_current_animation() {
+ animation_pingpong = false;
+ animation_player->stop();
+ animation_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ animation_slider->set_value_no_signal(0.0);
+ set_process(false);
+}
+
+void SceneImportSettings::_reset_animation(const String &p_animation_name) {
+ if (p_animation_name.is_empty()) {
+ animation_preview->hide();
+
+ if (animation_player != nullptr && animation_player->is_playing()) {
+ animation_player->stop();
+ }
+ animation_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+
+ _reset_bone_transforms();
+ set_process(false);
+ } else {
+ _reset_bone_transforms();
+ animation_preview->show();
+
+ animation_loop_mode = Animation::LoopMode::LOOP_NONE;
+ animation_pingpong = false;
+
+ if (animation_map.has(p_animation_name)) {
+ HashMap<StringName, Variant> settings = animation_map[p_animation_name].settings;
+ if (settings.has("settings/loop_mode")) {
+ animation_loop_mode = static_cast<Animation::LoopMode>((int)settings["settings/loop_mode"]);
+ }
+ }
+
+ if (animation_player->is_playing() && animation_loop_mode != Animation::LoopMode::LOOP_NONE) {
+ animation_player->play(p_animation_name);
+ } else {
+ animation_player->stop(true);
+ animation_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ animation_player->set_assigned_animation(p_animation_name);
+ animation_player->seek(0.0, true);
+ animation_slider->set_value_no_signal(0.0);
+ set_process(false);
+ }
+ }
+}
+
+void SceneImportSettings::_animation_slider_value_changed(double p_value) {
+ if (animation_player == nullptr || !animation_map.has(selected_id) || animation_map[selected_id].animation.is_null()) {
+ return;
+ }
+ if (animation_player->is_playing()) {
+ animation_player->stop();
+ animation_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ set_process(false);
+ }
+ animation_player->seek(p_value * animation_map[selected_id].animation->get_length(), true);
+}
+
+void SceneImportSettings::_animation_finished(const StringName &p_name) {
+ Animation::LoopMode loop_mode = animation_loop_mode;
+
+ switch (loop_mode) {
+ case Animation::LOOP_NONE: {
+ animation_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ animation_slider->set_value_no_signal(1.0);
+ set_process(false);
+ } break;
+ case Animation::LOOP_LINEAR: {
+ animation_player->play(p_name);
+ } break;
+ case Animation::LOOP_PINGPONG: {
+ if (animation_pingpong) {
+ animation_player->play(p_name);
+ } else {
+ animation_player->play_backwards(p_name);
+ }
+ animation_pingpong = !animation_pingpong;
+ } break;
+ default: {
+ } break;
+ }
+}
+
void SceneImportSettings::_material_tree_selected() {
if (selecting) {
return;
@@ -884,6 +1013,15 @@ void SceneImportSettings::_scene_tree_selected() {
_select(scene_tree, type, import_id);
}
+void SceneImportSettings::_cleanup() {
+ skeletons.clear();
+ if (animation_player != nullptr) {
+ animation_player->disconnect(SNAME("animation_finished"), callable_mp(this, &SceneImportSettings::_animation_finished));
+ animation_player = nullptr;
+ }
+ set_process(false);
+}
+
void SceneImportSettings::_viewport_input(const Ref<InputEvent> &p_input) {
float *rot_x = &cam_rot_x;
float *rot_y = &cam_rot_y;
@@ -1005,6 +1143,25 @@ void SceneImportSettings::_notification(int p_what) {
action_menu->add_theme_style_override("normal", get_theme_stylebox("normal", "Button"));
action_menu->add_theme_style_override("hover", get_theme_stylebox("hover", "Button"));
action_menu->add_theme_style_override("pressed", get_theme_stylebox("pressed", "Button"));
+
+ if (animation_player != nullptr && animation_player->is_playing()) {
+ animation_play_button->set_icon(get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")));
+ } else {
+ animation_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ }
+ animation_stop_button->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
+ } break;
+
+ case NOTIFICATION_PROCESS: {
+ if (animation_player != nullptr) {
+ animation_slider->set_value_no_signal(animation_player->get_current_animation_position() / animation_player->get_current_animation_length());
+ }
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible()) {
+ _cleanup();
+ }
} break;
}
}
@@ -1331,16 +1488,53 @@ SceneImportSettings::SceneImportSettings() {
material_tree->set_hide_root(true);
+ VBoxContainer *vp_vb = memnew(VBoxContainer);
+ vp_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ vp_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ vp_vb->set_anchors_and_offsets_preset(Control::LayoutPreset::PRESET_FULL_RECT);
+ property_split->add_child(vp_vb);
+
SubViewportContainer *vp_container = memnew(SubViewportContainer);
- vp_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ vp_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vp_container->set_custom_minimum_size(Size2(10, 10));
vp_container->set_stretch(true);
vp_container->connect("gui_input", callable_mp(this, &SceneImportSettings::_viewport_input));
- property_split->add_child(vp_container);
+ vp_vb->add_child(vp_container);
base_viewport = memnew(SubViewport);
vp_container->add_child(base_viewport);
+ animation_preview = memnew(PanelContainer);
+ animation_preview->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ vp_vb->add_child(animation_preview);
+ animation_preview->hide();
+
+ HBoxContainer *animation_hbox = memnew(HBoxContainer);
+ animation_preview->add_child(animation_hbox);
+
+ animation_play_button = memnew(Button);
+ animation_hbox->add_child(animation_play_button);
+ animation_play_button->set_flat(true);
+ animation_play_button->set_focus_mode(Control::FOCUS_NONE);
+ animation_play_button->set_shortcut(ED_SHORTCUT("scene_import_settings/play_selected_animation", TTR("Selected Animation Play/Pause"), Key::SPACE));
+ animation_play_button->connect(SNAME("pressed"), callable_mp(this, &SceneImportSettings::_play_animation));
+
+ animation_stop_button = memnew(Button);
+ animation_hbox->add_child(animation_stop_button);
+ animation_stop_button->set_flat(true);
+ animation_stop_button->set_focus_mode(Control::FOCUS_NONE);
+ animation_stop_button->connect(SNAME("pressed"), callable_mp(this, &SceneImportSettings::_stop_current_animation));
+
+ animation_slider = memnew(HSlider);
+ animation_hbox->add_child(animation_slider);
+ animation_slider->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ animation_slider->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ animation_slider->set_max(1.0);
+ animation_slider->set_step(1.0 / 100.0);
+ animation_slider->set_value_no_signal(0.0);
+ animation_slider->set_focus_mode(Control::FOCUS_NONE);
+ animation_slider->connect(SNAME("value_changed"), callable_mp(this, &SceneImportSettings::_animation_slider_value_changed));
+
base_viewport->set_use_own_world_3d(true);
camera = memnew(Camera3D);
@@ -1406,6 +1600,7 @@ SceneImportSettings::SceneImportSettings() {
inspector = memnew(EditorInspector);
inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
+ inspector->connect(SNAME("property_edited"), callable_mp(this, &SceneImportSettings::_inspector_property_edited));
property_split->add_child(inspector);
diff --git a/editor/import/scene_import_settings.h b/editor/import/scene_import_settings.h
index d65bb1404a..b4954b9099 100644
--- a/editor/import/scene_import_settings.h
+++ b/editor/import/scene_import_settings.h
@@ -35,10 +35,13 @@
#include "scene/3d/camera_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/item_list.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/option_button.h"
+#include "scene/gui/panel_container.h"
+#include "scene/gui/slider.h"
#include "scene/gui/split_container.h"
#include "scene/gui/subviewport_container.h"
#include "scene/gui/tab_container.h"
@@ -85,6 +88,15 @@ class SceneImportSettings : public ConfirmationDialog {
MeshInstance3D *mesh_preview = nullptr;
Ref<SphereMesh> material_preview;
+ AnimationPlayer *animation_player = nullptr;
+ List<Skeleton3D *> skeletons;
+ PanelContainer *animation_preview = nullptr;
+ HSlider *animation_slider = nullptr;
+ Button *animation_play_button = nullptr;
+ Button *animation_stop_button = nullptr;
+ Animation::LoopMode animation_loop_mode = Animation::LOOP_NONE;
+ bool animation_pingpong = false;
+
Ref<StandardMaterial3D> collider_mat;
float cam_rot_x = 0.0f;
@@ -151,9 +163,17 @@ class SceneImportSettings : public ConfirmationDialog {
void _update_view_gizmos();
void _update_camera();
void _select(Tree *p_from, String p_type, String p_id);
+ void _inspector_property_edited(const String &p_name);
+ void _reset_bone_transforms();
+ void _play_animation();
+ void _stop_current_animation();
+ void _reset_animation(const String &p_animation_name = "");
+ void _animation_slider_value_changed(double p_value);
+ void _animation_finished(const StringName &p_name);
void _material_tree_selected();
void _mesh_tree_selected();
void _scene_tree_selected();
+ void _cleanup();
void _viewport_input(const Ref<InputEvent> &p_input);
diff --git a/editor/import_defaults_editor.cpp b/editor/import_defaults_editor.cpp
index ebbea827c0..98a9bfe9dc 100644
--- a/editor/import_defaults_editor.cpp
+++ b/editor/import_defaults_editor.cpp
@@ -157,6 +157,9 @@ void ImportDefaultsEditor::_update_importer() {
settings->notify_property_list_changed();
+ // Set the importer class to fetch the correct class in the XML class reference.
+ // This allows tooltips to display when hovering properties.
+ inspector->set_object_class(importer->get_class_name());
inspector->edit(settings);
}
@@ -210,9 +213,14 @@ ImportDefaultsEditor::ImportDefaultsEditor() {
reset_defaults->connect("pressed", callable_mp(this, &ImportDefaultsEditor::_reset));
hb->add_child(reset_defaults);
add_child(hb);
+
inspector = memnew(EditorInspector);
add_child(inspector);
inspector->set_v_size_flags(SIZE_EXPAND_FILL);
+ // Make it possible to display tooltips stored in the XML class reference.
+ // The object name is set when the importer changes in `_update_importer()`.
+ inspector->set_use_doc_hints(true);
+
CenterContainer *cc = memnew(CenterContainer);
save_defaults = memnew(Button);
save_defaults->set_text(TTR("Save"));
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 7b8b9cd7a4..a17f497725 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
class ImportDockParameters : public Object {
GDCLASS(ImportDockParameters, Object);
@@ -157,6 +158,13 @@ void ImportDock::_add_keep_import_option(const String &p_importer_name) {
}
void ImportDock::_update_options(const String &p_path, const Ref<ConfigFile> &p_config) {
+ // Set the importer class to fetch the correct class in the XML class reference.
+ // This allows tooltips to display when hovering properties.
+ if (params->importer != nullptr) {
+ // Null check to avoid crashing if the "Keep File (No Import)" mode is selected.
+ import_opts->set_object_class(params->importer->get_class_name());
+ }
+
List<ResourceImporter::ImportOption> options;
if (params->importer.is_valid()) {
@@ -459,7 +467,6 @@ static bool _find_owners(EditorFileSystemDirectory *efsd, const String &p_path)
}
void ImportDock::_reimport_attempt() {
- bool need_restart = false;
bool used_in_resources = false;
String importer_name;
@@ -476,14 +483,15 @@ void ImportDock::_reimport_attempt() {
String imported_with = config->get_value("remap", "importer");
if (imported_with != importer_name) {
- need_restart = true;
+ need_cleanup.push_back(params->paths[i]);
if (_find_owners(EditorFileSystem::get_singleton()->get_filesystem(), params->paths[i])) {
used_in_resources = true;
}
}
}
- if (need_restart) {
+ if (!need_cleanup.is_empty() || used_in_resources) {
+ cleanup_warning->set_visible(!need_cleanup.is_empty());
label_warning->set_visible(used_in_resources);
reimport_confirm->popup_centered();
return;
@@ -492,11 +500,42 @@ void ImportDock::_reimport_attempt() {
_reimport();
}
-void ImportDock::_reimport_and_restart() {
- EditorNode::get_singleton()->save_all_scenes();
- EditorResourcePreview::get_singleton()->stop(); //don't try to re-create previews after import
+void ImportDock::_reimport_and_cleanup() {
+ HashMap<String, Ref<Resource>> old_resources;
+
+ for (const String &path : need_cleanup) {
+ Ref<Resource> res = ResourceLoader::load(path);
+ res->set_path("");
+ res->set_meta(SNAME("_skip_save_"), true);
+ old_resources[path] = res;
+ }
+
+ EditorResourcePreview::get_singleton()->stop(); // Don't try to re-create previews after import.
_reimport();
- EditorNode::get_singleton()->restart_editor();
+
+ if (need_cleanup.is_empty()) {
+ return;
+ }
+
+ // After changing resource type we need to make sure that all old instances are unloaded or replaced.
+ EditorNode::get_singleton()->push_item(nullptr);
+ EditorUndoRedoManager::get_singleton()->clear_history();
+
+ List<Ref<Resource>> external_resources;
+ ResourceCache::get_cached_resources(&external_resources);
+
+ for (const String &path : need_cleanup) {
+ Ref<Resource> old_res = old_resources[path];
+ Ref<Resource> new_res = ResourceLoader::load(path);
+
+ for (int j = 0; j < EditorNode::get_editor_data().get_edited_scene_count(); j++) {
+ _replace_resource_in_object(EditorNode::get_editor_data().get_edited_scene_root(j), old_res, new_res);
+ }
+ for (Ref<Resource> res : external_resources) {
+ _replace_resource_in_object(res.ptr(), old_res, new_res);
+ }
+ }
+ need_cleanup.clear();
}
void ImportDock::_advanced_options() {
@@ -561,6 +600,37 @@ void ImportDock::_reimport() {
_set_dirty(false);
}
+void ImportDock::_replace_resource_in_object(Object *p_object, const Ref<Resource> &old_resource, const Ref<Resource> &new_resource) {
+ ERR_FAIL_NULL(p_object);
+
+ List<PropertyInfo> props;
+ p_object->get_property_list(&props);
+
+ for (const PropertyInfo &p : props) {
+ if (p.type != Variant::OBJECT || p.hint != PROPERTY_HINT_RESOURCE_TYPE) {
+ continue;
+ }
+
+ Ref<Resource> res = p_object->get(p.name);
+ if (res.is_null()) {
+ continue;
+ }
+
+ if (res == old_resource) {
+ p_object->set(p.name, new_resource);
+ } else {
+ _replace_resource_in_object(res.ptr(), old_resource, new_resource);
+ }
+ }
+
+ Node *n = Object::cast_to<Node>(p_object);
+ if (n) {
+ for (int i = 0; i < n->get_child_count(); i++) {
+ _replace_resource_in_object(n->get_child(i), old_resource, new_resource);
+ }
+ }
+}
+
void ImportDock::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
@@ -644,6 +714,9 @@ ImportDock::ImportDock() {
import_opts->set_v_size_flags(SIZE_EXPAND_FILL);
import_opts->connect("property_edited", callable_mp(this, &ImportDock::_property_edited));
import_opts->connect("property_toggled", callable_mp(this, &ImportDock::_property_toggled));
+ // Make it possible to display tooltips stored in the XML class reference.
+ // The object name is set when the importer changes in `_update_options()`.
+ import_opts->set_use_doc_hints(true);
hb = memnew(HBoxContainer);
content->add_child(hb);
@@ -673,13 +746,13 @@ ImportDock::ImportDock() {
advanced->connect("pressed", callable_mp(this, &ImportDock::_advanced_options));
reimport_confirm = memnew(ConfirmationDialog);
- reimport_confirm->set_ok_button_text(TTR("Save Scenes, Re-Import, and Restart"));
content->add_child(reimport_confirm);
- reimport_confirm->connect("confirmed", callable_mp(this, &ImportDock::_reimport_and_restart));
+ reimport_confirm->connect("confirmed", callable_mp(this, &ImportDock::_reimport_and_cleanup));
VBoxContainer *vbc_confirm = memnew(VBoxContainer());
- vbc_confirm->add_child(memnew(Label(TTR("Changing the type of an imported file requires editor restart."))));
- label_warning = memnew(Label(TTR("WARNING: Assets exist that use this resource, they may stop loading properly.")));
+ cleanup_warning = memnew(Label(TTR("The imported resource is currently loaded. All instances will be replaced and undo history will be cleared.")));
+ vbc_confirm->add_child(cleanup_warning);
+ label_warning = memnew(Label(TTR("WARNING: Assets exist that use this resource. They may stop loading properly after changing type.")));
vbc_confirm->add_child(label_warning);
reimport_confirm->add_child(vbc_confirm);
diff --git a/editor/import_dock.h b/editor/import_dock.h
index f627cd965d..07c54f8beb 100644
--- a/editor/import_dock.h
+++ b/editor/import_dock.h
@@ -54,8 +54,10 @@ class ImportDock : public VBoxContainer {
HashMap<StringName, Variant> property_values;
ConfirmationDialog *reimport_confirm = nullptr;
+ Label *cleanup_warning = nullptr;
Label *label_warning = nullptr;
Button *import = nullptr;
+ List<String> need_cleanup;
Control *advanced_spacer = nullptr;
Button *advanced = nullptr;
@@ -75,9 +77,11 @@ class ImportDock : public VBoxContainer {
void _property_toggled(const StringName &p_prop, bool p_checked);
void _set_dirty(bool p_dirty);
void _reimport_attempt();
- void _reimport_and_restart();
+ void _reimport_and_cleanup();
void _reimport();
+ void _replace_resource_in_object(Object *p_object, const Ref<Resource> &old_resource, const Ref<Resource> &new_resource);
+
void _advanced_options();
enum {
ITEM_SET_AS_DEFAULT = 100,
diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp
index 545769d327..ebb35eedf9 100644
--- a/editor/node_dock.cpp
+++ b/editor/node_dock.cpp
@@ -70,6 +70,9 @@ void NodeDock::update_lists() {
void NodeDock::set_node(Node *p_node) {
connections->set_node(p_node);
groups->set_current(p_node);
+ if (p_node) {
+ last_valid_node = p_node;
+ }
if (p_node) {
if (connections_button->is_pressed()) {
@@ -88,6 +91,10 @@ void NodeDock::set_node(Node *p_node) {
}
}
+void NodeDock::restore_last_valid_node() {
+ set_node(last_valid_node);
+}
+
NodeDock::NodeDock() {
singleton = this;
diff --git a/editor/node_dock.h b/editor/node_dock.h
index e9dcc41d48..cc22171453 100644
--- a/editor/node_dock.h
+++ b/editor/node_dock.h
@@ -47,6 +47,7 @@ class NodeDock : public VBoxContainer {
HBoxContainer *mode_hb = nullptr;
Label *select_a_node = nullptr;
+ Node *last_valid_node = nullptr;
private:
static NodeDock *singleton;
@@ -60,6 +61,7 @@ protected:
public:
void set_node(Node *p_node);
+ void restore_last_valid_node();
void show_groups();
void show_connections();
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index ea210872f7..8f2839ddb0 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -48,6 +48,7 @@
#include "scene/gui/separator.h"
#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
+#include "scene/resources/style_box_flat.h"
void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script) {
for (int i = 0; i < add_options.size(); i++) {
@@ -125,7 +126,7 @@ void AnimationNodeBlendTreeEditor::update_graph() {
visible_properties.clear();
- graph->set_scroll_ofs(blend_tree->get_graph_offset() * EDSCALE);
+ graph->set_scroll_offset(blend_tree->get_graph_offset() * EDSCALE);
graph->clear_connections();
//erase all nodes
@@ -347,7 +348,7 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
return;
}
- Point2 instance_pos = graph->get_scroll_ofs();
+ Point2 instance_pos = graph->get_scroll_offset();
if (use_position_from_popup_menu) {
instance_pos += position_from_popup_menu;
} else {
@@ -1091,13 +1092,13 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->set_connection_lines_curvature(graph_lines_curvature);
VSeparator *vs = memnew(VSeparator);
- graph->get_zoom_hbox()->add_child(vs);
- graph->get_zoom_hbox()->move_child(vs, 0);
+ graph->get_menu_hbox()->add_child(vs);
+ graph->get_menu_hbox()->move_child(vs, 0);
add_node = memnew(MenuButton);
- graph->get_zoom_hbox()->add_child(add_node);
+ graph->get_menu_hbox()->add_child(add_node);
add_node->set_text(TTR("Add Node..."));
- graph->get_zoom_hbox()->move_child(add_node, 0);
+ graph->get_menu_hbox()->move_child(add_node, 0);
add_node->get_popup()->connect("id_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node));
add_node->get_popup()->connect("popup_hide", callable_mp(this, &AnimationNodeBlendTreeEditor::_popup_hide), CONNECT_DEFERRED);
add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu).bind(false));
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 1fdb1d4a6e..7f4e7460f8 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -47,6 +47,7 @@
#include "scene/gui/separator.h"
#include "scene/main/window.h"
#include "scene/resources/animation.h"
+#include "scene/resources/image_texture.h"
#include "scene/scene_string_names.h"
#include "servers/rendering_server.h"
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 327200506f..8c46b5c36e 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -42,6 +42,7 @@
#include "scene/gui/tree.h"
class AnimationPlayerEditorPlugin;
+class ImageTexture;
class AnimationPlayerEditor : public VBoxContainer {
GDCLASS(AnimationPlayerEditor, VBoxContainer);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 49f073f245..0b2af0172c 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -50,6 +50,7 @@
#include "scene/gui/tree.h"
#include "scene/main/viewport.h"
#include "scene/main/window.h"
+#include "scene/resources/style_box_flat.h"
#include "scene/scene_string_names.h"
bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) {
@@ -1507,6 +1508,10 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
int base = 1;
String name = base_name;
while (state_machine->has_node(name)) {
+ if (name == prev_name) {
+ name_edit_popup->hide(); // The old name wins, the name doesn't change, just hide the popup.
+ return;
+ }
base++;
name = base_name + " " + itos(base);
}
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index eeb0fd5f66..5c26199af1 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -42,11 +42,7 @@
#include "editor/gui/editor_file_dialog.h"
#include "editor/project_settings_editor.h"
#include "scene/gui/menu_button.h"
-
-#include "modules/modules_enabled.gen.h" // For svg.
-#ifdef MODULE_SVG_ENABLED
-#include "modules/svg/image_loader_svg.h"
-#endif
+#include "scene/resources/image_texture.h"
static inline void setup_http_request(HTTPRequest *request) {
request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
@@ -775,18 +771,9 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
image->copy_internals_from(Image::_webp_mem_loader_func(r, len));
} else if ((memcmp(&r[0], &bmp_signature[0], 2) == 0) && Image::_bmp_mem_loader_func) {
image->copy_internals_from(Image::_bmp_mem_loader_func(r, len));
+ } else if (Image::_svg_scalable_mem_loader_func) {
+ image->copy_internals_from(Image::_svg_scalable_mem_loader_func(r, len, 1.0));
}
-#ifdef MODULE_SVG_ENABLED
- else {
- ImageLoaderSVG svg_loader;
- Ref<Image> img = Ref<Image>(memnew(Image));
- Error err = svg_loader.create_image_from_utf8_buffer(img, image_data, 1.0, false);
-
- if (err == OK) {
- image->copy_internals_from(img);
- }
- }
-#endif
}
if (!image->is_empty()) {
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
index e01849ff26..89579150c2 100644
--- a/editor/plugins/audio_stream_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -30,7 +30,6 @@
#include "audio_stream_editor_plugin.h"
-#include "core/core_string_names.h"
#include "editor/audio_stream_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -195,7 +194,7 @@ void AudioStreamEditor::_seek_to(real_t p_x) {
void AudioStreamEditor::set_stream(const Ref<AudioStream> &p_stream) {
if (stream.is_valid()) {
- stream->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &AudioStreamEditor::_stream_changed));
+ stream->disconnect_changed(callable_mp(this, &AudioStreamEditor::_stream_changed));
}
stream = p_stream;
@@ -203,7 +202,7 @@ void AudioStreamEditor::set_stream(const Ref<AudioStream> &p_stream) {
hide();
return;
}
- stream->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &AudioStreamEditor::_stream_changed));
+ stream->connect_changed(callable_mp(this, &AudioStreamEditor::_stream_changed));
_player->set_stream(stream);
_current = 0;
diff --git a/editor/plugins/bit_map_editor_plugin.cpp b/editor/plugins/bit_map_editor_plugin.cpp
index 30fc60b0e0..3388cab006 100644
--- a/editor/plugins/bit_map_editor_plugin.cpp
+++ b/editor/plugins/bit_map_editor_plugin.cpp
@@ -33,6 +33,7 @@
#include "editor/editor_scale.h"
#include "scene/gui/label.h"
#include "scene/gui/texture_rect.h"
+#include "scene/resources/image_texture.h"
void BitMapEditor::setup(const Ref<BitMap> &p_bitmap) {
texture_rect->set_texture(ImageTexture::create_from_image(p_bitmap->convert_to_image()));
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 937a0ba6ba..0386a05cc2 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -62,6 +62,7 @@
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
+#include "scene/resources/style_box_texture.h"
// Min and Max are power of two in order to play nicely with successive increment.
// That way, we can naturally reach a 100% zoom from boundaries.
@@ -1290,7 +1291,13 @@ void CanvasItemEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref
if (mb.is_valid()) {
// Special behvior for scroll events, as the zoom_by_increment method can smartly end up on powers of two.
int increment = p_zoom_factor > 1.0 ? 1 : -1;
- zoom_widget->set_zoom_by_increments(increment, mb->is_alt_pressed());
+ bool by_integer = mb->is_alt_pressed();
+
+ if (EDITOR_GET("editors/2d/use_integer_zoom_by_default")) {
+ by_integer = !by_integer;
+ }
+
+ zoom_widget->set_zoom_by_increments(increment, by_integer);
} else {
zoom_widget->set_zoom(zoom_widget->get_zoom() * p_zoom_factor);
}
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 4e2a629c7e..2f97cda343 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -39,12 +39,13 @@ class AcceptDialog;
class CanvasItemEditorViewport;
class ConfirmationDialog;
class EditorData;
-class EditorZoomWidget;
class EditorSelection;
+class EditorZoomWidget;
class HScrollBar;
class HSplitContainer;
class MenuButton;
class PanelContainer;
+class StyleBoxTexture;
class ViewPanner;
class VScrollBar;
class VSplitContainer;
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index ef00af592f..7be0d6c172 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -217,11 +217,16 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() {
}
{
+ Vector2 offset;
+ if (emission_mask_centered->is_pressed()) {
+ offset = Vector2(-s.width * 0.5, -s.height * 0.5);
+ }
+
PackedVector2Array points;
points.resize(valid_positions.size());
Vector2 *pointsw = points.ptrw();
for (int i = 0; i < valid_positions.size(); i += 1) {
- pointsw[i] = valid_positions[i];
+ pointsw[i] = valid_positions[i] + offset;
}
particles->set_emission_points(points);
}
@@ -281,9 +286,14 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin() {
emission_mask_mode->add_item(TTR("Solid Pixels"), EMISSION_MODE_SOLID);
emission_mask_mode->add_item(TTR("Border Pixels"), EMISSION_MODE_BORDER);
emission_mask_mode->add_item(TTR("Directed Border Pixels"), EMISSION_MODE_BORDER_DIRECTED);
+ VBoxContainer *optionsvb = memnew(VBoxContainer);
+ emvb->add_margin_child(TTR("Options"), optionsvb);
+ emission_mask_centered = memnew(CheckBox);
+ emission_mask_centered->set_text(TTR("Centered"));
+ optionsvb->add_child(emission_mask_centered);
emission_colors = memnew(CheckBox);
- emission_colors->set_text(TTR("Capture from Pixel"));
- emvb->add_margin_child(TTR("Emission Colors"), emission_colors);
+ emission_colors->set_text(TTR("Capture Colors from Pixel"));
+ optionsvb->add_child(emission_colors);
toolbar->add_child(emission_mask);
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h
index cab9fca4d6..ff8e171208 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.h
@@ -69,6 +69,7 @@ class CPUParticles2DEditorPlugin : public EditorPlugin {
ConfirmationDialog *emission_mask = nullptr;
OptionButton *emission_mask_mode = nullptr;
+ CheckBox *emission_mask_centered = nullptr;
CheckBox *emission_colors = nullptr;
String source_emission_file;
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index a1a692bdd1..6228faaa72 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -31,7 +31,6 @@
#include "curve_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
-#include "core/core_string_names.h"
#include "core/input/input.h"
#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
@@ -45,6 +44,7 @@
#include "scene/gui/menu_button.h"
#include "scene/gui/popup_menu.h"
#include "scene/gui/separator.h"
+#include "scene/resources/image_texture.h"
CurveEdit::CurveEdit() {
set_focus_mode(FOCUS_ALL);
@@ -61,14 +61,14 @@ void CurveEdit::set_curve(Ref<Curve> p_curve) {
}
if (curve.is_valid()) {
- curve->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveEdit::_curve_changed));
+ curve->disconnect_changed(callable_mp(this, &CurveEdit::_curve_changed));
curve->disconnect(Curve::SIGNAL_RANGE_CHANGED, callable_mp(this, &CurveEdit::_curve_changed));
}
curve = p_curve;
if (curve.is_valid()) {
- curve->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveEdit::_curve_changed));
+ curve->connect_changed(callable_mp(this, &CurveEdit::_curve_changed));
curve->connect(Curve::SIGNAL_RANGE_CHANGED, callable_mp(this, &CurveEdit::_curve_changed));
}
@@ -184,7 +184,9 @@ void CurveEdit::gui_input(const Ref<InputEvent> &p_event) {
toggle_linear(selected_index, selected_tangent_index);
} else {
int point_to_remove = get_point_at(mpos);
- if (point_to_remove != -1) {
+ if (point_to_remove == -1) {
+ set_selected_index(-1); // Nothing on the place of the click, just deselect the point.
+ } else {
if (grabbing == GRAB_ADD) {
curve->remove_point(point_to_remove); // Point is temporary, so remove directly from curve.
set_selected_index(-1);
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index 3068ad3f93..3c9bc991d3 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -54,8 +54,7 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) {
EditorDebuggerNode *debugger = memnew(EditorDebuggerNode);
Button *db = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Debugger"), debugger);
- // Add separation for the warning/error icon that is displayed later.
- db->add_theme_constant_override("h_separation", 6 * EDSCALE);
+ db->set_theme_type_variation("BottomPanelButton");
debugger->set_tool_button(db);
// Main editor debug menu.
diff --git a/editor/plugins/dedicated_server_export_plugin.h b/editor/plugins/dedicated_server_export_plugin.h
index cb014ae52d..8991c052b3 100644
--- a/editor/plugins/dedicated_server_export_plugin.h
+++ b/editor/plugins/dedicated_server_export_plugin.h
@@ -40,7 +40,7 @@ private:
EditorExportPreset::FileExportMode _get_export_mode_for_path(const String &p_path);
protected:
- String _get_name() const override { return "DedicatedServer"; }
+ String get_name() const override { return "DedicatedServer"; }
PackedStringArray _get_export_features(const Ref<EditorExportPlatform> &p_platform, bool p_debug) const override;
uint64_t _get_customization_configuration_hash() const override;
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 2b0691b36f..fba45e5372 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -37,8 +37,11 @@
#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "scene/resources/atlas_texture.h"
#include "scene/resources/bit_map.h"
#include "scene/resources/font.h"
+#include "scene/resources/gradient_texture.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
#include "servers/audio/audio_stream.h"
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index c3d1e920d7..5d90a746f9 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -1020,6 +1020,7 @@ EditorPropertyFontNamesArray::EditorPropertyFontNamesArray() {
if (OS::get_singleton()) {
Vector<String> fonts = OS::get_singleton()->get_system_fonts();
+ fonts.sort();
for (int i = 0; i < fonts.size(); i++) {
menu->add_item(fonts[i], i + 6);
}
diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h
index d1c47ab14e..54e6899796 100644
--- a/editor/plugins/gdextension_export_plugin.h
+++ b/editor/plugins/gdextension_export_plugin.h
@@ -36,7 +36,7 @@
class GDExtensionExportPlugin : public EditorExportPlugin {
protected:
virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features);
- virtual String _get_name() const { return "GDExtension"; }
+ virtual String get_name() const { return "GDExtension"; }
};
void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index 8631ee05c8..03d3ac1732 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -39,6 +39,7 @@
#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/separator.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/particle_process_material.h"
void GPUParticles2DEditorPlugin::edit(Object *p_object) {
@@ -292,11 +293,16 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
texdata.resize(w * h * 2 * sizeof(float));
{
+ Vector2 offset;
+ if (emission_mask_centered->is_pressed()) {
+ offset = Vector2(-s.width * 0.5, -s.height * 0.5);
+ }
+
uint8_t *tw = texdata.ptrw();
float *twf = reinterpret_cast<float *>(tw);
for (int i = 0; i < vpc; i++) {
- twf[i * 2 + 0] = valid_positions[i].x;
- twf[i * 2 + 1] = valid_positions[i].y;
+ twf[i * 2 + 0] = valid_positions[i].x + offset.x;
+ twf[i * 2 + 1] = valid_positions[i].y + offset.y;
}
}
@@ -417,9 +423,14 @@ GPUParticles2DEditorPlugin::GPUParticles2DEditorPlugin() {
emission_mask_mode->add_item(TTR("Solid Pixels"), EMISSION_MODE_SOLID);
emission_mask_mode->add_item(TTR("Border Pixels"), EMISSION_MODE_BORDER);
emission_mask_mode->add_item(TTR("Directed Border Pixels"), EMISSION_MODE_BORDER_DIRECTED);
+ VBoxContainer *optionsvb = memnew(VBoxContainer);
+ emvb->add_margin_child(TTR("Options"), optionsvb);
+ emission_mask_centered = memnew(CheckBox);
+ emission_mask_centered->set_text(TTR("Centered"));
+ optionsvb->add_child(emission_mask_centered);
emission_colors = memnew(CheckBox);
- emission_colors->set_text(TTR("Capture from Pixel"));
- emvb->add_margin_child(TTR("Emission Colors"), emission_colors);
+ emission_colors->set_text(TTR("Capture Colors from Pixel"));
+ optionsvb->add_child(emission_colors);
toolbar->add_child(emission_mask);
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h
index aa6d166d85..237a005ab7 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.h
@@ -75,6 +75,7 @@ class GPUParticles2DEditorPlugin : public EditorPlugin {
ConfirmationDialog *emission_mask = nullptr;
OptionButton *emission_mask_mode = nullptr;
+ CheckBox *emission_mask_centered = nullptr;
CheckBox *emission_colors = nullptr;
String source_emission_file;
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 65f66c2661..f0b2e32c72 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -38,6 +38,7 @@
#include "scene/3d/cpu_particles_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/menu_button.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/particle_process_material.h"
bool GPUParticles3DEditorBase::_generate(Vector<Vector3> &points, Vector<Vector3> &normals) {
diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp
index 000db06d48..59bd0f02fc 100644
--- a/editor/plugins/gradient_editor.cpp
+++ b/editor/plugins/gradient_editor.cpp
@@ -34,11 +34,12 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_undo_redo_manager.h"
+#include "scene/resources/gradient_texture.h"
void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) {
gradient = p_gradient;
connect("ramp_changed", callable_mp(this, &GradientEditor::_ramp_changed));
- gradient->connect("changed", callable_mp(this, &GradientEditor::_gradient_changed));
+ gradient->connect_changed(callable_mp(this, &GradientEditor::_gradient_changed));
set_points(gradient->get_points());
set_interpolation_mode(gradient->get_interpolation_mode());
set_interpolation_color_space(gradient->get_interpolation_color_space());
diff --git a/editor/plugins/gradient_editor.h b/editor/plugins/gradient_editor.h
index b78b740f4f..9ff39b2213 100644
--- a/editor/plugins/gradient_editor.h
+++ b/editor/plugins/gradient_editor.h
@@ -35,6 +35,8 @@
#include "scene/gui/popup.h"
#include "scene/resources/gradient.h"
+class GradientTexture1D;
+
class GradientEditor : public Control {
GDCLASS(GradientEditor, Control);
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
index 08de48af18..c48de7c3dd 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -38,6 +38,7 @@
#include "scene/gui/button.h"
#include "scene/gui/flow_container.h"
#include "scene/gui/separator.h"
+#include "scene/resources/gradient_texture.h"
Point2 GradientTexture2DEdit::_get_handle_pos(const Handle p_handle) {
// Get the handle's mouse position in pixels relative to offset.
@@ -132,7 +133,7 @@ void GradientTexture2DEdit::gui_input(const Ref<InputEvent> &p_event) {
void GradientTexture2DEdit::set_texture(Ref<GradientTexture2D> &p_texture) {
texture = p_texture;
- texture->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ texture->connect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
void GradientTexture2DEdit::set_snap_enabled(bool p_snap_enabled) {
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.h b/editor/plugins/gradient_texture_2d_editor_plugin.h
index 2816b11d74..33570593cc 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.h
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.h
@@ -36,6 +36,7 @@
class Button;
class EditorSpinSlider;
+class GradientTexture2D;
class GradientTexture2DEdit : public Control {
GDCLASS(GradientTexture2DEdit, Control);
diff --git a/editor/plugins/input_event_editor_plugin.cpp b/editor/plugins/input_event_editor_plugin.cpp
index be36447432..9a54a8c1a1 100644
--- a/editor/plugins/input_event_editor_plugin.cpp
+++ b/editor/plugins/input_event_editor_plugin.cpp
@@ -77,7 +77,7 @@ void InputEventConfigContainer::set_event(const Ref<InputEvent> &p_event) {
input_event = p_event;
_event_changed();
- input_event->connect("changed", callable_mp(this, &InputEventConfigContainer::_event_changed));
+ input_event->connect_changed(callable_mp(this, &InputEventConfigContainer::_event_changed));
}
InputEventConfigContainer::InputEventConfigContainer() {
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 4b65ce7304..68d3661d10 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -1583,6 +1583,22 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
}
}
+// This is only active during instant transforms,
+// to capture and wrap mouse events outside the control.
+void Node3DEditorViewport::input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(!_edit.instant);
+ Ref<InputEventMouseMotion> m = p_event;
+
+ if (m.is_valid()) {
+ if (_edit.mode == TRANSFORM_ROTATE) {
+ _edit.mouse_pos = m->get_position(); // rotate should not wrap
+ } else {
+ _edit.mouse_pos += _get_warped_mouse_motion(p_event);
+ }
+ update_transform(_get_key_modifier(m) == Key::SHIFT);
+ }
+}
+
void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (previewing) {
return; //do NONE
@@ -1906,7 +1922,8 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> m = p_event;
- if (m.is_valid()) {
+ // Instant transforms process mouse motion in input() to handle wrapping.
+ if (m.is_valid() && !_edit.instant) {
_edit.mouse_pos = m->get_position();
if (spatial_editor->get_single_selected_node()) {
@@ -1956,7 +1973,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle, _edit.gizmo_handle_secondary);
set_message(n + ": " + String(v));
- } else if (m->get_button_mask().has_flag(MouseButtonMask::LEFT) || _edit.instant) {
+ } else if (m->get_button_mask().has_flag(MouseButtonMask::LEFT)) {
if (nav_scheme == NAVIGATION_MAYA && m->is_alt_pressed()) {
nav_mode = NAVIGATION_ORBIT;
} else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed() && m->is_shift_pressed()) {
@@ -1993,7 +2010,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
return;
}
- update_transform(m->get_position(), _get_key_modifier(m) == Key::SHIFT);
+ update_transform(_get_key_modifier(m) == Key::SHIFT);
}
} else if (m->get_button_mask().has_flag(MouseButtonMask::RIGHT) || freelook_active) {
if (nav_scheme == NAVIGATION_MAYA && m->is_alt_pressed()) {
@@ -2183,7 +2200,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_edit.plane = TRANSFORM_VIEW;
spatial_editor->set_local_coords_enabled(false);
}
- update_transform(_edit.mouse_pos, Input::get_singleton()->is_key_pressed(Key::SHIFT));
+ update_transform(Input::get_singleton()->is_key_pressed(Key::SHIFT));
set_message(new_message, 2);
accept_event();
return;
@@ -4515,9 +4532,11 @@ void Node3DEditorViewport::begin_transform(TransformMode p_mode, bool instant) {
_edit.instant = instant;
_edit.snap = spatial_editor->is_snap_enabled();
update_transform_gizmo_view();
+ set_process_input(instant);
}
}
+// Apply the current transform operation.
void Node3DEditorViewport::commit_transform() {
ERR_FAIL_COND(_edit.mode == TRANSFORM_NONE);
static const char *_transform_name[4] = {
@@ -4552,9 +4571,10 @@ void Node3DEditorViewport::commit_transform() {
set_message("");
}
-void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
- Vector3 ray_pos = _get_ray_pos(p_mousepos);
- Vector3 ray = _get_ray(p_mousepos);
+// Update the current transform operation in response to an input.
+void Node3DEditorViewport::update_transform(bool p_shift) {
+ Vector3 ray_pos = _get_ray_pos(_edit.mouse_pos);
+ Vector3 ray = _get_ray(_edit.mouse_pos);
double snap = EDITOR_GET("interface/inspector/default_float_step");
int snap_step_decimals = Math::range_step_decimals(snap);
@@ -4894,12 +4914,14 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
}
+// Perform cleanup after a transform operation is committed or cancelled.
void Node3DEditorViewport::finish_transform() {
spatial_editor->set_local_coords_enabled(_edit.original_local);
_edit.mode = TRANSFORM_NONE;
_edit.instant = false;
spatial_editor->update_transform_gizmo();
surface->queue_redraw();
+ set_process_input(false);
}
// Register a shortcut and also add it as an input action with the same events.
@@ -4907,7 +4929,7 @@ void Node3DEditorViewport::register_shortcut_action(const String &p_path, const
Ref<Shortcut> sc = ED_SHORTCUT(p_path, p_name, p_keycode, p_physical);
shortcut_changed_callback(sc, p_path);
// Connect to the change event on the shortcut so the input binding can be updated.
- sc->connect("changed", callable_mp(this, &Node3DEditorViewport::shortcut_changed_callback).bind(sc, p_path));
+ sc->connect_changed(callable_mp(this, &Node3DEditorViewport::shortcut_changed_callback).bind(sc, p_path));
}
// Update the action in the InputMap to the provided shortcut events.
@@ -7925,6 +7947,8 @@ void Node3DEditor::clear() {
}
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true);
+ grid_enabled = true;
+ grid_init_draw = false;
}
void Node3DEditor::_sun_direction_draw() {
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 28803e67cb..79674bdd64 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -401,6 +401,7 @@ private:
void _surface_focus_enter();
void _surface_focus_exit();
+ void input(const Ref<InputEvent> &p_event) override;
void _sinput(const Ref<InputEvent> &p_event);
void _update_freelook(real_t delta);
Node3DEditor *spatial_editor = nullptr;
@@ -444,7 +445,7 @@ private:
void begin_transform(TransformMode p_mode, bool instant);
void commit_transform();
- void update_transform(Point2 p_mousepos, bool p_shift);
+ void update_transform(bool p_shift);
void finish_transform();
void register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode, bool p_physical = false);
diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index efbb2b0d2b..ceff9cb5f3 100644
--- a/editor/plugins/polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -30,7 +30,6 @@
#include "polygon_3d_editor_plugin.h"
-#include "core/core_string_names.h"
#include "core/input/input.h"
#include "core/io/file_access.h"
#include "core/math/geometry_2d.h"
@@ -497,7 +496,7 @@ void Polygon3DEditor::edit(Node *p_node) {
node_resource = node->call("_get_editable_3d_polygon_resource");
if (node_resource.is_valid()) {
- node_resource->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Polygon3DEditor::_polygon_draw));
+ node_resource->connect_changed(callable_mp(this, &Polygon3DEditor::_polygon_draw));
}
//Enable the pencil tool if the polygon is empty
if (_get_polygon().is_empty()) {
@@ -518,7 +517,7 @@ void Polygon3DEditor::edit(Node *p_node) {
} else {
node = nullptr;
if (node_resource.is_valid()) {
- node_resource->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Polygon3DEditor::_polygon_draw));
+ node_resource->disconnect_changed(callable_mp(this, &Polygon3DEditor::_polygon_draw));
}
node_resource.unref();
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 1d449d79a6..78ba26503d 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -846,13 +846,14 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
_update_selected_editor_menu();
}
- _update_history_arrows();
-
- _update_script_names();
- _update_members_overview_visibility();
- _update_help_overview_visibility();
- _save_layout();
- _update_find_replace_bar();
+ if (script_close_queue.is_empty()) {
+ _update_history_arrows();
+ _update_script_names();
+ _update_members_overview_visibility();
+ _update_help_overview_visibility();
+ _save_layout();
+ _update_find_replace_bar();
+ }
}
void ScriptEditor::_close_current_tab(bool p_save) {
@@ -2434,6 +2435,18 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
return true;
}
+PackedStringArray ScriptEditor::get_unsaved_scripts() const {
+ PackedStringArray unsaved_list;
+
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
+ if (se && se->is_unsaved()) {
+ unsaved_list.append(se->get_name());
+ }
+ }
+ return unsaved_list;
+}
+
void ScriptEditor::save_current_script() {
ScriptEditorBase *current = _get_current_editor();
if (!current || _test_script_times_on_disk()) {
@@ -3911,8 +3924,8 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
_update_recent_scripts();
file_menu->get_popup()->add_separator();
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL | Key::S), FILE_SAVE);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As...")), FILE_SAVE_AS);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KeyModifierMask::CMD_OR_CTRL | Key::S), FILE_SAVE);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::S), FILE_SAVE_AS);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KeyModifierMask::SHIFT | KeyModifierMask::ALT | Key::S), FILE_SAVE_ALL);
ED_SHORTCUT_OVERRIDE("script_editor/save_all", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::S);
file_menu->get_popup()->add_separator();
@@ -4206,8 +4219,53 @@ void ScriptEditorPlugin::selected_notify() {
_focus_another_editor();
}
+String ScriptEditorPlugin::get_unsaved_status(const String &p_for_scene) const {
+ const PackedStringArray unsaved_scripts = script_editor->get_unsaved_scripts();
+ if (unsaved_scripts.is_empty()) {
+ return String();
+ }
+
+ PackedStringArray message;
+ if (!p_for_scene.is_empty()) {
+ PackedStringArray unsaved_built_in_scripts;
+
+ const String scene_file = p_for_scene.get_file();
+ for (const String &E : unsaved_scripts) {
+ if (!E.is_resource_file() && E.contains(scene_file)) {
+ unsaved_built_in_scripts.append(E);
+ }
+ }
+
+ if (unsaved_built_in_scripts.is_empty()) {
+ return String();
+ } else {
+ message.resize(unsaved_built_in_scripts.size() + 1);
+ message.write[0] = TTR("There are unsaved changes in the following built-in script(s):");
+
+ int i = 1;
+ for (const String &E : unsaved_built_in_scripts) {
+ message.write[i] = E.trim_suffix("(*)");
+ i++;
+ }
+ return String("\n").join(message);
+ }
+ }
+
+ message.resize(unsaved_scripts.size() + 1);
+ message.write[0] = TTR("Save changes to the following script(s) before quitting?");
+
+ int i = 1;
+ for (const String &E : unsaved_scripts) {
+ message.write[i] = E.trim_suffix("(*)");
+ i++;
+ }
+ return String("\n").join(message);
+}
+
void ScriptEditorPlugin::save_external_data() {
- script_editor->save_all_scripts();
+ if (!EditorNode::get_singleton()->is_exiting()) {
+ script_editor->save_all_scripts();
+ }
}
void ScriptEditorPlugin::apply_changes() {
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index e879920e41..198aaa6c4e 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -512,6 +512,7 @@ public:
void get_breakpoints(List<String> *p_breakpoints);
+ PackedStringArray get_unsaved_scripts() const;
void save_current_script();
void save_all_scripts();
@@ -572,6 +573,7 @@ public:
virtual void make_visible(bool p_visible) override;
virtual void selected_notify() override;
+ virtual String get_unsaved_status(const String &p_for_scene) const override;
virtual void save_external_data() override;
virtual void apply_changes() override;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 5fdfb21176..321c0f34b5 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -282,6 +282,22 @@ void ScriptTextEditor::_error_clicked(Variant p_line) {
if (p_line.get_type() == Variant::INT) {
code_editor->get_text_editor()->remove_secondary_carets();
code_editor->get_text_editor()->set_caret_line(p_line.operator int64_t());
+ } else if (p_line.get_type() == Variant::DICTIONARY) {
+ Dictionary meta = p_line.operator Dictionary();
+ const String path = meta["path"].operator String();
+ const int line = meta["line"].operator int64_t();
+ const int column = meta["column"].operator int64_t();
+ if (path.is_empty()) {
+ code_editor->get_text_editor()->remove_secondary_carets();
+ code_editor->get_text_editor()->set_caret_line(line);
+ } else {
+ Ref<Resource> scr = ResourceLoader::load(path);
+ if (!scr.is_valid()) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not load file at:") + "\n\n" + path, TTR("Error!"));
+ } else {
+ ScriptEditor::get_singleton()->edit(scr, line, column);
+ }
+ }
}
}
@@ -458,9 +474,17 @@ void ScriptTextEditor::_validate_script() {
warnings.clear();
errors.clear();
+ depended_errors.clear();
safe_lines.clear();
if (!script->get_language()->validate(text, script->get_path(), &fnc, &errors, &warnings, &safe_lines)) {
+ for (List<ScriptLanguage::ScriptError>::Element *E = errors.front(); E; E = E->next()) {
+ if (E->get().path.is_empty() || E->get().path != script->get_path()) {
+ depended_errors[E->get().path].push_back(E->get());
+ E->erase();
+ }
+ }
+
// TRANSLATORS: Script error pointing to a line and column number.
String error_text = vformat(TTR("Error at (%d, %d):"), errors[0].line, errors[0].column) + " " + errors[0].message;
code_editor->set_error(error_text);
@@ -560,6 +584,10 @@ void ScriptTextEditor::_update_errors() {
errors_panel->clear();
errors_panel->push_table(2);
for (const ScriptLanguage::ScriptError &err : errors) {
+ Dictionary click_meta;
+ click_meta["line"] = err.line;
+ click_meta["column"] = err.column;
+
errors_panel->push_cell();
errors_panel->push_meta(err.line - 1);
errors_panel->push_color(warnings_panel->get_theme_color(SNAME("error_color"), SNAME("Editor")));
@@ -575,6 +603,41 @@ void ScriptTextEditor::_update_errors() {
}
errors_panel->pop(); // Table
+ for (const KeyValue<String, List<ScriptLanguage::ScriptError>> &KV : depended_errors) {
+ Dictionary click_meta;
+ click_meta["path"] = KV.key;
+ click_meta["line"] = 1;
+
+ errors_panel->add_newline();
+ errors_panel->add_newline();
+ errors_panel->push_meta(click_meta);
+ errors_panel->add_text(vformat(R"(%s:)", KV.key));
+ errors_panel->pop(); // Meta goto.
+ errors_panel->add_newline();
+
+ errors_panel->push_indent(1);
+ errors_panel->push_table(2);
+ String filename = KV.key.get_file();
+ for (const ScriptLanguage::ScriptError &err : KV.value) {
+ click_meta["line"] = err.line;
+ click_meta["column"] = err.column;
+
+ errors_panel->push_cell();
+ errors_panel->push_meta(click_meta);
+ errors_panel->push_color(errors_panel->get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ errors_panel->add_text(TTR("Line") + " " + itos(err.line) + ":");
+ errors_panel->pop(); // Color.
+ errors_panel->pop(); // Meta goto.
+ errors_panel->pop(); // Cell.
+
+ errors_panel->push_cell();
+ errors_panel->add_text(err.message);
+ errors_panel->pop(); // Cell.
+ }
+ errors_panel->pop(); // Table
+ errors_panel->pop(); // Indent.
+ }
+
CodeEdit *te = code_editor->get_text_editor();
bool highlight_safe = EDITOR_GET("text_editor/appearance/gutters/highlight_type_safe_lines");
bool last_is_safe = false;
@@ -811,6 +874,8 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
}
ScriptLanguage::LookupResult result;
+ String code_text = code_editor->get_text_editor()->get_text_with_cursor_char(p_row, p_column);
+ 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()) {
@@ -823,7 +888,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
EditorNode::get_singleton()->load_resource(p_symbol);
}
- } else if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), p_symbol, script->get_path(), base, result) == OK) {
+ } else if (lc_error == OK) {
_goto_line(p_row);
switch (result.type) {
@@ -944,7 +1009,10 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) {
}
ScriptLanguage::LookupResult result;
- if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), p_symbol, script->get_path(), base, result) == OK || (ProjectSettings::get_singleton()->has_autoload(p_symbol) && ProjectSettings::get_singleton()->get_autoload(p_symbol).is_singleton)) {
+ 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) {
text_edit->set_symbol_lookup_word_as_valid(true);
} else if (p_symbol.is_relative_path()) {
String path = _get_absolute_path(p_symbol);
@@ -1726,9 +1794,17 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
String variable_name = String(node->get_name()).to_snake_case().validate_identifier();
if (use_type) {
- text_to_drop += vformat("@onready var %s: %s = %s%s\n", variable_name, node->get_class_name(), is_unique ? "%" : "$", path);
+ StringName class_name = node->get_class_name();
+ Ref<Script> node_script = node->get_script();
+ if (node_script.is_valid()) {
+ StringName global_node_script_name = node_script->get_global_name();
+ if (global_node_script_name != StringName()) {
+ class_name = global_node_script_name;
+ }
+ }
+ text_to_drop += vformat("@onready var %s: %s = %c%s\n", variable_name, class_name, is_unique ? '%' : '$', path);
} else {
- text_to_drop += vformat("@onready var %s = %s%s\n", variable_name, is_unique ? "%" : "$", path);
+ text_to_drop += vformat("@onready var %s = %c%s\n", variable_name, is_unique ? '%' : '$', path);
}
}
} else {
@@ -1841,7 +1917,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
bool open_docs = false;
bool goto_definition = false;
- if (word_at_pos.is_resource_file()) {
+ if (ScriptServer::is_global_class(word_at_pos) || word_at_pos.is_resource_file()) {
open_docs = true;
} else {
Node *base = get_tree()->get_edited_scene_root();
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 808a6417e4..d275013b91 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -68,6 +68,7 @@ class ScriptTextEditor : public ScriptEditorBase {
Vector<String> functions;
List<ScriptLanguage::Warning> warnings;
List<ScriptLanguage::ScriptError> errors;
+ HashMap<String, List<ScriptLanguage::ScriptError>> depended_errors;
HashSet<int> safe_lines;
List<Connection> missing_connections;
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 268828e8f5..247586fbfc 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -287,6 +287,27 @@ void ShaderEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) {
p_layout->set_value("ShaderEditor", "selected_shader", selected_shader);
}
+String ShaderEditorPlugin::get_unsaved_status(const String &p_for_scene) const {
+ if (!p_for_scene.is_empty()) {
+ // TODO: handle built-in shaders.
+ return String();
+ }
+
+ // TODO: This should also include visual shaders and shader includes, but save_external_data() doesn't seem to save them...
+ PackedStringArray unsaved_shaders;
+ for (uint32_t i = 0; i < edited_shaders.size(); i++) {
+ if (edited_shaders[i].shader_editor) {
+ if (edited_shaders[i].shader_editor->is_unsaved()) {
+ if (unsaved_shaders.is_empty()) {
+ unsaved_shaders.append(TTR("Save changes to the following shaders(s) before quitting?"));
+ }
+ unsaved_shaders.append(edited_shaders[i].shader_editor->get_name());
+ }
+ }
+ }
+ return String("\n").join(unsaved_shaders);
+}
+
void ShaderEditorPlugin::save_external_data() {
for (EditedShader &edited_shader : edited_shaders) {
if (edited_shader.shader_editor) {
diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h
index 45b48a2f91..fb7b283266 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -115,6 +115,7 @@ public:
virtual void set_window_layout(Ref<ConfigFile> p_layout) override;
virtual void get_window_layout(Ref<ConfigFile> p_layout) override;
+ virtual String get_unsaved_status(const String &p_for_scene) const override;
virtual void save_external_data() override;
virtual void apply_changes() override;
diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp
index f9aa14dd09..b0e532b136 100644
--- a/editor/plugins/shader_file_editor_plugin.cpp
+++ b/editor/plugins/shader_file_editor_plugin.cpp
@@ -222,7 +222,7 @@ void ShaderFileEditor::_bind_methods() {
void ShaderFileEditor::edit(const Ref<RDShaderFile> &p_shader) {
if (p_shader.is_null()) {
if (shader_file.is_valid()) {
- shader_file->disconnect("changed", callable_mp(this, &ShaderFileEditor::_shader_changed));
+ shader_file->disconnect_changed(callable_mp(this, &ShaderFileEditor::_shader_changed));
}
return;
}
@@ -234,7 +234,7 @@ void ShaderFileEditor::edit(const Ref<RDShaderFile> &p_shader) {
shader_file = p_shader;
if (shader_file.is_valid()) {
- shader_file->connect("changed", callable_mp(this, &ShaderFileEditor::_shader_changed));
+ shader_file->connect_changed(callable_mp(this, &ShaderFileEditor::_shader_changed));
}
_update_options();
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 563398e512..7b35351457 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -46,6 +46,7 @@
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/separator.h"
+#include "scene/resources/atlas_texture.h"
static void _draw_shadowed_line(Control *p_control, const Point2 &p_from, const Size2 &p_size, const Size2 &p_shadow_offset, Color p_color, Color p_shadow_color) {
p_control->draw_line(p_from, p_from + p_size, p_color);
@@ -948,13 +949,16 @@ void SpriteFramesEditor::_animation_name_edited() {
String name = new_name;
int counter = 0;
while (frames->has_animation(name)) {
+ if (name == String(edited_anim)) {
+ edited->set_text(0, name); // The name didn't change, just updated the column text to name.
+ return;
+ }
counter++;
name = new_name + "_" + itos(counter);
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Animation"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
- _rename_node_animation(undo_redo, false, edited_anim, "", "");
undo_redo->add_do_method(frames.ptr(), "rename_animation", edited_anim, name);
undo_redo->add_undo_method(frames.ptr(), "rename_animation", name, edited_anim);
_rename_node_animation(undo_redo, false, edited_anim, name, name);
@@ -1208,30 +1212,29 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
bool searching = anim_search_box->get_text().size();
String searched_string = searching ? anim_search_box->get_text().to_lower() : String();
+ TreeItem *selected = nullptr;
for (const StringName &E : anim_names) {
String name = E;
-
if (searching && name.to_lower().find(searched_string) < 0) {
continue;
}
-
TreeItem *it = animations->create_item(anim_root);
-
it->set_metadata(0, name);
-
it->set_text(0, name);
it->set_editable(0, true);
-
if (animated_sprite) {
if (name == String(animated_sprite->call("get_autoplay"))) {
it->set_icon(0, autoplay_icon);
}
}
-
if (E == edited_anim) {
it->select(0);
+ selected = it;
}
}
+ if (selected) {
+ animations->scroll_to_item(selected);
+ }
}
if (animated_sprite) {
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index a53f8f73d9..ed75be9061 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -44,6 +44,7 @@
#include "scene/gui/split_container.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
+#include "scene/resources/image_texture.h"
class OptionButton;
class EditorFileDialog;
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index c126aec008..1d14f5e60b 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_scale.h"
#include "scene/gui/button.h"
+#include "scene/resources/style_box_texture.h"
bool StyleBoxPreview::grid_preview_enabled = true;
@@ -42,11 +43,11 @@ void StyleBoxPreview::_grid_preview_toggled(bool p_active) {
void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) {
if (stylebox.is_valid()) {
- stylebox->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ stylebox->disconnect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
stylebox = p_stylebox;
if (stylebox.is_valid()) {
- stylebox->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ stylebox->connect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
Ref<StyleBoxTexture> sbt = stylebox;
grid_preview->set_visible(sbt.is_valid());
diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp
index 791746da96..ed98c7f85c 100644
--- a/editor/plugins/text_shader_editor.cpp
+++ b/editor/plugins/text_shader_editor.cpp
@@ -122,7 +122,7 @@ void ShaderTextEditor::set_edited_shader(const Ref<Shader> &p_shader, const Stri
return;
}
if (shader.is_valid()) {
- shader->disconnect(SNAME("changed"), callable_mp(this, &ShaderTextEditor::_shader_changed));
+ shader->disconnect_changed(callable_mp(this, &ShaderTextEditor::_shader_changed));
}
shader = p_shader;
shader_inc = Ref<ShaderInclude>();
@@ -130,7 +130,7 @@ void ShaderTextEditor::set_edited_shader(const Ref<Shader> &p_shader, const Stri
set_edited_code(p_code);
if (shader.is_valid()) {
- shader->connect(SNAME("changed"), callable_mp(this, &ShaderTextEditor::_shader_changed));
+ shader->connect_changed(callable_mp(this, &ShaderTextEditor::_shader_changed));
}
}
@@ -152,7 +152,7 @@ void ShaderTextEditor::set_edited_shader_include(const Ref<ShaderInclude> &p_sha
return;
}
if (shader_inc.is_valid()) {
- shader_inc->disconnect(SNAME("changed"), callable_mp(this, &ShaderTextEditor::_shader_changed));
+ shader_inc->disconnect_changed(callable_mp(this, &ShaderTextEditor::_shader_changed));
}
shader_inc = p_shader_inc;
shader = Ref<Shader>();
@@ -160,7 +160,7 @@ void ShaderTextEditor::set_edited_shader_include(const Ref<ShaderInclude> &p_sha
set_edited_code(p_code);
if (shader_inc.is_valid()) {
- shader_inc->connect(SNAME("changed"), callable_mp(this, &ShaderTextEditor::_shader_changed));
+ shader_inc->connect_changed(callable_mp(this, &ShaderTextEditor::_shader_changed));
}
}
@@ -238,7 +238,7 @@ void ShaderTextEditor::_load_theme_settings() {
ShaderPreprocessor::get_keyword_list(&pp_keywords, false);
for (const String &E : pp_keywords) {
- syntax_highlighter->add_keyword_color(E, keyword_color);
+ syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);
}
// Colorize built-ins like `COLOR` differently to make them easier
@@ -646,13 +646,13 @@ void TextShaderEditor::_menu_option(int p_option) {
shader_editor->move_lines_down();
} break;
case EDIT_INDENT: {
- if (shader.is_null()) {
+ if (shader.is_null() && shader_inc.is_null()) {
return;
}
shader_editor->get_text_editor()->indent_lines();
} break;
case EDIT_UNINDENT: {
- if (shader.is_null()) {
+ if (shader.is_null() && shader_inc.is_null()) {
return;
}
shader_editor->get_text_editor()->unindent_lines();
@@ -668,12 +668,10 @@ void TextShaderEditor::_menu_option(int p_option) {
shader_editor->get_text_editor()->set_line_wrapping_mode(wrap == TextEdit::LINE_WRAPPING_BOUNDARY ? TextEdit::LINE_WRAPPING_NONE : TextEdit::LINE_WRAPPING_BOUNDARY);
} break;
case EDIT_TOGGLE_COMMENT: {
- if (shader.is_null()) {
+ if (shader.is_null() && shader_inc.is_null()) {
return;
}
-
shader_editor->toggle_inline_comment("//");
-
} break;
case EDIT_COMPLETE: {
shader_editor->get_text_editor()->request_code_completion();
diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp
index 9904b888f2..2702e94188 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -115,7 +115,7 @@ void Texture3DEditor::_texture_rect_update_area() {
void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
if (!texture.is_null()) {
- texture->disconnect("changed", callable_mp(this, &Texture3DEditor::_texture_changed));
+ texture->disconnect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));
}
texture = p_texture;
@@ -125,7 +125,7 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
_make_shaders();
}
- texture->connect("changed", callable_mp(this, &Texture3DEditor::_texture_changed));
+ texture->connect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));
queue_redraw();
texture_rect->set_material(material);
setting = true;
@@ -176,7 +176,7 @@ Texture3DEditor::Texture3DEditor() {
Texture3DEditor::~Texture3DEditor() {
if (!texture.is_null()) {
- texture->disconnect("changed", callable_mp(this, &Texture3DEditor::_texture_changed));
+ texture->disconnect_changed(callable_mp(this, &Texture3DEditor::_texture_changed));
}
}
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index 1a9e09f3b1..87b207ebcd 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -29,9 +29,14 @@
/**************************************************************************/
#include "texture_editor_plugin.h"
+
#include "editor/editor_scale.h"
#include "scene/gui/label.h"
#include "scene/gui/texture_rect.h"
+#include "scene/resources/animated_texture.h"
+#include "scene/resources/atlas_texture.h"
+#include "scene/resources/compressed_texture.h"
+#include "scene/resources/image_texture.h"
TextureRect *TexturePreview::get_texture_display() {
return texture_display;
@@ -135,7 +140,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
metadata_label = memnew(Label);
_update_metadata_label_text();
- p_texture->connect("changed", callable_mp(this, &TexturePreview::_update_metadata_label_text));
+ p_texture->connect_changed(callable_mp(this, &TexturePreview::_update_metadata_label_text));
// It's okay that these colors are static since the grid color is static too.
metadata_label->add_theme_color_override("font_color", Color::named("white"));
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index 816d081617..a0188b08e5 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -181,7 +181,7 @@ void TextureLayeredEditor::_texture_rect_update_area() {
void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) {
if (!texture.is_null()) {
- texture->disconnect("changed", callable_mp(this, &TextureLayeredEditor::_texture_changed));
+ texture->disconnect_changed(callable_mp(this, &TextureLayeredEditor::_texture_changed));
}
texture = p_texture;
@@ -191,7 +191,7 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) {
_make_shaders();
}
- texture->connect("changed", callable_mp(this, &TextureLayeredEditor::_texture_changed));
+ texture->connect_changed(callable_mp(this, &TextureLayeredEditor::_texture_changed));
queue_redraw();
texture_rect->set_material(materials[texture->get_layered_type()]);
setting = true;
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index f2e650a604..19df31a0b3 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -30,7 +30,6 @@
#include "texture_region_editor_plugin.h"
-#include "core/core_string_names.h"
#include "core/input/input.h"
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
@@ -42,7 +41,7 @@
#include "scene/gui/separator.h"
#include "scene/gui/spin_box.h"
#include "scene/gui/view_panner.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/atlas_texture.h"
void draw_margin_line(Control *edit_draw, Vector2 from, Vector2 to) {
Vector2 line = (to - from).normalized() * 10;
@@ -433,7 +432,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} else if (obj_styleBox.is_valid()) {
undo_redo->add_do_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], obj_styleBox->get_texture_margin(side[edited_margin]));
undo_redo->add_undo_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], prev_margin);
- obj_styleBox->emit_signal(CoreStringNames::get_singleton()->changed);
+ obj_styleBox->emit_changed();
}
edited_margin = -1;
} else {
@@ -913,10 +912,10 @@ void TextureRegionEditor::edit(Object *p_obj) {
node_ninepatch->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (obj_styleBox.is_valid()) {
- obj_styleBox->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
+ obj_styleBox->disconnect_changed(callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (atlas_tex.is_valid()) {
- atlas_tex->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
+ atlas_tex->disconnect_changed(callable_mp(this, &TextureRegionEditor::_texture_changed));
}
node_sprite_2d = nullptr;
@@ -941,7 +940,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
}
if (is_resource) {
- p_obj->connect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
+ Object::cast_to<Resource>(p_obj)->connect_changed(callable_mp(this, &TextureRegionEditor::_texture_changed));
} else {
p_obj->connect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index c303cec3f5..6b7a198246 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -38,11 +38,11 @@
#include "scene/3d/sprite_3d.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/nine_patch_rect.h"
-#include "scene/resources/style_box.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/style_box_texture.h"
-class ViewPanner;
+class AtlasTexture;
class OptionButton;
+class ViewPanner;
class TextureRegionEditor : public AcceptDialog {
GDCLASS(TextureRegionEditor, AcceptDialog);
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 09053db122..a1ddfc4b85 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -3151,7 +3151,7 @@ void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_ite
void ThemeTypeEditor::_change_pinned_stylebox() {
if (leading_stylebox.pinned) {
if (leading_stylebox.stylebox.is_valid()) {
- leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
Ref<StyleBox> new_stylebox = edited_theme->get_stylebox(leading_stylebox.item_name, edited_type);
@@ -3159,10 +3159,10 @@ void ThemeTypeEditor::_change_pinned_stylebox() {
leading_stylebox.ref_stylebox = (new_stylebox.is_valid() ? new_stylebox->duplicate() : Ref<Resource>());
if (leading_stylebox.stylebox.is_valid()) {
- new_stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ new_stylebox->connect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
} else if (leading_stylebox.stylebox.is_valid()) {
- leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
}
@@ -3187,7 +3187,7 @@ void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_
void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_stylebox) {
if (leading_stylebox.stylebox.is_valid()) {
- leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
LeadingStylebox leader;
@@ -3198,7 +3198,7 @@ void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_
leading_stylebox = leader;
if (p_stylebox.is_valid()) {
- p_stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ p_stylebox->connect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
_update_type_items();
@@ -3214,7 +3214,7 @@ void ThemeTypeEditor::_on_unpin_leader_button_pressed() {
void ThemeTypeEditor::_unpin_leading_stylebox() {
if (leading_stylebox.stylebox.is_valid()) {
- leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
LeadingStylebox leader;
@@ -3337,12 +3337,12 @@ void ThemeTypeEditor::_bind_methods() {
void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {
if (edited_theme.is_valid()) {
- edited_theme->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
+ edited_theme->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
}
edited_theme = p_theme;
if (edited_theme.is_valid()) {
- edited_theme->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
+ edited_theme->connect_changed(callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
_update_type_list();
}
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index f4a6c4af2d..fb8cb57d4d 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -321,7 +321,7 @@ DefaultThemeEditorPreview::DefaultThemeEditorPreview() {
first_vb->add_child(bt);
Button *tb = memnew(Button);
tb->set_flat(true);
- tb->set_text("Button");
+ tb->set_text("Flat Button");
first_vb->add_child(tb);
CheckButton *cb = memnew(CheckButton);
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index 7ed9c9d61b..937480eb50 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -36,6 +36,7 @@
#include "editor/gui/editor_file_dialog.h"
#include "scene/gui/control.h"
#include "scene/gui/split_container.h"
+#include "scene/resources/image_texture.h"
void AtlasMergingDialog::_property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {
_set(p_property, p_value);
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index ef805e6524..0fbce2a677 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -88,11 +88,11 @@ void TileDataEditor::_bind_methods() {
void TileDataEditor::set_tile_set(Ref<TileSet> p_tile_set) {
if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileDataEditor::_tile_set_changed_plan_update));
+ tile_set->disconnect_changed(callable_mp(this, &TileDataEditor::_tile_set_changed_plan_update));
}
tile_set = p_tile_set;
if (tile_set.is_valid()) {
- tile_set->connect("changed", callable_mp(this, &TileDataEditor::_tile_set_changed_plan_update));
+ tile_set->connect_changed(callable_mp(this, &TileDataEditor::_tile_set_changed_plan_update));
}
_tile_set_changed_plan_update();
}
@@ -685,6 +685,14 @@ void GenericTilePolygonEditor::_store_snap_options() {
EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "tile_snap_subdiv", snap_subdivision->get_value());
}
+void GenericTilePolygonEditor::_toggle_expand(bool p_expand) {
+ if (p_expand) {
+ TileSetEditor::get_singleton()->add_expanded_editor(this);
+ } else {
+ TileSetEditor::get_singleton()->remove_expanded_editor();
+ }
+}
+
void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) {
use_undo_redo = p_use_undo_redo;
}
@@ -793,8 +801,13 @@ void GenericTilePolygonEditor::set_multiple_polygon_mode(bool p_multiple_polygon
void GenericTilePolygonEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_ENTER_TREE: {
+ if (!get_meta("reparented", false)) {
+ button_expand->set_pressed_no_signal(false);
+ }
+ } break;
case NOTIFICATION_THEME_CHANGED: {
+ button_expand->set_icon(get_theme_icon(SNAME("DistractionFree"), SNAME("EditorIcons")));
button_create->set_icon(get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
button_edit->set_icon(get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
button_delete->set_icon(get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons")));
@@ -831,6 +844,16 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
tools_button_group.instantiate();
+ button_expand = memnew(Button);
+ button_expand->set_flat(true);
+ button_expand->set_toggle_mode(true);
+ button_expand->set_pressed(false);
+ button_expand->set_tooltip_text(TTR("Expand editor"));
+ button_expand->connect("toggled", callable_mp(this, &GenericTilePolygonEditor::_toggle_expand));
+ toolbar->add_child(button_expand);
+
+ toolbar->add_child(memnew(VSeparator));
+
button_create = memnew(Button);
button_create->set_flat(true);
button_create->set_toggle_mode(true);
@@ -885,7 +908,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
snap_subdivision->set_max(99);
Control *root = memnew(Control);
- root->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ root->set_v_size_flags(Control::SIZE_EXPAND_FILL);
root->set_custom_minimum_size(Size2(0, 200 * EDSCALE));
root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
add_child(root);
@@ -1185,19 +1208,18 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2
Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
int font_size = TileSetEditor::get_singleton()->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
String text;
+ // Round floating point precision to 2 digits, as tiles don't have that much space.
switch (value.get_type()) {
- case Variant::INT:
- text = vformat("%d", value);
- break;
case Variant::FLOAT:
text = vformat("%.2f", value);
break;
- case Variant::STRING:
- case Variant::STRING_NAME:
- text = value;
+ case Variant::VECTOR2:
+ case Variant::VECTOR3:
+ case Variant::VECTOR4:
+ text = vformat("%.2v", value);
break;
default:
- return;
+ text = value.stringify();
break;
}
@@ -1216,8 +1238,8 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2
}
Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
- p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1));
- p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color);
+ p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 4), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 3, Color(0, 0, 0));
+ p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 4), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color);
}
}
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index b3ecdb8cfb..4bba5bb467 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -36,10 +36,11 @@
#include "editor/editor_properties.h"
#include "scene/2d/tile_map.h"
#include "scene/gui/box_container.h"
+#include "scene/gui/panel_container.h"
+class Label;
class MenuButton;
class SpinBox;
-class Label;
class EditorUndoRedoManager;
class TileDataEditor : public VBoxContainer {
@@ -117,6 +118,7 @@ private:
HBoxContainer *toolbar = nullptr;
Ref<ButtonGroup> tools_button_group;
+ Button *button_expand = nullptr;
Button *button_create = nullptr;
Button *button_edit = nullptr;
Button *button_delete = nullptr;
@@ -165,6 +167,7 @@ private:
void _base_control_gui_input(Ref<InputEvent> p_event);
void _set_snap_option(int p_index);
void _store_snap_options();
+ void _toggle_expand(bool p_expand);
void _snap_to_tile_shape(Point2 &r_point, float &r_current_snapped_dist, float p_snap_dist);
void _snap_point(Point2 &r_point);
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index aac7fb3b84..9c5d55d78f 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -109,8 +109,8 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
}
}
-Vector<TileMapEditorPlugin::TabData> TileMapEditorTilesPlugin::get_tabs() const {
- Vector<TileMapEditorPlugin::TabData> tabs;
+Vector<TileMapSubEditorPlugin::TabData> TileMapEditorTilesPlugin::get_tabs() const {
+ Vector<TileMapSubEditorPlugin::TabData> tabs;
tabs.push_back({ toolbar, tiles_bottom_panel });
tabs.push_back({ toolbar, patterns_bottom_panel });
return tabs;
@@ -147,7 +147,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
old_source = -1;
}
- List<int> source_ids = TilesEditorPlugin::get_singleton()->get_sorted_sources(tile_set);
+ List<int> source_ids = TilesEditorUtils::get_singleton()->get_sorted_sources(tile_set);
for (const int &source_id : source_ids) {
TileSetSource *source = *tile_set->get_source(source_id);
@@ -209,7 +209,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
}
// Synchronize the lists.
- TilesEditorPlugin::get_singleton()->set_sources_lists_current(sources_list->get_current());
+ TilesEditorUtils::get_singleton()->set_sources_lists_current(sources_list->get_current());
}
void TileMapEditorTilesPlugin::_update_source_display() {
@@ -322,7 +322,7 @@ void TileMapEditorTilesPlugin::_update_patterns_list() {
int id = patterns_item_list->add_item("");
patterns_item_list->set_item_metadata(id, tile_set->get_pattern(i));
patterns_item_list->set_item_tooltip(id, vformat(TTR("Index: %d"), i));
- TilesEditorPlugin::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileMapEditorTilesPlugin::_pattern_preview_done));
+ TilesEditorUtils::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileMapEditorTilesPlugin::_pattern_preview_done));
}
// Update the label visibility.
@@ -354,7 +354,7 @@ void TileMapEditorTilesPlugin::_update_atlas_view() {
ERR_FAIL_COND(!atlas_source);
tile_atlas_view->set_atlas_source(*tile_map->get_tileset(), atlas_source, source_id);
- TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view);
+ TilesEditorUtils::get_singleton()->synchronize_atlas_view(tile_atlas_view);
tile_atlas_control->queue_redraw();
}
@@ -766,9 +766,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
for (int y = rect.position.y; y < rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
- Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_local(coords));
- tile_xform.set_scale(tile_shape_size);
+ Transform2D tile_xform(0, tile_shape_size, 0, tile_map->map_to_local(coords));
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false);
}
}
@@ -784,6 +782,8 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
to_draw.insert(coords);
}
+ Transform2D tile_xform(0, tile_shape_size, 0, tile_map->map_to_local(coords));
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.2), true);
}
}
tile_map->draw_cells_outline(p_overlay, to_draw, Color(1.0, 1.0, 1.0), xform);
@@ -1386,7 +1386,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
for (int i = 0; i < sources_list->get_item_count(); i++) {
if (int(sources_list->get_item_metadata(i)) == picked_source) {
sources_list->set_current(i);
- TilesEditorPlugin::get_singleton()->set_sources_lists_current(i);
+ TilesEditorUtils::get_singleton()->set_sources_lists_current(i);
break;
}
}
@@ -1720,7 +1720,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
if (frame > 0) {
color.a *= 0.3;
}
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(E.get_atlas_coords(), frame), color);
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(E.get_atlas_coords(), frame), color);
}
}
}
@@ -1729,7 +1729,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile == 0 && !tile_set_dragging_selection) {
for (int frame = 0; frame < atlas->get_tile_animation_frames_count(hovered_tile.get_atlas_coords()); frame++) {
Color color = Color(1.0, 0.8, 0.0, frame == 0 ? 0.6 : 0.3);
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(hovered_tile.get_atlas_coords(), frame), color);
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(hovered_tile.get_atlas_coords(), frame), color);
}
}
@@ -1751,7 +1751,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
}
}
for (const Vector2i &E : to_draw) {
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(E));
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(E));
}
}
}
@@ -1900,7 +1900,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_draw() {
if (E.source_id == source_id && E.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && E.alternative_tile > 0) {
Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E.get_atlas_coords(), E.alternative_tile);
if (rect != Rect2i()) {
- TilesEditorPlugin::draw_selection_rect(alternative_tiles_control, rect);
+ TilesEditorUtils::draw_selection_rect(alternative_tiles_control, rect);
}
}
}
@@ -1909,7 +1909,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_draw() {
if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile > 0) {
Rect2i rect = tile_atlas_view->get_alternative_tile_rect(hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile);
if (rect != Rect2i()) {
- TilesEditorPlugin::draw_selection_rect(alternative_tiles_control, rect, Color(1.0, 0.8, 0.0, 0.5));
+ TilesEditorUtils::draw_selection_rect(alternative_tiles_control, rect, Color(1.0, 0.8, 0.0, 0.5));
}
}
}
@@ -2031,10 +2031,10 @@ void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer
}
void TileMapEditorTilesPlugin::_set_source_sort(int p_sort) {
- for (int i = 0; i != TilesEditorPlugin::SOURCE_SORT_MAX; i++) {
+ for (int i = 0; i != TilesEditorUtils::SOURCE_SORT_MAX; i++) {
source_sort_button->get_popup()->set_item_checked(i, (i == (int)p_sort));
}
- TilesEditorPlugin::get_singleton()->set_sorting_option(p_sort);
+ TilesEditorUtils::get_singleton()->set_sorting_option(p_sort);
_update_tile_set_sources_list();
EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "tile_source_sort", p_sort);
}
@@ -2217,11 +2217,11 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
PopupMenu *p = source_sort_button->get_popup();
p->connect("id_pressed", callable_mp(this, &TileMapEditorTilesPlugin::_set_source_sort));
- p->add_radio_check_item(TTR("Sort by ID (Ascending)"), TilesEditorPlugin::SOURCE_SORT_ID);
- p->add_radio_check_item(TTR("Sort by ID (Descending)"), TilesEditorPlugin::SOURCE_SORT_ID_REVERSE);
- p->add_radio_check_item(TTR("Sort by Name (Ascending)"), TilesEditorPlugin::SOURCE_SORT_NAME);
- p->add_radio_check_item(TTR("Sort by Name (Descending)"), TilesEditorPlugin::SOURCE_SORT_NAME_REVERSE);
- p->set_item_checked(TilesEditorPlugin::SOURCE_SORT_ID, true);
+ p->add_radio_check_item(TTR("Sort by ID (Ascending)"), TilesEditorUtils::SOURCE_SORT_ID);
+ p->add_radio_check_item(TTR("Sort by ID (Descending)"), TilesEditorUtils::SOURCE_SORT_ID_REVERSE);
+ p->add_radio_check_item(TTR("Sort by Name (Ascending)"), TilesEditorUtils::SOURCE_SORT_NAME);
+ p->add_radio_check_item(TTR("Sort by Name (Descending)"), TilesEditorUtils::SOURCE_SORT_NAME_REVERSE);
+ p->set_item_checked(TilesEditorUtils::SOURCE_SORT_ID, true);
sources_bottom_actions->add_child(source_sort_button);
sources_list = memnew(ItemList);
@@ -2233,8 +2233,8 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_fix_selected_and_hovered).unbind(1));
sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_source_display).unbind(1));
- sources_list->connect("item_selected", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_sources_lists_current));
- sources_list->connect("visibility_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::synchronize_sources_list).bind(sources_list, source_sort_button));
+ sources_list->connect("item_selected", callable_mp(TilesEditorUtils::get_singleton(), &TilesEditorUtils::set_sources_lists_current));
+ sources_list->connect("visibility_changed", callable_mp(TilesEditorUtils::get_singleton(), &TilesEditorUtils::synchronize_sources_list).bind(sources_list, source_sort_button));
sources_list->add_user_signal(MethodInfo("sort_request"));
sources_list->connect("sort_request", callable_mp(this, &TileMapEditorTilesPlugin::_update_tile_set_sources_list));
split_container_left_side->add_child(sources_list);
@@ -2246,7 +2246,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
tile_atlas_view->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tile_atlas_view->set_texture_grid_visible(false);
tile_atlas_view->set_tile_shape_grid_visible(false);
- tile_atlas_view->connect("transform_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_atlas_view_transform));
+ tile_atlas_view->connect("transform_changed", callable_mp(TilesEditorUtils::get_singleton(), &TilesEditorUtils::set_atlas_view_transform));
atlas_sources_split_container->add_child(tile_atlas_view);
tile_atlas_control = memnew(Control);
@@ -2353,8 +2353,8 @@ void TileMapEditorTerrainsPlugin::_update_toolbar() {
}
}
-Vector<TileMapEditorPlugin::TabData> TileMapEditorTerrainsPlugin::get_tabs() const {
- Vector<TileMapEditorPlugin::TabData> tabs;
+Vector<TileMapSubEditorPlugin::TabData> TileMapEditorTerrainsPlugin::get_tabs() const {
+ Vector<TileMapSubEditorPlugin::TabData> tabs;
tabs.push_back({ toolbar, main_vbox_container });
return tabs;
}
@@ -3549,7 +3549,7 @@ void TileMapEditor::_update_bottom_panel() {
// Update the visibility of controls.
missing_tileset_label->set_visible(!tile_set.is_valid());
- for (TileMapEditorPlugin::TabData &tab_data : tabs_data) {
+ for (TileMapSubEditorPlugin::TabData &tab_data : tabs_data) {
tab_data.panel->hide();
}
if (tile_set.is_valid()) {
@@ -3639,14 +3639,14 @@ void TileMapEditor::_tab_changed(int p_tab_id) {
tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer);
// Update toolbar.
- for (TileMapEditorPlugin::TabData &tab_data : tabs_data) {
+ for (TileMapSubEditorPlugin::TabData &tab_data : tabs_data) {
tab_data.toolbar->hide();
}
tabs_data[p_tab_id].toolbar->show();
// Update visible panel.
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- for (TileMapEditorPlugin::TabData &tab_data : tabs_data) {
+ for (TileMapSubEditorPlugin::TabData &tab_data : tabs_data) {
tab_data.panel->hide();
}
if (tile_map && tile_map->get_tileset().is_valid()) {
@@ -4006,7 +4006,7 @@ TileMapEditor::TileMapEditor() {
tabs_bar = memnew(TabBar);
tabs_bar->set_clip_tabs(false);
for (int plugin_index = 0; plugin_index < tile_map_editor_plugins.size(); plugin_index++) {
- Vector<TileMapEditorPlugin::TabData> tabs_vector = tile_map_editor_plugins[plugin_index]->get_tabs();
+ Vector<TileMapSubEditorPlugin::TabData> tabs_vector = tile_map_editor_plugins[plugin_index]->get_tabs();
for (int tab_index = 0; tab_index < tabs_vector.size(); tab_index++) {
tabs_bar->add_tab(tabs_vector[tab_index].panel->get_name());
tabs_data.push_back(tabs_vector[tab_index]);
@@ -4024,7 +4024,7 @@ TileMapEditor::TileMapEditor() {
tile_map_toolbar->add_child(tabs_bar);
// Tabs toolbars.
- for (TileMapEditorPlugin::TabData &tab_data : tabs_data) {
+ for (TileMapSubEditorPlugin::TabData &tab_data : tabs_data) {
tab_data.toolbar->hide();
if (!tab_data.toolbar->get_parent()) {
tile_map_toolbar->add_child(tab_data.toolbar);
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index 1cab1d1500..eb8c3937a0 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -48,7 +48,7 @@
#include "scene/gui/tab_bar.h"
#include "scene/gui/tree.h"
-class TileMapEditorPlugin : public Object {
+class TileMapSubEditorPlugin : public Object {
public:
struct TabData {
Control *toolbar = nullptr;
@@ -65,8 +65,8 @@ public:
virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer){};
};
-class TileMapEditorTilesPlugin : public TileMapEditorPlugin {
- GDCLASS(TileMapEditorTilesPlugin, TileMapEditorPlugin);
+class TileMapEditorTilesPlugin : public TileMapSubEditorPlugin {
+ GDCLASS(TileMapEditorTilesPlugin, TileMapSubEditorPlugin);
private:
ObjectID tile_map_id;
@@ -219,8 +219,8 @@ public:
~TileMapEditorTilesPlugin();
};
-class TileMapEditorTerrainsPlugin : public TileMapEditorPlugin {
- GDCLASS(TileMapEditorTerrainsPlugin, TileMapEditorPlugin);
+class TileMapEditorTerrainsPlugin : public TileMapSubEditorPlugin {
+ GDCLASS(TileMapEditorTerrainsPlugin, TileMapSubEditorPlugin);
private:
ObjectID tile_map_id;
@@ -321,7 +321,7 @@ private:
int tile_map_layer = -1;
// Vector to keep plugins.
- Vector<TileMapEditorPlugin *> tile_map_editor_plugins;
+ Vector<TileMapSubEditorPlugin *> tile_map_editor_plugins;
// Toolbar.
HFlowContainer *tile_map_toolbar = nullptr;
@@ -339,8 +339,8 @@ private:
// Bottom panel.
Label *missing_tileset_label = nullptr;
TabBar *tabs_bar = nullptr;
- LocalVector<TileMapEditorPlugin::TabData> tabs_data;
- LocalVector<TileMapEditorPlugin *> tabs_plugins;
+ LocalVector<TileMapSubEditorPlugin::TabData> tabs_data;
+ LocalVector<TileMapSubEditorPlugin *> tabs_plugins;
void _update_bottom_panel();
// TileMap.
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index c71dcf1003..61d57e5eab 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -37,6 +37,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/tiles/tile_set_editor.h"
#include "editor/progress_dialog.h"
#include "scene/gui/box_container.h"
@@ -246,6 +247,12 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
}
emit_signal(SNAME("changed"), "animation_speed");
return true;
+ } else if (p_name == "animation_mode") {
+ for (TileSelection tile : tiles) {
+ tile_set_atlas_source->set_tile_animation_mode(tile.tile, VariantCaster<TileSetAtlasSource::TileAnimationMode>::cast(p_value));
+ }
+ emit_signal(SNAME("changed"), "animation_mode");
+ return true;
} else if (p_name == "animation_frames_count") {
for (TileSelection tile : tiles) {
int frame_count = p_value;
@@ -349,6 +356,9 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_na
} else if (p_name == "animation_speed") {
r_ret = tile_set_atlas_source->get_tile_animation_speed(coords);
return true;
+ } else if (p_name == "animation_mode") {
+ r_ret = tile_set_atlas_source->get_tile_animation_mode(coords);
+ return true;
} else if (p_name == "animation_frames_count") {
r_ret = tile_set_atlas_source->get_tile_animation_frames_count(coords);
return true;
@@ -417,6 +427,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
p_list->push_back(PropertyInfo(Variant::INT, PNAME("animation_columns")));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, PNAME("animation_separation")));
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("animation_speed")));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("animation_mode"), PROPERTY_HINT_ENUM, "Default,Random Start Times"));
p_list->push_back(PropertyInfo(Variant::INT, PNAME("animation_frames_count"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_"));
// Not optimal, but returns value for the first tile. This is similar to what MultiNodeEdit does.
if (tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile) == 1) {
@@ -720,6 +731,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
tile_data_editors["probability"] = tile_data_probability_editor;
}
+ Color disabled_color = get_theme_color("disabled_font_color", "Editor");
+
// --- Physics ---
ADD_TILE_DATA_EDITOR_GROUP(TTR("Physics"));
for (int i = 0; i < tile_set->get_physics_layers_count(); i++) {
@@ -738,6 +751,16 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
tile_data_editors.erase(vformat("physics_layer_%d", i));
}
+ if (tile_set->get_physics_layers_count() == 0) {
+ item = tile_data_editors_tree->create_item(group);
+ item->set_icon(0, get_theme_icon("Info", "EditorIcons"));
+ item->set_icon_modulate(0, disabled_color);
+ item->set_text(0, TTR("No physics layers"));
+ item->set_tooltip_text(0, TTR("Create and customize physics layers in the inspector of the TileSet resource."));
+ item->set_selectable(0, false);
+ item->set_custom_color(0, disabled_color);
+ }
+
// --- Navigation ---
ADD_TILE_DATA_EDITOR_GROUP(TTR("Navigation"));
for (int i = 0; i < tile_set->get_navigation_layers_count(); i++) {
@@ -756,6 +779,16 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
tile_data_editors.erase(vformat("navigation_layer_%d", i));
}
+ if (tile_set->get_navigation_layers_count() == 0) {
+ item = tile_data_editors_tree->create_item(group);
+ item->set_icon(0, get_theme_icon("Info", "EditorIcons"));
+ item->set_icon_modulate(0, disabled_color);
+ item->set_text(0, TTR("No navigation layers"));
+ item->set_tooltip_text(0, TTR("Create and customize navigation layers in the inspector of the TileSet resource."));
+ item->set_selectable(0, false);
+ item->set_custom_color(0, disabled_color);
+ }
+
// --- Custom Data ---
ADD_TILE_DATA_EDITOR_GROUP(TTR("Custom Data"));
for (int i = 0; i < tile_set->get_custom_data_layers_count(); i++) {
@@ -789,6 +822,16 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
tile_data_editors.erase(vformat("custom_data_%d", i));
}
+ if (tile_set->get_custom_data_layers_count() == 0) {
+ item = tile_data_editors_tree->create_item(group);
+ item->set_icon(0, get_theme_icon("Info", "EditorIcons"));
+ item->set_icon_modulate(0, disabled_color);
+ item->set_text(0, TTR("No custom data layers"));
+ item->set_tooltip_text(0, TTR("Create and customize custom data layers in the inspector of the TileSet resource."));
+ item->set_selectable(0, false);
+ item->set_custom_color(0, disabled_color);
+ }
+
#undef ADD_TILE_DATA_EDITOR_GROUP
#undef ADD_TILE_DATA_EDITOR
@@ -924,6 +967,8 @@ void TileSetAtlasSourceEditor::_update_atlas_view() {
if (tile_set.is_null()) {
return;
+ } else {
+ tile_create_help->set_visible(tools_button_group->get_pressed_button() == tool_setup_atlas_source_button);
}
Vector2i pos;
@@ -969,7 +1014,7 @@ void TileSetAtlasSourceEditor::_update_atlas_view() {
tile_atlas_view->queue_redraw();
// Synchronize atlas view.
- TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view);
+ TilesEditorUtils::get_singleton()->synchronize_atlas_view(tile_atlas_view);
}
void TileSetAtlasSourceEditor::_update_toolbar() {
@@ -1099,24 +1144,26 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
}
} else if (drag_type >= DRAG_TYPE_RESIZE_TOP_LEFT && drag_type <= DRAG_TYPE_RESIZE_LEFT) {
// Resizing a tile.
- new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(-1, -1)).min(grid_size);
-
Rect2i old_rect = Rect2i(drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
Rect2i new_rect = old_rect;
if (drag_type == DRAG_TYPE_RESIZE_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT) {
+ new_base_tiles_coords = _get_drag_offset_tile_coords(Vector2i(-1, 0));
new_rect.position.x = MIN(new_base_tiles_coords.x + 1, old_rect.get_end().x - 1);
new_rect.size.x = old_rect.get_end().x - new_rect.position.x;
}
if (drag_type == DRAG_TYPE_RESIZE_TOP || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT) {
+ new_base_tiles_coords = _get_drag_offset_tile_coords(Vector2i(0, -1));
new_rect.position.y = MIN(new_base_tiles_coords.y + 1, old_rect.get_end().y - 1);
new_rect.size.y = old_rect.get_end().y - new_rect.position.y;
}
if (drag_type == DRAG_TYPE_RESIZE_RIGHT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
+ new_base_tiles_coords = _get_drag_offset_tile_coords(Vector2i(1, 0));
new_rect.set_end(Vector2i(MAX(new_base_tiles_coords.x, old_rect.position.x + 1), new_rect.get_end().y));
}
if (drag_type == DRAG_TYPE_RESIZE_BOTTOM || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
+ new_base_tiles_coords = _get_drag_offset_tile_coords(Vector2i(0, 1));
new_rect.set_end(Vector2i(new_rect.get_end().x, MAX(new_base_tiles_coords.y, old_rect.position.y + 1)));
}
@@ -1523,66 +1570,6 @@ void TileSetAtlasSourceEditor::_end_dragging() {
// Change mouse accordingly.
}
-Control::CursorShape TileSetAtlasSourceEditor::get_cursor_shape(const Point2 &p_pos) const {
- Control::CursorShape cursor_shape = get_default_cursor_shape();
- if (drag_type == DRAG_TYPE_NONE) {
- if (selection.size() == 1) {
- // Change the cursor depending on the hovered thing.
- TileSelection selected = selection.front()->get();
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
- Transform2D xform = tile_atlas_control->get_global_transform().affine_inverse() * get_global_transform();
- Vector2 mouse_local_pos = xform.xform(p_pos);
- Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
- Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
- Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
- Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
- const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
- const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
- bool can_grow[4];
- for (int i = 0; i < 4; i++) {
- can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
- can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
- }
- for (int i = 0; i < 4; i++) {
- Vector2 pos = rect.position + rect.size * coords[i];
- if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
- cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
- }
- Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
- if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
- cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
- }
- }
- }
- }
- } else {
- switch (drag_type) {
- case DRAG_TYPE_RESIZE_TOP_LEFT:
- case DRAG_TYPE_RESIZE_BOTTOM_RIGHT:
- cursor_shape = CURSOR_FDIAGSIZE;
- break;
- case DRAG_TYPE_RESIZE_TOP:
- case DRAG_TYPE_RESIZE_BOTTOM:
- cursor_shape = CURSOR_VSIZE;
- break;
- case DRAG_TYPE_RESIZE_TOP_RIGHT:
- case DRAG_TYPE_RESIZE_BOTTOM_LEFT:
- cursor_shape = CURSOR_BDIAGSIZE;
- break;
- case DRAG_TYPE_RESIZE_LEFT:
- case DRAG_TYPE_RESIZE_RIGHT:
- cursor_shape = CURSOR_HSIZE;
- break;
- case DRAG_TYPE_MOVE_TILE:
- cursor_shape = CURSOR_MOVE;
- break;
- default:
- break;
- }
- }
- return cursor_shape;
-}
-
HashMap<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_properties_per_tiles(const List<PropertyInfo> &r_list, const TileSetAtlasSource *p_atlas) {
// Group properties per tile.
HashMap<Vector2i, List<const PropertyInfo *>> per_tile;
@@ -1693,7 +1680,7 @@ void TileSetAtlasSourceEditor::_menu_option(int p_option) {
}
}
-void TileSetAtlasSourceEditor::_unhandled_key_input(const Ref<InputEvent> &p_event) {
+void TileSetAtlasSourceEditor::shortcut_input(const Ref<InputEvent> &p_event) {
// Check for shortcuts.
if (ED_IS_SHORTCUT("tiles_editor/delete_tile", p_event)) {
if (tools_button_group->get_pressed_button() == tool_select_button && !selection.is_empty()) {
@@ -1737,7 +1724,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(selected.tile); frame++) {
Color color = Color(0.0, 1.0, 0.0, frame == 0 ? 1.0 : 0.3);
Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile, frame);
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, region, color);
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, region, color);
}
}
}
@@ -1779,7 +1766,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
// Draw the tiles to be removed.
for (const Vector2i &E : drag_modified_tiles) {
for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(E); frame++) {
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, tile_set_atlas_source->get_tile_texture_region(E, frame), Color(0.0, 0.0, 0.0));
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, tile_set_atlas_source->get_tile_texture_region(E, frame), Color(0.0, 0.0, 0.0));
}
}
} else if (drag_type == DRAG_TYPE_RECT_SELECT || drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT) {
@@ -1806,7 +1793,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
for (const Vector2i &E : to_paint) {
Vector2i coords = E;
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, tile_set_atlas_source->get_tile_texture_region(coords), color);
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, tile_set_atlas_source->get_tile_texture_region(coords), color);
}
} else if (drag_type == DRAG_TYPE_CREATE_TILES_USING_RECT) {
// Draw tiles to be created.
@@ -1823,7 +1810,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
Vector2i coords = Vector2i(x, y);
if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
Vector2i origin = margins + (coords * (tile_size + separation));
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, Rect2i(origin, tile_size));
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, Rect2i(origin, tile_size));
}
}
}
@@ -1840,7 +1827,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
Vector2i separation = tile_set_atlas_source->get_separation();
Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
Vector2i origin = margins + (area.position * (tile_size + separation));
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, Rect2i(origin, area.size * tile_size));
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, Rect2i(origin, area.size * tile_size));
} else {
Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
if (hovered_base_tile_coords.x >= 0 && hovered_base_tile_coords.y >= 0 && hovered_base_tile_coords.x < grid_size.x && hovered_base_tile_coords.y < grid_size.y) {
@@ -1849,7 +1836,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
// Draw existing hovered tile.
for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(hovered_tile); frame++) {
Color color = Color(1.0, 0.8, 0.0, frame == 0 ? 0.6 : 0.3);
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, tile_set_atlas_source->get_tile_texture_region(hovered_tile, frame), color);
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, tile_set_atlas_source->get_tile_texture_region(hovered_tile, frame), color);
}
} else {
// Draw empty tile, only in add/remove tiles mode.
@@ -1858,7 +1845,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
Vector2i separation = tile_set_atlas_source->get_separation();
Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
Vector2i origin = margins + (hovered_base_tile_coords * (tile_size + separation));
- TilesEditorPlugin::draw_selection_rect(tile_atlas_control, Rect2i(origin, tile_size));
+ TilesEditorUtils::draw_selection_rect(tile_atlas_control, Rect2i(origin, tile_size));
}
}
}
@@ -2017,7 +2004,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() {
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, hovered_alternative_tile_coords.z);
if (rect != Rect2i()) {
- TilesEditorPlugin::draw_selection_rect(alternative_tiles_control, rect, Color(1.0, 0.8, 0.0, 0.5));
+ TilesEditorUtils::draw_selection_rect(alternative_tiles_control, rect, Color(1.0, 0.8, 0.0, 0.5));
}
}
@@ -2027,7 +2014,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() {
if (selected.alternative >= 1) {
Rect2i rect = tile_atlas_view->get_alternative_tile_rect(selected.tile, selected.alternative);
if (rect != Rect2i()) {
- TilesEditorPlugin::draw_selection_rect(alternative_tiles_control, rect);
+ TilesEditorUtils::draw_selection_rect(alternative_tiles_control, rect);
}
}
}
@@ -2094,7 +2081,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
void TileSetAtlasSourceEditor::_tile_set_changed() {
if (tile_set->get_source_count() == 0) {
// No sources, so nothing to do here anymore.
- tile_set->disconnect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
+ tile_set->disconnect_changed(callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
tile_set = Ref<TileSet>();
return;
}
@@ -2156,7 +2143,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
Ref<TileSetAtlasSource> atlas_source = atlas_source_proxy->get_edited();
ERR_FAIL_COND(!atlas_source.is_valid());
- UndoRedo *internal_undo_redo = undo_redo_man->get_history_for_object(atlas_source.ptr()).undo_redo;
+ UndoRedo *internal_undo_redo = undo_redo_man->get_history_for_object(atlas_source_proxy).undo_redo;
internal_undo_redo->start_force_keep_in_merge_ends();
PackedVector2Array arr;
@@ -2180,7 +2167,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
String prefix = vformat("%d:%d/", coords.x, coords.y);
for (PropertyInfo pi : properties) {
if (pi.name.begins_with(prefix)) {
- ADD_UNDO(atlas_source.ptr(), pi.name);
+ ADD_UNDO(atlas_source_proxy, pi.name);
}
}
}
@@ -2191,6 +2178,12 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
#undef ADD_UNDO
}
+Vector2i TileSetAtlasSourceEditor::_get_drag_offset_tile_coords(const Vector2i &p_offset) const {
+ Vector2i half_tile_size = tile_set->get_tile_size() / 2;
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() + half_tile_size * p_offset);
+ return new_base_tiles_coords.max(Vector2i(-1, -1)).min(tile_set_atlas_source->get_atlas_grid_size());
+}
+
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);
@@ -2208,7 +2201,7 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource
// Remove listener for old objects.
if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
+ tile_set->disconnect_changed(callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
}
// Clear the selection.
@@ -2223,7 +2216,7 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource
read_only = new_read_only_state;
if (tile_set.is_valid()) {
- tile_set->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
+ tile_set->connect_changed(callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
}
if (read_only && tools_button_group->get_pressed_button() == tool_paint_button) {
@@ -2250,6 +2243,7 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource
}
void TileSetAtlasSourceEditor::init_source() {
+ tool_setup_atlas_source_button->set_pressed(true);
confirm_auto_create_tiles->popup_centered();
}
@@ -2418,15 +2412,16 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
}
void TileSetAtlasSourceEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &TileSetAtlasSourceEditor::_unhandled_key_input);
ClassDB::bind_method(D_METHOD("_set_selection_from_array"), &TileSetAtlasSourceEditor::_set_selection_from_array);
ADD_SIGNAL(MethodInfo("source_id_changed", PropertyInfo(Variant::INT, "source_id")));
}
TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
- set_process_unhandled_key_input(true);
+ set_shortcut_context(this);
+ set_process_shortcut_input(true);
set_process_internal(true);
+ TileSetEditor::get_singleton()->register_split(this);
// Middle panel.
VBoxContainer *middle_vbox_container = memnew(VBoxContainer);
@@ -2488,7 +2483,8 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_inspector_no_tile_selected_label = memnew(Label);
tile_inspector_no_tile_selected_label->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
tile_inspector_no_tile_selected_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- tile_inspector_no_tile_selected_label->set_text(TTR("No tiles selected."));
+ tile_inspector_no_tile_selected_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
+ tile_inspector_no_tile_selected_label->set_text(TTR("No tiles selected.\nSelect one or more tiles from the palette to edit its properties."));
middle_vbox_container->add_child(tile_inspector_no_tile_selected_label);
// Property values palette.
@@ -2584,10 +2580,22 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_view->set_h_size_flags(SIZE_EXPAND_FILL);
tile_atlas_view->set_v_size_flags(SIZE_EXPAND_FILL);
tile_atlas_view->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
- tile_atlas_view->connect("transform_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_atlas_view_transform));
+ tile_atlas_view->connect("transform_changed", callable_mp(TilesEditorUtils::get_singleton(), &TilesEditorUtils::set_atlas_view_transform));
tile_atlas_view->connect("transform_changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed).unbind(2));
right_panel->add_child(tile_atlas_view);
+ tile_create_help = memnew(HBoxContainer);
+ tile_atlas_view->add_child(tile_create_help);
+ tile_create_help->set_mouse_filter(MOUSE_FILTER_IGNORE);
+ tile_create_help->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_LEFT, Control::PRESET_MODE_MINSIZE, 30 * EDSCALE);
+ tile_create_help->add_theme_constant_override("separation", 30 * EDSCALE);
+
+ Label *help_label = memnew(Label(TTR("Hold Ctrl to create multiple tiles.")));
+ tile_create_help->add_child(help_label);
+
+ help_label = memnew(Label(TTR("Hold Shift to create big tiles.")));
+ tile_create_help->add_child(help_label);
+
base_tile_popup_menu = memnew(PopupMenu);
base_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE);
base_tile_popup_menu->add_item(TTR("Create an Alternative Tile"), TILE_CREATE_ALTERNATIVE);
@@ -2599,7 +2607,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
empty_base_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
tile_atlas_view->add_child(empty_base_tile_popup_menu);
- tile_atlas_control = memnew(Control);
+ tile_atlas_control = memnew(TileAtlasControl(this));
tile_atlas_control->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_draw));
tile_atlas_control->connect("mouse_exited", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_mouse_exited));
tile_atlas_control->connect("gui_input", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_gui_input));
@@ -2827,3 +2835,63 @@ bool EditorInspectorPluginTileData::parse_property(Object *p_object, const Varia
}
return false;
}
+
+Control::CursorShape TileSetAtlasSourceEditor::TileAtlasControl::get_cursor_shape(const Point2 &p_pos) const {
+ Control::CursorShape cursor_shape = get_default_cursor_shape();
+ if (editor->drag_type == DRAG_TYPE_NONE) {
+ if (editor->selection.size() == 1) {
+ // Change the cursor depending on the hovered thing.
+ TileSelection selected = editor->selection.front()->get();
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
+ Transform2D xform = editor->tile_atlas_control->get_global_transform().affine_inverse() * get_global_transform();
+ Vector2 mouse_local_pos = xform.xform(p_pos);
+ Vector2i size_in_atlas = editor->tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
+ Rect2 region = editor->tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ Size2 zoomed_size = editor->resize_handle->get_size() / editor->tile_atlas_view->get_zoom();
+ Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
+ const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ bool can_grow[4];
+ for (int i = 0; i < 4; i++) {
+ can_grow[i] = editor->tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], editor->tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), editor->tile_set_atlas_source->get_tile_animation_columns(selected.tile), editor->tile_set_atlas_source->get_tile_animation_separation(selected.tile), editor->tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
+ can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
+ }
+ for (int i = 0; i < 4; i++) {
+ Vector2 pos = rect.position + rect.size * coords[i];
+ if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
+ }
+ Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
+ if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
+ }
+ }
+ }
+ }
+ } else {
+ switch (editor->drag_type) {
+ case DRAG_TYPE_RESIZE_TOP_LEFT:
+ case DRAG_TYPE_RESIZE_BOTTOM_RIGHT:
+ cursor_shape = CURSOR_FDIAGSIZE;
+ break;
+ case DRAG_TYPE_RESIZE_TOP:
+ case DRAG_TYPE_RESIZE_BOTTOM:
+ cursor_shape = CURSOR_VSIZE;
+ break;
+ case DRAG_TYPE_RESIZE_TOP_RIGHT:
+ case DRAG_TYPE_RESIZE_BOTTOM_LEFT:
+ cursor_shape = CURSOR_BDIAGSIZE;
+ break;
+ case DRAG_TYPE_RESIZE_LEFT:
+ case DRAG_TYPE_RESIZE_RIGHT:
+ cursor_shape = CURSOR_HSIZE;
+ break;
+ case DRAG_TYPE_MOVE_TILE:
+ cursor_shape = CURSOR_MOVE;
+ break;
+ default:
+ break;
+ }
+ }
+ return cursor_shape;
+}
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index f8dbbc4b3f..ff928ab2eb 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -112,6 +112,15 @@ public:
}
};
+ class TileAtlasControl : public Control {
+ TileSetAtlasSourceEditor *editor = nullptr;
+
+ public:
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
+ TileAtlasControl(TileSetAtlasSourceEditor *p_editor) { editor = p_editor; }
+ };
+ friend class TileAtlasControl;
+
private:
bool read_only = false;
@@ -150,6 +159,7 @@ private:
// -- Atlas view --
TileAtlasView *tile_atlas_view = nullptr;
+ HBoxContainer *tile_create_help = nullptr;
// Dragging
enum DragType {
@@ -257,13 +267,11 @@ private:
void _update_atlas_view();
void _update_toolbar();
- // -- input events --
- void _unhandled_key_input(const Ref<InputEvent> &p_event);
-
// -- Misc --
void _auto_create_tiles();
void _auto_remove_tiles();
AcceptDialog *confirm_auto_create_tiles = nullptr;
+ Vector2i _get_drag_offset_tile_coords(const Vector2i &p_offset) const;
void _tile_set_changed();
void _tile_proxy_object_changed(String p_what);
@@ -275,12 +283,13 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ // -- input events --
+ virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
+
public:
void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_source, int p_source_id);
void init_source();
- virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
-
TileSetAtlasSourceEditor();
~TileSetAtlasSourceEditor();
};
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 23076266ee..eb79394cc9 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/gui/editor_file_dialog.h"
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
@@ -148,7 +149,7 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
sources_list->clear();
// Update the atlas sources.
- List<int> source_ids = TilesEditorPlugin::get_singleton()->get_sorted_sources(tile_set);
+ List<int> source_ids = TilesEditorUtils::get_singleton()->get_sorted_sources(tile_set);
for (const int &source_id : source_ids) {
TileSetSource *source = *tile_set->get_source(source_id);
@@ -220,7 +221,31 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
_source_selected(sources_list->get_current());
// Synchronize the lists.
- TilesEditorPlugin::get_singleton()->set_sources_lists_current(sources_list->get_current());
+ TilesEditorUtils::get_singleton()->set_sources_lists_current(sources_list->get_current());
+}
+
+void TileSetEditor::_texture_file_selected(const String &p_path) {
+ Ref<Texture2D> texture = ResourceLoader::load(p_path);
+ if (texture.is_null()) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid texture selected."));
+ return;
+ }
+
+ int source_id = tile_set->get_next_source_id();
+
+ Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
+ atlas_source->set_texture(texture);
+
+ // Add a new source.
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Add atlas source"));
+ undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
+ undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
+ undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
+ undo_redo->commit_action();
+
+ _update_sources_list(source_id);
+ tile_set_atlas_source_editor->init_source();
}
void TileSetEditor::_source_selected(int p_source_index) {
@@ -278,19 +303,19 @@ void TileSetEditor::_source_add_id_pressed(int p_id_pressed) {
switch (p_id_pressed) {
case 0: {
- int source_id = tile_set->get_next_source_id();
-
- Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
-
- // Add a new source.
- EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Add atlas source"));
- undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
- undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
- undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
- undo_redo->commit_action();
-
- _update_sources_list(source_id);
+ if (!texture_file_dialog) {
+ texture_file_dialog = memnew(EditorFileDialog);
+ add_child(texture_file_dialog);
+ texture_file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+ texture_file_dialog->connect("file_selected", callable_mp(this, &TileSetEditor::_texture_file_selected));
+
+ List<String> extensions;
+ ResourceLoader::get_recognized_extensions_for_type("Texture2D", &extensions);
+ for (const String &E : extensions) {
+ texture_file_dialog->add_filter("*." + E, E.to_upper());
+ }
+ }
+ texture_file_dialog->popup_file_dialog();
} break;
case 1: {
int source_id = tile_set->get_next_source_id();
@@ -327,8 +352,8 @@ void TileSetEditor::_sources_advanced_menu_id_pressed(int p_id_pressed) {
}
void TileSetEditor::_set_source_sort(int p_sort) {
- TilesEditorPlugin::get_singleton()->set_sorting_option(p_sort);
- for (int i = 0; i != TilesEditorPlugin::SOURCE_SORT_MAX; i++) {
+ TilesEditorUtils::get_singleton()->set_sorting_option(p_sort);
+ for (int i = 0; i != TilesEditorUtils::SOURCE_SORT_MAX; i++) {
source_sort_button->get_popup()->set_item_checked(i, (i == (int)p_sort));
}
@@ -345,13 +370,13 @@ void TileSetEditor::_set_source_sort(int p_sort) {
void TileSetEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
sources_delete_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
sources_add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
source_sort_button->set_icon(get_theme_icon(SNAME("Sort"), SNAME("EditorIcons")));
sources_advanced_menu_button->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
missing_texture_texture = get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons"));
+ expanded_area->add_theme_style_override("panel", get_theme_stylebox("panel", "Tree"));
_update_sources_list();
} break;
@@ -376,6 +401,12 @@ void TileSetEditor::_notification(int p_what) {
tile_set_changed_needs_update = false;
}
} break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible_in_tree()) {
+ remove_expanded_editor();
+ }
+ } break;
}
}
@@ -419,7 +450,7 @@ void TileSetEditor::_update_patterns_list() {
int id = patterns_item_list->add_item("");
patterns_item_list->set_item_metadata(id, tile_set->get_pattern(i));
patterns_item_list->set_item_tooltip(id, vformat(TTR("Index: %d"), i));
- TilesEditorPlugin::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileSetEditor::_pattern_preview_done));
+ TilesEditorUtils::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileSetEditor::_pattern_preview_done));
}
// Update the label visibility.
@@ -698,7 +729,7 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
// Remove listener.
if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
+ tile_set->disconnect_changed(callable_mp(this, &TileSetEditor::_tile_set_changed));
}
// Change the edited object.
@@ -713,7 +744,7 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
sources_advanced_menu_button->set_disabled(read_only);
source_sort_button->set_disabled(read_only);
- tile_set->connect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
+ tile_set->connect_changed(callable_mp(this, &TileSetEditor::_tile_set_changed));
if (first_edit) {
first_edit = false;
_set_source_sort(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "tile_source_sort", 0));
@@ -724,11 +755,70 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
}
}
+void TileSetEditor::add_expanded_editor(Control *p_editor) {
+ expanded_editor = p_editor;
+ expanded_editor_parent = p_editor->get_parent()->get_instance_id();
+
+ // Find the scrollable control this node belongs to.
+ Node *check_parent = expanded_editor->get_parent();
+ Control *parent_container = nullptr;
+ while (check_parent) {
+ parent_container = Object::cast_to<EditorInspector>(check_parent);
+ if (parent_container) {
+ break;
+ }
+ parent_container = Object::cast_to<ScrollContainer>(check_parent);
+ if (parent_container) {
+ break;
+ }
+ check_parent = check_parent->get_parent();
+ }
+ ERR_FAIL_NULL(parent_container);
+
+ expanded_editor->set_meta("reparented", true);
+ expanded_editor->reparent(expanded_area);
+ expanded_area->show();
+ expanded_area->set_size(Vector2(parent_container->get_global_rect().get_end().x - expanded_area->get_global_position().x, expanded_area->get_size().y));
+
+ for (SplitContainer *split : disable_on_expand) {
+ split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
+ }
+}
+
+void TileSetEditor::remove_expanded_editor() {
+ if (!expanded_editor) {
+ return;
+ }
+
+ Node *original_parent = Object::cast_to<Node>(ObjectDB::get_instance(expanded_editor_parent));
+ if (original_parent) {
+ expanded_editor->remove_meta("reparented");
+ expanded_editor->reparent(original_parent);
+ } else {
+ expanded_editor->queue_free();
+ }
+ expanded_editor = nullptr;
+ expanded_editor_parent = ObjectID();
+ expanded_area->hide();
+
+ for (SplitContainer *split : disable_on_expand) {
+ split->set_dragger_visibility(SplitContainer::DRAGGER_VISIBLE);
+ }
+}
+
+void TileSetEditor::register_split(SplitContainer *p_split) {
+ disable_on_expand.push_back(p_split);
+}
+
TileSetEditor::TileSetEditor() {
singleton = this;
set_process_internal(true);
+ VBoxContainer *main_vb = memnew(VBoxContainer);
+ add_child(main_vb);
+ main_vb->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
+
// TabBar.
tabs_bar = memnew(TabBar);
tabs_bar->set_tab_alignment(TabBar::ALIGNMENT_CENTER);
@@ -740,7 +830,7 @@ TileSetEditor::TileSetEditor() {
tile_set_toolbar = memnew(HBoxContainer);
tile_set_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
tile_set_toolbar->add_child(tabs_bar);
- add_child(tile_set_toolbar);
+ main_vb->add_child(tile_set_toolbar);
//// Tiles ////
// Split container.
@@ -748,7 +838,7 @@ TileSetEditor::TileSetEditor() {
split_container->set_name(TTR("Tiles"));
split_container->set_h_size_flags(SIZE_EXPAND_FILL);
split_container->set_v_size_flags(SIZE_EXPAND_FILL);
- add_child(split_container);
+ main_vb->add_child(split_container);
// Sources list.
VBoxContainer *split_container_left_side = memnew(VBoxContainer);
@@ -764,19 +854,19 @@ TileSetEditor::TileSetEditor() {
PopupMenu *p = source_sort_button->get_popup();
p->connect("id_pressed", callable_mp(this, &TileSetEditor::_set_source_sort));
- p->add_radio_check_item(TTR("Sort by ID (Ascending)"), TilesEditorPlugin::SOURCE_SORT_ID);
- p->add_radio_check_item(TTR("Sort by ID (Descending)"), TilesEditorPlugin::SOURCE_SORT_ID_REVERSE);
- p->add_radio_check_item(TTR("Sort by Name (Ascending)"), TilesEditorPlugin::SOURCE_SORT_NAME);
- p->add_radio_check_item(TTR("Sort by Name (Descending)"), TilesEditorPlugin::SOURCE_SORT_NAME_REVERSE);
- p->set_item_checked(TilesEditorPlugin::SOURCE_SORT_ID, true);
+ p->add_radio_check_item(TTR("Sort by ID (Ascending)"), TilesEditorUtils::SOURCE_SORT_ID);
+ p->add_radio_check_item(TTR("Sort by ID (Descending)"), TilesEditorUtils::SOURCE_SORT_ID_REVERSE);
+ p->add_radio_check_item(TTR("Sort by Name (Ascending)"), TilesEditorUtils::SOURCE_SORT_NAME);
+ p->add_radio_check_item(TTR("Sort by Name (Descending)"), TilesEditorUtils::SOURCE_SORT_NAME_REVERSE);
+ p->set_item_checked(TilesEditorUtils::SOURCE_SORT_ID, true);
sources_list = memnew(ItemList);
sources_list->set_fixed_icon_size(Size2(60, 60) * EDSCALE);
sources_list->set_h_size_flags(SIZE_EXPAND_FILL);
sources_list->set_v_size_flags(SIZE_EXPAND_FILL);
sources_list->connect("item_selected", callable_mp(this, &TileSetEditor::_source_selected));
- sources_list->connect("item_selected", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_sources_lists_current));
- sources_list->connect("visibility_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::synchronize_sources_list).bind(sources_list, source_sort_button));
+ sources_list->connect("item_selected", callable_mp(TilesEditorUtils::get_singleton(), &TilesEditorUtils::set_sources_lists_current));
+ sources_list->connect("visibility_changed", callable_mp(TilesEditorUtils::get_singleton(), &TilesEditorUtils::synchronize_sources_list).bind(sources_list, source_sort_button));
sources_list->add_user_signal(MethodInfo("sort_request"));
sources_list->connect("sort_request", callable_mp(this, &TileSetEditor::_update_sources_list).bind(-1));
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
@@ -855,7 +945,7 @@ TileSetEditor::TileSetEditor() {
patterns_item_list->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
patterns_item_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
patterns_item_list->connect("gui_input", callable_mp(this, &TileSetEditor::_patterns_item_list_gui_input));
- add_child(patterns_item_list);
+ main_vb->add_child(patterns_item_list);
patterns_item_list->hide();
patterns_help_label = memnew(Label);
@@ -864,6 +954,12 @@ TileSetEditor::TileSetEditor() {
patterns_help_label->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
patterns_item_list->add_child(patterns_help_label);
+ // Expanded editor
+ expanded_area = memnew(PanelContainer);
+ add_child(expanded_area);
+ expanded_area->set_anchors_and_offsets_preset(PRESET_LEFT_WIDE);
+ expanded_area->hide();
+
// Registers UndoRedo inspector callback.
EditorNode::get_singleton()->get_editor_data().add_move_array_element_function(SNAME("TileSet"), callable_mp(this, &TileSetEditor::_move_tile_set_array_element));
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetEditor::_undo_redo_inspector_callback));
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index d36d3bde41..40ca1f7ed7 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -32,15 +32,18 @@
#define TILE_SET_EDITOR_H
#include "atlas_merging_dialog.h"
-#include "scene/gui/box_container.h"
#include "scene/gui/tab_bar.h"
#include "scene/resources/tile_set.h"
#include "tile_proxies_manager_dialog.h"
#include "tile_set_atlas_source_editor.h"
#include "tile_set_scenes_collection_source_editor.h"
-class TileSetEditor : public VBoxContainer {
- GDCLASS(TileSetEditor, VBoxContainer);
+class EditorFileDialog;
+class HBoxContainer;
+class SplitContainer;
+
+class TileSetEditor : public Control {
+ GDCLASS(TileSetEditor, Control);
static TileSetEditor *singleton;
@@ -72,12 +75,14 @@ private:
MenuButton *sources_advanced_menu_button = nullptr;
ItemList *sources_list = nullptr;
Ref<Texture2D> missing_texture_texture;
+ void _texture_file_selected(const String &p_path);
void _source_selected(int p_source_index);
void _source_delete_pressed();
void _source_add_id_pressed(int p_id_pressed);
void _sources_advanced_menu_id_pressed(int p_id_pressed);
void _set_source_sort(int p_sort);
+ EditorFileDialog *texture_file_dialog = nullptr;
AtlasMergingDialog *atlas_merging_dialog = nullptr;
TileProxiesManagerDialog *tile_proxies_manager_dialog = nullptr;
@@ -91,6 +96,12 @@ private:
bool select_last_pattern = false;
void _update_patterns_list();
+ // Expanded editor.
+ PanelContainer *expanded_area = nullptr;
+ Control *expanded_editor = nullptr;
+ ObjectID expanded_editor_parent;
+ LocalVector<SplitContainer *> disable_on_expand;
+
void _tile_set_changed();
void _tab_changed(int p_tab_changed);
@@ -105,6 +116,10 @@ public:
void edit(Ref<TileSet> p_tile_set);
+ void add_expanded_editor(Control *p_editor);
+ void remove_expanded_editor();
+ void register_split(SplitContainer *p_split);
+
TileSetEditor();
};
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 6908dd7c3b..5ffa7b4bd4 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -384,7 +384,7 @@ void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetS
// Remove listener for old objects.
if (tile_set_scenes_collection_source) {
- tile_set_scenes_collection_source->disconnect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed));
+ tile_set_scenes_collection_source->disconnect_changed(callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed));
}
// Change the edited object.
@@ -404,7 +404,7 @@ void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetS
// Add the listener again.
if (tile_set_scenes_collection_source) {
- tile_set_scenes_collection_source->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed));
+ tile_set_scenes_collection_source->connect_changed(callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed));
}
// Update everything.
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index b2ee3103ce..4238002b72 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/inspector_dock.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/tile_map.h"
@@ -45,25 +46,27 @@
#include "scene/gui/button.h"
#include "scene/gui/control.h"
#include "scene/gui/separator.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/tile_set.h"
-TilesEditorPlugin *TilesEditorPlugin::singleton = nullptr;
+TilesEditorUtils *TilesEditorUtils::singleton = nullptr;
+TileMapEditorPlugin *local_singleton = nullptr;
-void TilesEditorPlugin::_preview_frame_started() {
- RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_pattern_preview_done));
+void TilesEditorUtils::_preview_frame_started() {
+ RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<TilesEditorUtils *>(this), &TilesEditorUtils::_pattern_preview_done));
}
-void TilesEditorPlugin::_pattern_preview_done() {
+void TilesEditorUtils::_pattern_preview_done() {
pattern_preview_done.post();
}
-void TilesEditorPlugin::_thread_func(void *ud) {
- TilesEditorPlugin *te = static_cast<TilesEditorPlugin *>(ud);
+void TilesEditorUtils::_thread_func(void *ud) {
+ TilesEditorUtils *te = static_cast<TilesEditorUtils *>(ud);
set_current_thread_safe_for_nodes(true);
te->_thread();
}
-void TilesEditorPlugin::_thread() {
+void TilesEditorUtils::_thread() {
pattern_thread_exited.clear();
while (!pattern_thread_exit.is_set()) {
pattern_preview_sem.wait();
@@ -123,7 +126,7 @@ void TilesEditorPlugin::_thread() {
// Add the viewport at the last moment to avoid rendering too early.
EditorNode::get_singleton()->call_deferred("add_child", viewport);
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_preview_frame_started), Object::CONNECT_ONE_SHOT);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorUtils *>(this), &TilesEditorUtils::_preview_frame_started), Object::CONNECT_ONE_SHOT);
pattern_preview_done.wait();
@@ -143,85 +146,7 @@ void TilesEditorPlugin::_thread() {
pattern_thread_exited.set();
}
-void TilesEditorPlugin::_tile_map_changed() {
- tile_map_changed_needs_update = true;
-}
-
-void TilesEditorPlugin::_update_editors() {
- // If tile_map is not edited, we change the edited only if we are not editing a tile_set.
- if (tile_set.is_valid()) {
- tileset_editor->edit(tile_set);
- }
-
- TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- if (tile_map) {
- tilemap_editor->edit(tile_map);
- } else {
- tilemap_editor->edit(nullptr);
- }
-
- // Update the viewport.
- CanvasItemEditor::get_singleton()->update_viewport();
-
- // Make sure the tile set editor is visible if we have one assigned.
- tileset_editor_button->set_visible(is_visible && tile_set.is_valid());
- tilemap_editor_button->set_visible(is_visible && tile_map);
-
- // Update visibility of bottom panel buttons.
- if (tileset_editor_button->is_pressed() && !tile_set.is_valid()) {
- if (tile_map) {
- EditorNode::get_singleton()->make_bottom_panel_item_visible(tilemap_editor);
- } else {
- EditorNode::get_singleton()->hide_bottom_panel();
- }
- }
-}
-
-void TilesEditorPlugin::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_INTERNAL_PROCESS: {
- if (tile_map_changed_needs_update) {
- TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- if (tile_map) {
- tile_set = tile_map->get_tileset();
- }
- _update_editors();
- tile_map_changed_needs_update = false;
- }
- } break;
- }
-}
-
-void TilesEditorPlugin::make_visible(bool p_visible) {
- if (p_visible || is_tile_map_selected()) {
- // Disable and hide invalid editors.
- TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- tileset_editor_button->set_visible(tile_set.is_valid());
- tilemap_editor_button->set_visible(tile_map);
- if (tile_map && (!is_editing_tile_set || !p_visible)) {
- EditorNode::get_singleton()->make_bottom_panel_item_visible(tilemap_editor);
- } else {
- EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor);
- }
- is_visible = true;
- } else {
- tileset_editor_button->hide();
- tilemap_editor_button->hide();
- EditorNode::get_singleton()->hide_bottom_panel();
- is_visible = false;
- }
-}
-
-bool TilesEditorPlugin::is_tile_map_selected() {
- TypedArray<Node> selection = EditorInterface::get_singleton()->get_selection()->get_selected_nodes();
- if (selection.size() == 1 && Object::cast_to<TileMap>(selection[0])) {
- return true;
- }
-
- return false;
-}
-
-void TilesEditorPlugin::queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback) {
+void TilesEditorUtils::queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback) {
ERR_FAIL_COND(!p_tile_set.is_valid());
ERR_FAIL_COND(!p_pattern.is_valid());
{
@@ -231,11 +156,11 @@ void TilesEditorPlugin::queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileM
pattern_preview_sem.post();
}
-void TilesEditorPlugin::set_sources_lists_current(int p_current) {
+void TilesEditorUtils::set_sources_lists_current(int p_current) {
atlas_sources_lists_current = p_current;
}
-void TilesEditorPlugin::synchronize_sources_list(Object *p_current_list, Object *p_current_sort_button) {
+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);
@@ -263,12 +188,12 @@ void TilesEditorPlugin::synchronize_sources_list(Object *p_current_list, Object
}
}
-void TilesEditorPlugin::set_atlas_view_transform(float p_zoom, Vector2 p_scroll) {
+void TilesEditorUtils::set_atlas_view_transform(float p_zoom, Vector2 p_scroll) {
atlas_view_zoom = p_zoom;
atlas_view_scroll = p_scroll;
}
-void TilesEditorPlugin::synchronize_atlas_view(Object *p_current) {
+void TilesEditorUtils::synchronize_atlas_view(Object *p_current) {
TileAtlasView *tile_atlas_view = Object::cast_to<TileAtlasView>(p_current);
ERR_FAIL_COND(!tile_atlas_view);
@@ -277,11 +202,11 @@ void TilesEditorPlugin::synchronize_atlas_view(Object *p_current) {
}
}
-void TilesEditorPlugin::set_sorting_option(int p_option) {
+void TilesEditorUtils::set_sorting_option(int p_option) {
source_sort = p_option;
}
-List<int> TilesEditorPlugin::get_sorted_sources(const Ref<TileSet> p_tile_set) const {
+List<int> TilesEditorUtils::get_sorted_sources(const Ref<TileSet> p_tile_set) const {
SourceNameComparator::tile_set = p_tile_set;
List<int> source_ids;
@@ -309,9 +234,9 @@ List<int> TilesEditorPlugin::get_sorted_sources(const Ref<TileSet> p_tile_set) c
return source_ids;
}
-Ref<TileSet> TilesEditorPlugin::SourceNameComparator::tile_set;
+Ref<TileSet> TilesEditorUtils::SourceNameComparator::tile_set;
-bool TilesEditorPlugin::SourceNameComparator::operator()(const int &p_a, const int &p_b) const {
+bool TilesEditorUtils::SourceNameComparator::operator()(const int &p_a, const int &p_b) const {
String name_a;
String name_b;
@@ -358,104 +283,149 @@ bool TilesEditorPlugin::SourceNameComparator::operator()(const int &p_a, const i
return NaturalNoCaseComparator()(name_a, name_b);
}
-void TilesEditorPlugin::edit(Object *p_object) {
- // Disconnect to changes.
- TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- if (tile_map) {
- tile_map->disconnect("changed", callable_mp(this, &TilesEditorPlugin::_tile_map_changed));
- }
+void TilesEditorUtils::draw_selection_rect(CanvasItem *p_ci, const Rect2 &p_rect, const Color &p_color) {
+ 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_theme_icon(SNAME("TileSelection"), SNAME("EditorIcons"))->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());
+}
- // Update edited objects.
- tile_set = Ref<TileSet>();
- is_editing_tile_set = false;
-
- if (p_object) {
- if (p_object->is_class("TileMap")) {
- tile_map_id = p_object->get_instance_id();
- tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- tile_set = tile_map->get_tileset();
- EditorNode::get_singleton()->make_bottom_panel_item_visible(tilemap_editor);
- } else if (p_object->is_class("TileSet")) {
- tile_set = Ref<TileSet>(p_object);
- if (tile_map) {
- if (tile_map->get_tileset() != tile_set || !tile_map->is_inside_tree() || !is_tile_map_selected()) {
- tile_map = nullptr;
- tile_map_id = ObjectID();
- }
- }
- is_editing_tile_set = true;
+TilesEditorUtils::TilesEditorUtils() {
+ singleton = this;
+ // Pattern preview generation thread.
+ pattern_preview_thread.start(_thread_func, this);
+}
+
+TilesEditorUtils::~TilesEditorUtils() {
+ if (pattern_preview_thread.is_started()) {
+ pattern_thread_exit.set();
+ pattern_preview_sem.post();
+ while (!pattern_thread_exited.is_set()) {
+ OS::get_singleton()->delay_usec(10000);
+ RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
}
+ pattern_preview_thread.wait_to_finish();
}
+ singleton = nullptr;
+}
- // Update the editors.
- _update_editors();
+void TileMapEditorPlugin::_tile_map_changed() {
+ if (tile_map_changed_needs_update) {
+ return;
+ }
+ tile_map_changed_needs_update = true;
+ callable_mp(this, &TileMapEditorPlugin::_update_tile_map).call_deferred();
+}
+
+void TileMapEditorPlugin::_update_tile_map() {
+ if (tile_map && tile_map->get_tileset().is_valid()) {
+ EditorNode::get_singleton()->edit_item(tile_map->get_tileset().ptr(), InspectorDock::get_inspector_singleton());
+ }
+ tile_map_changed_needs_update = false;
+}
+
+void TileMapEditorPlugin::_notification(int p_notification) {
+ if (p_notification == NOTIFICATION_EXIT_TREE) {
+ get_tree()->queue_delete(TilesEditorUtils::get_singleton());
+ }
+}
- // If the tileset is being edited, the visibility function must be called
- // here after _update_editors has been called.
- if (is_editing_tile_set) {
- EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor);
+void TileMapEditorPlugin::edit(Object *p_object) {
+ if (tile_map) {
+ tile_map->disconnect("changed", callable_mp(this, &TileMapEditorPlugin::_tile_map_changed));
}
- // Add change listener.
+ tile_map = Object::cast_to<TileMap>(p_object);
+
+ editor->edit(tile_map);
if (tile_map) {
- tile_map->connect("changed", callable_mp(this, &TilesEditorPlugin::_tile_map_changed));
+ tile_map->connect("changed", callable_mp(this, &TileMapEditorPlugin::_tile_map_changed));
+
+ if (tile_map->get_tileset().is_valid()) {
+ EditorNode::get_singleton()->edit_item(tile_map->get_tileset().ptr(), InspectorDock::get_inspector_singleton());
+ }
}
}
-bool TilesEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("TileMap") || p_object->is_class("TileSet");
+bool TileMapEditorPlugin::handles(Object *p_object) const {
+ return Object::cast_to<TileMap>(p_object) != nullptr;
}
-void TilesEditorPlugin::draw_selection_rect(CanvasItem *p_ci, const Rect2 &p_rect, const Color &p_color) {
- 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_theme_icon(SNAME("TileSelection"), SNAME("EditorIcons"))->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());
+void TileMapEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ button->show();
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(editor);
+ } else {
+ button->hide();
+ if (editor->is_visible_in_tree()) {
+ EditorNode::get_singleton()->hide_bottom_panel();
+ }
+ }
}
-TilesEditorPlugin::TilesEditorPlugin() {
- set_process_internal(true);
+bool TileMapEditorPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+ return editor->forward_canvas_gui_input(p_event);
+}
- // Update the singleton.
- singleton = this;
+void TileMapEditorPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) {
+ editor->forward_canvas_draw_over_viewport(p_overlay);
+}
- // Tileset editor.
- tileset_editor = memnew(TileSetEditor);
- tileset_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- tileset_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- tileset_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
- tileset_editor->hide();
+bool TileMapEditorPlugin::is_editor_visible() const {
+ return editor->is_visible_in_tree();
+}
- // Tilemap editor.
- tilemap_editor = memnew(TileMapEditor);
- tilemap_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- tilemap_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- tilemap_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
- tilemap_editor->hide();
+TileMapEditorPlugin::TileMapEditorPlugin() {
+ memnew(TilesEditorUtils);
+ local_singleton = this;
- // Pattern preview generation thread.
- pattern_preview_thread.start(_thread_func, this);
+ editor = memnew(TileMapEditor);
+ editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
+ editor->hide();
- // Bottom buttons.
- tileset_editor_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("TileSet"), tileset_editor);
- tileset_editor_button->hide();
- tilemap_editor_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("TileMap"), tilemap_editor);
- tilemap_editor_button->hide();
+ button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("TileMap"), editor);
+ button->hide();
+}
- // Initialization.
- _update_editors();
+TileMapEditorPlugin::~TileMapEditorPlugin() {
+ local_singleton = nullptr;
}
-TilesEditorPlugin::~TilesEditorPlugin() {
- if (pattern_preview_thread.is_started()) {
- pattern_thread_exit.set();
- pattern_preview_sem.post();
- while (!pattern_thread_exited.is_set()) {
- OS::get_singleton()->delay_usec(10000);
- RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
+void TileSetEditorPlugin::edit(Object *p_object) {
+ editor->edit(Ref<TileSet>(p_object));
+}
+
+bool TileSetEditorPlugin::handles(Object *p_object) const {
+ return Object::cast_to<TileSet>(p_object) != nullptr;
+}
+
+void TileSetEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ button->show();
+ if (!local_singleton->is_editor_visible()) {
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(editor);
+ }
+ } else {
+ button->hide();
+ if (editor->is_visible_in_tree()) {
+ EditorNode::get_singleton()->hide_bottom_panel();
}
- pattern_preview_thread.wait_to_finish();
}
}
+
+TileSetEditorPlugin::TileSetEditorPlugin() {
+ DEV_ASSERT(local_singleton);
+
+ editor = memnew(TileSetEditor);
+ editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
+ editor->hide();
+
+ button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("TileSet"), editor);
+ button->hide();
+}
diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h
index 50073e59c6..73be9798bd 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.h
+++ b/editor/plugins/tiles/tiles_editor_plugin.h
@@ -38,10 +38,10 @@
#include "tile_map_editor.h"
#include "tile_set_editor.h"
-class TilesEditorPlugin : public EditorPlugin {
- GDCLASS(TilesEditorPlugin, EditorPlugin);
+class TilesEditorUtils : public Object {
+ GDCLASS(TilesEditorUtils, Object);
- static TilesEditorPlugin *singleton;
+ static TilesEditorUtils *singleton;
public:
enum SourceSortOption {
@@ -53,28 +53,11 @@ public:
};
private:
- bool is_visible = false;
-
- bool tile_map_changed_needs_update = false;
- ObjectID tile_map_id;
- Ref<TileSet> tile_set;
- bool is_editing_tile_set = false;
-
- Button *tilemap_editor_button = nullptr;
- TileMapEditor *tilemap_editor = nullptr;
-
- Button *tileset_editor_button = nullptr;
- TileSetEditor *tileset_editor = nullptr;
-
- void _update_editors();
-
// For synchronization.
int atlas_sources_lists_current = 0;
float atlas_view_zoom = 1.0;
Vector2 atlas_view_scroll;
- void _tile_map_changed();
-
// Source sorting.
int source_sort = SOURCE_SORT_ID;
@@ -101,16 +84,8 @@ private:
static void _thread_func(void *ud);
void _thread();
-protected:
- void _notification(int p_what);
-
public:
- _FORCE_INLINE_ static TilesEditorPlugin *get_singleton() { return singleton; }
-
- virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return tilemap_editor->forward_canvas_gui_input(p_event); }
- virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { tilemap_editor->forward_canvas_draw_over_viewport(p_overlay); }
-
- bool is_tile_map_selected();
+ _FORCE_INLINE_ static TilesEditorUtils *get_singleton() { return singleton; }
// Pattern preview API.
void queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback);
@@ -126,14 +101,52 @@ public:
void set_sorting_option(int p_option);
List<int> get_sorted_sources(const Ref<TileSet> p_tile_set) const;
+ static void draw_selection_rect(CanvasItem *p_ci, const Rect2 &p_rect, const Color &p_color = Color(1.0, 1.0, 1.0));
+
+ TilesEditorUtils();
+ ~TilesEditorUtils();
+};
+
+class TileMapEditorPlugin : public EditorPlugin {
+ GDCLASS(TileMapEditorPlugin, EditorPlugin);
+
+ TileMapEditor *editor = nullptr;
+ Button *button = nullptr;
+ TileMap *tile_map = nullptr;
+
+ bool tile_map_changed_needs_update = false;
+ void _tile_map_changed();
+ void _update_tile_map();
+
+protected:
+ void _notification(int p_notification);
+
+public:
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- static void draw_selection_rect(CanvasItem *p_ci, const Rect2 &p_rect, const Color &p_color = Color(1.0, 1.0, 1.0));
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
+
+ bool is_editor_visible() const;
+
+ TileMapEditorPlugin();
+ ~TileMapEditorPlugin();
+};
+
+class TileSetEditorPlugin : public EditorPlugin {
+ GDCLASS(TileSetEditorPlugin, EditorPlugin);
+
+ TileSetEditor *editor = nullptr;
+ Button *button = nullptr;
+
+public:
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool p_visible) override;
- TilesEditorPlugin();
- ~TilesEditorPlugin();
+ TileSetEditorPlugin();
};
#endif // TILES_EDITOR_PLUGIN_H
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index c9651e634f..3062059001 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -31,7 +31,6 @@
#include "visual_shader_editor_plugin.h"
#include "core/config/project_settings.h"
-#include "core/core_string_names.h"
#include "core/io/resource_loader.h"
#include "core/math/math_defs.h"
#include "core/os/keyboard.h"
@@ -57,6 +56,9 @@
#include "scene/gui/tree.h"
#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
+#include "scene/resources/curve_texture.h"
+#include "scene/resources/image_texture.h"
+#include "scene/resources/style_box_flat.h"
#include "scene/resources/visual_shader_nodes.h"
#include "scene/resources/visual_shader_particle_nodes.h"
#include "servers/display_server.h"
@@ -239,7 +241,7 @@ void VisualShaderGraphPlugin::update_curve(int p_node_id) {
if (tex->get_texture().is_valid()) {
links[p_node_id].curve_editors[0]->set_curve(tex->get_texture()->get_curve());
}
- tex->emit_signal(CoreStringNames::get_singleton()->changed);
+ tex->emit_changed();
}
}
@@ -253,7 +255,7 @@ void VisualShaderGraphPlugin::update_curve_xyz(int p_node_id) {
links[p_node_id].curve_editors[1]->set_curve(tex->get_texture()->get_curve_y());
links[p_node_id].curve_editors[2]->set_curve(tex->get_texture()->get_curve_z());
}
- tex->emit_signal(CoreStringNames::get_singleton()->changed);
+ tex->emit_changed();
}
}
@@ -426,7 +428,8 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
Ref<VisualShaderNodeGroupBase> group_node = Object::cast_to<VisualShaderNodeGroupBase>(vsnode.ptr());
bool is_group = !group_node.is_null();
- bool is_comment = false;
+ Ref<VisualShaderNodeComment> comment_node = Object::cast_to<VisualShaderNodeComment>(vsnode.ptr());
+ bool is_comment = comment_node.is_valid();
Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(group_node.ptr());
bool is_expression = !expression_node.is_null();
@@ -465,6 +468,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
expression = expression_node->get_expression();
}
+ if (is_comment) {
+ node->set_visible(false);
+ }
+
node->set_position_offset(visual_shader->get_node_position(p_type, p_id));
node->set_title(vsnode->get_caption());
node->set_name(itos(p_id));
@@ -488,17 +495,6 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
}
if (is_resizable) {
- Ref<VisualShaderNodeComment> comment_node = Object::cast_to<VisualShaderNodeComment>(vsnode.ptr());
- if (comment_node.is_valid()) {
- is_comment = true;
- node->set_comment(true);
-
- Label *comment_label = memnew(Label);
- node->add_child(comment_label);
- comment_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- comment_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- comment_label->set_text(comment_node->get_description());
- }
editor->call_deferred(SNAME("_set_node_size"), (int)p_type, p_id, size);
}
@@ -560,9 +556,8 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
if (curve.is_valid()) {
custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- Callable ce = callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve);
- if (curve->get_texture().is_valid() && !curve->get_texture()->is_connected("changed", ce)) {
- curve->get_texture()->connect("changed", ce.bind(p_id));
+ if (curve->get_texture().is_valid()) {
+ curve->get_texture()->connect_changed(callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve).bind(p_id));
}
CurveEditor *curve_editor = memnew(CurveEditor);
@@ -578,9 +573,8 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
if (curve_xyz.is_valid()) {
custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- Callable ce = callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve_xyz);
- if (curve_xyz->get_texture().is_valid() && !curve_xyz->get_texture()->is_connected("changed", ce)) {
- curve_xyz->get_texture()->connect("changed", ce.bind(p_id));
+ if (curve_xyz->get_texture().is_valid()) {
+ curve_xyz->get_texture()->connect_changed(callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve_xyz).bind(p_id));
}
CurveEditor *curve_editor_x = memnew(CurveEditor);
@@ -1159,20 +1153,14 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
visual_shader = Ref<VisualShader>(p_visual_shader);
graph_plugin->register_shader(visual_shader.ptr());
- Callable ce = callable_mp(this, &VisualShaderEditor::_update_preview);
- if (!visual_shader->is_connected("changed", ce)) {
- visual_shader->connect("changed", ce);
- }
- visual_shader->set_graph_offset(graph->get_scroll_ofs() / EDSCALE);
+ visual_shader->connect_changed(callable_mp(this, &VisualShaderEditor::_update_preview));
+ visual_shader->set_graph_offset(graph->get_scroll_offset() / EDSCALE);
_set_mode(visual_shader->get_mode());
_update_nodes();
} else {
if (visual_shader.is_valid()) {
- Callable ce = callable_mp(this, &VisualShaderEditor::_update_preview);
- if (visual_shader->is_connected("changed", ce)) {
- visual_shader->disconnect("changed", ce);
- }
+ visual_shader->disconnect_changed(callable_mp(this, &VisualShaderEditor::_update_preview));
}
visual_shader.unref();
}
@@ -2031,7 +2019,7 @@ void VisualShaderEditor::_update_graph() {
return;
}
- graph->set_scroll_ofs(visual_shader->get_graph_offset() * EDSCALE);
+ graph->set_scroll_offset(visual_shader->get_graph_offset() * EDSCALE);
VisualShader::Type type = get_current_shader_type();
@@ -3089,6 +3077,9 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
if (!is_native) {
vsnode->set_script(add_options[p_idx].script);
}
+ VisualShaderNodeCustom *custom_node = Object::cast_to<VisualShaderNodeCustom>(vsn);
+ ERR_FAIL_COND(!custom_node);
+ custom_node->update_ports();
}
bool is_texture2d = (Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()) != nullptr);
@@ -3099,7 +3090,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
bool is_curve_xyz = (Object::cast_to<VisualShaderNodeCurveXYZTexture>(vsnode.ptr()) != nullptr);
bool is_parameter = (Object::cast_to<VisualShaderNodeParameter>(vsnode.ptr()) != nullptr);
- Point2 position = graph->get_scroll_ofs();
+ Point2 position = graph->get_scroll_offset();
if (saved_node_pos_dirty) {
position += saved_node_pos;
@@ -3217,16 +3208,26 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
} else {
- // Attempting to connect to the first correct port.
+ int _to_slot = -1;
+
+ // Attempting to connect to the default input port or to the first correct port (if it's not found).
for (int i = 0; i < vsnode->get_input_port_count(); i++) {
if (visual_shader->is_port_types_compatible(output_port_type, vsnode->get_input_port_type(i))) {
- undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, i);
- undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, i);
- undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, i);
- undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, i);
- break;
+ if (i == vsnode->get_default_input_port(output_port_type)) {
+ _to_slot = i;
+ break;
+ } else if (_to_slot == -1) {
+ _to_slot = i;
+ }
}
}
+
+ if (_to_slot >= 0) {
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ }
}
if (output_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {
@@ -4386,7 +4387,7 @@ void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2
mpos = graph->get_local_mouse_position();
}
- _dup_paste_nodes(type, copy_items_buffer, copy_connections_buffer, graph->get_scroll_ofs() / scale + mpos / scale - selection_center, false);
+ _dup_paste_nodes(type, copy_items_buffer, copy_connections_buffer, graph->get_scroll_offset() / scale + mpos / scale - selection_center, false);
}
void VisualShaderEditor::_mode_selected(int p_id) {
@@ -5089,7 +5090,7 @@ VisualShaderEditor::VisualShaderEditor() {
FileSystemDock::get_singleton()->connect("resource_removed", callable_mp(this, &VisualShaderEditor::_resource_removed));
graph = memnew(GraphEdit);
- graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL);
+ graph->get_menu_hbox()->set_h_size_flags(SIZE_EXPAND_FILL);
graph->set_v_size_flags(SIZE_EXPAND_FILL);
graph->set_h_size_flags(SIZE_EXPAND_FILL);
graph->set_show_zoom_label(true);
@@ -5182,8 +5183,8 @@ VisualShaderEditor::VisualShaderEditor() {
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SAMPLER, VisualShaderNode::PORT_TYPE_SAMPLER);
VSeparator *vs = memnew(VSeparator);
- graph->get_zoom_hbox()->add_child(vs);
- graph->get_zoom_hbox()->move_child(vs, 0);
+ graph->get_menu_hbox()->add_child(vs);
+ graph->get_menu_hbox()->move_child(vs, 0);
custom_mode_box = memnew(CheckBox);
custom_mode_box->set_text(TTR("Custom"));
@@ -5217,28 +5218,28 @@ VisualShaderEditor::VisualShaderEditor() {
edit_type = edit_type_standard;
- graph->get_zoom_hbox()->add_child(custom_mode_box);
- graph->get_zoom_hbox()->move_child(custom_mode_box, 0);
- graph->get_zoom_hbox()->add_child(edit_type_standard);
- graph->get_zoom_hbox()->move_child(edit_type_standard, 0);
- graph->get_zoom_hbox()->add_child(edit_type_particles);
- graph->get_zoom_hbox()->move_child(edit_type_particles, 0);
- graph->get_zoom_hbox()->add_child(edit_type_sky);
- graph->get_zoom_hbox()->move_child(edit_type_sky, 0);
- graph->get_zoom_hbox()->add_child(edit_type_fog);
- graph->get_zoom_hbox()->move_child(edit_type_fog, 0);
+ graph->get_menu_hbox()->add_child(custom_mode_box);
+ graph->get_menu_hbox()->move_child(custom_mode_box, 0);
+ graph->get_menu_hbox()->add_child(edit_type_standard);
+ graph->get_menu_hbox()->move_child(edit_type_standard, 0);
+ graph->get_menu_hbox()->add_child(edit_type_particles);
+ graph->get_menu_hbox()->move_child(edit_type_particles, 0);
+ graph->get_menu_hbox()->add_child(edit_type_sky);
+ graph->get_menu_hbox()->move_child(edit_type_sky, 0);
+ graph->get_menu_hbox()->add_child(edit_type_fog);
+ graph->get_menu_hbox()->move_child(edit_type_fog, 0);
add_node = memnew(Button);
add_node->set_flat(true);
add_node->set_text(TTR("Add Node..."));
- graph->get_zoom_hbox()->add_child(add_node);
- graph->get_zoom_hbox()->move_child(add_node, 0);
+ graph->get_menu_hbox()->add_child(add_node);
+ graph->get_menu_hbox()->move_child(add_node, 0);
add_node->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_members_dialog).bind(false, VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PORT_TYPE_MAX));
varying_button = memnew(MenuButton);
varying_button->set_text(TTR("Manage Varyings"));
varying_button->set_switch_on_hover(true);
- graph->get_zoom_hbox()->add_child(varying_button);
+ graph->get_menu_hbox()->add_child(varying_button);
PopupMenu *varying_menu = varying_button->get_popup();
varying_menu->add_item(TTR("Add Varying"), int(VaryingMenuOptions::ADD));
@@ -5249,7 +5250,7 @@ VisualShaderEditor::VisualShaderEditor() {
preview_shader->set_flat(true);
preview_shader->set_toggle_mode(true);
preview_shader->set_tooltip_text(TTR("Show generated shader code."));
- graph->get_zoom_hbox()->add_child(preview_shader);
+ graph->get_menu_hbox()->add_child(preview_shader);
preview_shader->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_preview_text));
///////////////////////////////////////
@@ -5874,6 +5875,10 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("CurveXYZTexture", "Textures/Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value obtained from the depth prepass in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
texture2d_node_option_idx = add_options.size();
+ add_options.push_back(AddOption("WorldPositionFromDepth", "Textures/Functions", "VisualShaderNodeWorldPositionFromDepth", TTR("Reconstructs the World Position of the Node from the depth texture."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ texture2d_node_option_idx = add_options.size();
+ add_options.push_back(AddOption("ScreenNormalWorldSpace", "Textures/Functions", "VisualShaderNodeScreenNormalWorldSpace", TTR("Unpacks the Screen Normal Texture in World Space"), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ texture2d_node_option_idx = add_options.size();
add_options.push_back(AddOption("Texture2D", "Textures/Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
texture2d_array_node_option_idx = add_options.size();
add_options.push_back(AddOption("Texture2DArray", "Textures/Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
@@ -5918,6 +5923,8 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("ProximityFade", "Utility", "VisualShaderNodeProximityFade", TTR("The proximity fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("RandomRange", "Utility", "VisualShaderNodeRandomRange", TTR("Returns a random value between the minimum and maximum input values."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Remap", "Utility", "VisualShaderNodeRemap", TTR("Remaps a given input from the input range to the output range."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("RotationByAxis", "Utility", "VisualShaderNodeRotationByAxis", TTR("Rotates an input vector by a given angle."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("RotationByAxis", "Utility", "VisualShaderNodeRotationByAxis", TTR("Rotates an input vector by a given angle."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
// VECTOR
@@ -6120,7 +6127,6 @@ VisualShaderEditor::VisualShaderEditor() {
// SPECIAL
- add_options.push_back(AddOption("Comment", "Special", "VisualShaderNodeComment", TTR("A rectangular area with a description string for better graph organization.")));
add_options.push_back(AddOption("Expression", "Special", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));
add_options.push_back(AddOption("GlobalExpression", "Special", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, parameters and constants.")));
add_options.push_back(AddOption("ParameterRef", "Special", "VisualShaderNodeParameterRef", TTR("A reference to an existing parameter.")));
@@ -6447,7 +6453,7 @@ public:
properties[i]->update_property();
properties[i]->set_name_split_ratio(0);
}
- node->connect("changed", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_node_changed));
+ node->connect_changed(callable_mp(this, &VisualShaderNodePluginDefaultEditor::_node_changed));
}
static void _bind_methods() {
@@ -6713,7 +6719,7 @@ void VisualShaderNodePortPreview::_shader_changed() {
void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid) {
shader = p_shader;
- shader->connect("changed", callable_mp(this, &VisualShaderNodePortPreview::_shader_changed), CONNECT_DEFERRED);
+ shader->connect_changed(callable_mp(this, &VisualShaderNodePortPreview::_shader_changed), CONNECT_DEFERRED);
type = p_type;
port = p_port;
node = p_node;
diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index 5ae5468e4b..43b133f4b5 100644
--- a/editor/plugins/voxel_gi_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -166,8 +166,13 @@ void VoxelGIEditorPlugin::_voxel_gi_save_path_and_bake(const String &p_path) {
probe_file->hide();
if (voxel_gi) {
voxel_gi->bake();
- ERR_FAIL_COND(voxel_gi->get_probe_data().is_null());
- ResourceSaver::save(voxel_gi->get_probe_data(), p_path, ResourceSaver::FLAG_CHANGE_PATH);
+ // Ensure the VoxelGIData is always saved to an external resource.
+ // This avoids bloating the scene file with large binary data,
+ // which would be serialized as Base64 if the scene is a `.tscn` file.
+ Ref<VoxelGIData> voxel_gi_data = voxel_gi->get_probe_data();
+ ERR_FAIL_COND(voxel_gi_data.is_null());
+ voxel_gi_data->set_path(p_path);
+ ResourceSaver::save(voxel_gi_data, p_path, ResourceSaver::FLAG_CHANGE_PATH);
}
}
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 9008b6a600..b2994f3065 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -336,7 +336,7 @@ bool ProjectConverter3To4::convert() {
// Checking if folder contains valid Godot 3 project.
// Project should not be converted more than once.
{
- String converter_text = "; Project was converted by built-in tool to Godot 4.0";
+ String converter_text = "; Project was converted by built-in tool to Godot 4";
ERR_FAIL_COND_V_MSG(!FileAccess::exists("project.godot"), false, "Current working directory doesn't contain a \"project.godot\" file for a Godot 3 project.");
@@ -536,7 +536,7 @@ bool ProjectConverter3To4::validate_conversion() {
// Checking if folder contains valid Godot 3 project.
// Project should not be converted more than once.
{
- String conventer_text = "; Project was converted by built-in tool to Godot 4.0";
+ String conventer_text = "; Project was converted by built-in tool to Godot 4";
ERR_FAIL_COND_V_MSG(!FileAccess::exists("project.godot"), false, "Current directory doesn't contain any Godot 3 project");
@@ -857,16 +857,16 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_gdscript_builtin("\tif OS.get_borderless_window(): pass", "\tif get_window().borderless: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tOS.set_borderless_window(Settings.borderless)", "\tget_window().borderless = (Settings.borderless)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide( a, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide_with_snap( a, g, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide( a, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter3To4 looks that snap in Godot 4 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide_with_snap( a, g, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\t# TODOConverter3To4 looks that snap in Godot 4 is float, not vector like in Godot 3 - previous value `g`\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("remove_and_slide(a,b,c,d,e,f)", "remove_and_slide(a,b,c,d,e,f)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("list_dir_begin( )", "list_dir_begin() # TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("sort_custom( a , b )", "sort_custom(Callable(a, b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -874,9 +874,9 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_gdscript_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1, 2, 3, 4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -998,7 +998,7 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_gdscript_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a, b, c, d).abc# e) TODOGODOT4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a, b, c, d).abc# e) TODOConverter3To4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("get_focus_owner()", "get_viewport().gui_get_focus_owner()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("button.pressed = 1", "button.button_pressed = 1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("button.pressed=1", "button.button_pressed=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -1149,13 +1149,13 @@ bool ProjectConverter3To4::test_array_names() {
// Light2D, Texture, Viewport are special classes(probably virtual ones).
if (ClassDB::class_exists(StringName(old_class)) && old_class != "Light2D" && old_class != "Texture" && old_class != "Viewport") {
- ERR_PRINT(vformat("Class \"%s\" exists in Godot 4.0, so it cannot be renamed to something else.", old_class));
+ ERR_PRINT(vformat("Class \"%s\" exists in Godot 4, so it cannot be renamed to something else.", old_class));
valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI.
}
// Callable is special class, to which normal classes may be renamed.
if (!ClassDB::class_exists(StringName(new_class)) && new_class != "Callable") {
- ERR_PRINT(vformat("Class \"%s\" does not exist in Godot 4.0, so it cannot be used in the conversion.", old_class));
+ ERR_PRINT(vformat("Class \"%s\" does not exist in Godot 4, so it cannot be used in the conversion.", old_class));
valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI.
}
}
@@ -1630,8 +1630,8 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
// With longer lines, doing so can sometimes be significantly faster.
if ((line.contains(".lock") || line.contains(".unlock")) && !line.contains("mtx") && !line.contains("mutex") && !line.contains("Mutex")) {
- line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
- line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
+ line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
+ line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
}
// PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray
@@ -1832,7 +1832,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
// infiinite_interia
if (parts.size() >= 6) {
- line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n";
+ line_new += starting_space + "# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `" + parts[5] + "`\n";
}
line_new += starting_space + base_obj + "move_and_slide()";
@@ -1863,7 +1863,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
// snap
if (parts.size() >= 2) {
- line_new += starting_space + "# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n";
+ line_new += starting_space + "# TODOConverter3To4 looks that snap in Godot 4 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n";
}
// up_direction
@@ -1888,7 +1888,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
// infiinite_interia
if (parts.size() >= 7) {
- line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n";
+ line_new += starting_space + "# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `" + parts[6] + "`\n";
}
line_new += starting_space + base_obj + "move_and_slide()";
@@ -1919,7 +1919,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
int start = line.find("list_dir_begin(");
int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
- line = line.substr(0, start) + "list_dir_begin() " + line.substr(end + start) + "# TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547";
+ line = line.substr(0, start) + "list_dir_begin() " + line.substr(end + start) + "# TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547";
}
}
@@ -2203,14 +2203,14 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
}
- // draw_rect(a,b,c,d,e) -> draw_rect(a,b,c,d)#e) TODOGODOT4 Antialiasing argument is missing
+ // draw_rect(a,b,c,d,e) -> draw_rect(a,b,c,d)#e) TODOConverter3To4 Antialiasing argument is missing
if (contains_function_call(line, "draw_rect(")) {
int start = line.find("draw_rect(");
int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 5) {
- line = line.substr(0, start) + "draw_rect(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ", " + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOGODOT4 Antialiasing argument is missing";
+ line = line.substr(0, start) + "draw_rect(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ", " + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOConverter3To4 Antialiasing argument is missing";
}
}
}
@@ -2241,9 +2241,10 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
// rotating = true -> ignore_rotation = false # reversed "rotating" for Camera2D
if (contains_function_call(line, "rotating")) {
- int start = line.find("rotating");
+ String function_name = "rotating";
+ int start = line.find(function_name);
bool foundNextEqual = false;
- String line_to_check = line.substr(start + String("rotating").length());
+ String line_to_check = line.substr(start + function_name.length());
String assigned_value;
for (int current_index = 0; line_to_check.length() > current_index; current_index++) {
char32_t chr = line_to_check.get(current_index);
@@ -2251,14 +2252,14 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
continue;
} else if (chr == '=') {
foundNextEqual = true;
- assigned_value = line.right(current_index).strip_edges();
+ assigned_value = line.substr(start + function_name.length() + current_index + 1).strip_edges();
assigned_value = assigned_value == "true" ? "false" : "true";
} else {
break;
}
}
if (foundNextEqual) {
- line = line.substr(0, start) + "ignore_rotation =" + assigned_value + " # reversed \"rotating\" for Camera2D";
+ line = line.substr(0, start) + "ignore_rotation = " + assigned_value + " # reversed \"rotating\" for Camera2D";
}
}
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index a86963c330..691adcdb7a 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -59,6 +59,7 @@
#include "scene/gui/separator.h"
#include "scene/gui/texture_rect.h"
#include "scene/main/window.h"
+#include "scene/resources/image_texture.h"
#include "servers/display_server.h"
#include "servers/navigation_server_3d.h"
#include "servers/physics_server_2d.h"
@@ -1042,10 +1043,25 @@ void ProjectListItemControl::set_project_icon(const Ref<Texture2D> &p_icon) {
project_icon->set_texture(p_icon);
}
-void ProjectListItemControl::set_unsupported_features(const PackedStringArray &p_features) {
+bool _project_feature_looks_like_version(const String &p_feature) {
+ return p_feature.contains(".") && p_feature.substr(0, 3).is_numeric();
+}
+
+void ProjectListItemControl::set_unsupported_features(PackedStringArray p_features) {
if (p_features.size() > 0) {
- String unsupported_features_str = String(", ").join(p_features);
- project_unsupported_features->set_tooltip_text(TTR("The project uses features unsupported by the current build:") + "\n" + unsupported_features_str);
+ String tooltip_text = "";
+ for (int i = 0; i < p_features.size(); i++) {
+ if (_project_feature_looks_like_version(p_features[i])) {
+ tooltip_text += TTR("This project was last edited in a different Godot version: ") + p_features[i] + "\n";
+ p_features.remove_at(i);
+ i--;
+ }
+ }
+ if (p_features.size() > 0) {
+ String unsupported_features_str = String(", ").join(p_features);
+ tooltip_text += TTR("This project uses features unsupported by the current build:") + "\n" + unsupported_features_str;
+ }
+ project_unsupported_features->set_tooltip_text(tooltip_text);
project_unsupported_features->show();
} else {
project_unsupported_features->hide();
@@ -1450,7 +1466,7 @@ void ProjectList::_create_project_item_control(int p_index) {
hb->set_project_path(item.path);
hb->set_tooltip_text(item.description);
hb->set_tags(item.tags, this);
- hb->set_unsupported_features(item.unsupported_features);
+ hb->set_unsupported_features(item.unsupported_features.duplicate());
hb->set_is_favorite(item.favorite);
hb->set_is_missing(item.missing);
@@ -2297,8 +2313,8 @@ void ProjectManager::_open_selected_projects_ask() {
warning_message += TTR("Warning: This project uses C#, but this build of Godot does not have\nthe Mono module. If you proceed you will not be able to use any C# scripts.\n\n");
unsupported_features.remove_at(i);
i--;
- } else if (feature.substr(0, 3).is_numeric()) {
- warning_message += vformat(TTR("Warning: This project was built in Godot %s.\nOpening will upgrade or downgrade the project to Godot %s.\n\n"), Variant(feature), Variant(VERSION_BRANCH));
+ } else if (_project_feature_looks_like_version(feature)) {
+ warning_message += vformat(TTR("Warning: This project was last edited in Godot %s. Opening will change it to Godot %s.\n\n"), Variant(feature), Variant(VERSION_BRANCH));
unsupported_features.remove_at(i);
i--;
}
@@ -2337,6 +2353,8 @@ void ProjectManager::_perform_full_project_conversion() {
args.push_back("--path");
args.push_back(path);
args.push_back("--convert-3to4");
+ args.push_back("--rendering-driver");
+ args.push_back(Main::get_rendering_driver_name());
Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
@@ -2504,6 +2522,7 @@ void ProjectManager::_apply_project_tags() {
callable_mp((Window *)tag_manage_dialog, &Window::show).call_deferred(); // Make sure the dialog does not disappear.
return;
} else {
+ tags.sort();
cfg.set_value("application", "config/tags", tags);
err = cfg.save(project_godot);
if (err != OK) {
@@ -3095,7 +3114,7 @@ ProjectManager::ProjectManager() {
ask_full_convert_dialog = memnew(ConfirmationDialog);
ask_full_convert_dialog->set_autowrap(true);
- ask_full_convert_dialog->set_text(TTR("This option will perform full project conversion, updating scenes, resources and scripts from Godot 3.x to work in Godot 4.0.\n\nNote that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.\n\nIMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open it in older versions of Godot."));
+ ask_full_convert_dialog->set_text(TTR("This option will perform full project conversion, updating scenes, resources and scripts from Godot 3 to work in Godot 4.\n\nNote that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.\n\nIMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open it in older versions of Godot."));
ask_full_convert_dialog->connect("confirmed", callable_mp(this, &ProjectManager::_perform_full_project_conversion));
add_child(ask_full_convert_dialog);
diff --git a/editor/project_manager.h b/editor/project_manager.h
index bd82fd0578..043178fb6f 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -166,7 +166,7 @@ public:
void set_project_path(const String &p_path);
void set_tags(const PackedStringArray &p_tags, ProjectList *p_parent_list);
void set_project_icon(const Ref<Texture2D> &p_icon);
- void set_unsupported_features(const PackedStringArray &p_features);
+ void set_unsupported_features(PackedStringArray p_features);
bool should_load_project_icon() const;
void set_selected(bool p_selected);
diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp
index b674ce5967..636bb01557 100644
--- a/editor/register_editor_types.cpp
+++ b/editor/register_editor_types.cpp
@@ -50,7 +50,19 @@
#include "editor/gui/editor_file_dialog.h"
#include "editor/gui/editor_spin_slider.h"
#include "editor/import/editor_import_plugin.h"
+#include "editor/import/resource_importer_bitmask.h"
+#include "editor/import/resource_importer_bmfont.h"
+#include "editor/import/resource_importer_csv_translation.h"
+#include "editor/import/resource_importer_dynamic_font.h"
+#include "editor/import/resource_importer_image.h"
+#include "editor/import/resource_importer_imagefont.h"
+#include "editor/import/resource_importer_layered_texture.h"
+#include "editor/import/resource_importer_obj.h"
#include "editor/import/resource_importer_scene.h"
+#include "editor/import/resource_importer_shader_file.h"
+#include "editor/import/resource_importer_texture.h"
+#include "editor/import/resource_importer_texture_atlas.h"
+#include "editor/import/resource_importer_wav.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/plugins/audio_stream_editor_plugin.h"
#include "editor/plugins/audio_stream_randomizer_editor_plugin.h"
@@ -168,6 +180,21 @@ void register_editor_types() {
GDREGISTER_CLASS(EditorDebuggerPlugin);
GDREGISTER_ABSTRACT_CLASS(EditorDebuggerSession);
+ // Required to document import options in the class reference.
+ GDREGISTER_CLASS(ResourceImporterBitMap);
+ GDREGISTER_CLASS(ResourceImporterBMFont);
+ GDREGISTER_CLASS(ResourceImporterCSVTranslation);
+ GDREGISTER_CLASS(ResourceImporterDynamicFont);
+ GDREGISTER_CLASS(ResourceImporterImage);
+ GDREGISTER_CLASS(ResourceImporterImageFont);
+ GDREGISTER_CLASS(ResourceImporterLayeredTexture);
+ GDREGISTER_CLASS(ResourceImporterOBJ);
+ GDREGISTER_CLASS(ResourceImporterScene);
+ GDREGISTER_CLASS(ResourceImporterShaderFile);
+ GDREGISTER_CLASS(ResourceImporterTexture);
+ GDREGISTER_CLASS(ResourceImporterTextureAtlas);
+ GDREGISTER_CLASS(ResourceImporterWAV);
+
// This list is alphabetized, and plugins that depend on Node2D are in their own section below.
EditorPlugins::add_by_type<AnimationTreeEditorPlugin>();
EditorPlugins::add_by_type<AudioStreamEditorPlugin>();
@@ -227,7 +254,8 @@ void register_editor_types() {
EditorPlugins::add_by_type<Cast2DEditorPlugin>();
EditorPlugins::add_by_type<Skeleton2DEditorPlugin>();
EditorPlugins::add_by_type<Sprite2DEditorPlugin>();
- EditorPlugins::add_by_type<TilesEditorPlugin>();
+ EditorPlugins::add_by_type<TileMapEditorPlugin>();
+ EditorPlugins::add_by_type<TileSetEditorPlugin>();
// For correct doc generation.
GLOBAL_DEF("editor/run/main_run_args", "");
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index 7d7ea2f509..607b53718b 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -164,37 +164,64 @@ void ShaderCreateDialog::_create_new() {
code += vformat("shader_type %s;\n", mode_menu->get_text().to_snake_case());
if (current_template == 0) { // Default template.
- code += "\n";
switch (current_mode) {
case Shader::MODE_SPATIAL:
- code += "void fragment() {\n";
- code += "\t// Place fragment code here.\n";
- code += "}\n";
+ code += R"(
+void vertex() {
+ // Called for every vertex the material is visible on.
+}
+
+void fragment() {
+ // Called for every pixel the material is visible on.
+}
+
+void light() {
+ // Called for every pixel for every light affecting the material.
+}
+)";
break;
case Shader::MODE_CANVAS_ITEM:
- code += "void fragment() {\n";
- code += "\t// Place fragment code here.\n";
- code += "}\n";
+ code += R"(
+void vertex() {
+ // Called for every vertex the material is visible on.
+}
+
+void fragment() {
+ // Called for every pixel the material is visible on.
+}
+
+void light() {
+ // Called for every pixel for every light affecting the CanvasItem.
+}
+)";
break;
case Shader::MODE_PARTICLES:
- code += "void start() {\n";
- code += "\t// Place start code here.\n";
- code += "}\n";
- code += "\n";
- code += "void process() {\n";
- code += "\t// Place process code here.\n";
- code += "}\n";
+ code += R"(
+void start() {
+ // Called when a particle is spawned.
+}
+
+void process() {
+ // Called every frame on existing particles (according to the Fixed FPS property).
+}
+)";
break;
case Shader::MODE_SKY:
- code += "void sky() {\n";
- code += "\t// Place sky code here.\n";
- code += "}\n";
+ code += R"(
+void sky() {
+ // Called for every visible pixel in the sky background, as well as all pixels
+ // in the radiance cubemap.
+}
+)";
break;
case Shader::MODE_FOG:
- code += "void fog() {\n";
- code += "\t// Place fog code here.\n";
- code += "}\n";
- break;
+ code += R"(
+void fog() {
+ // Called once for every froxel that is touched by an axis-aligned bounding box
+ // of the associated FogVolume. This means that froxels that just barely touch
+ // a given FogVolume will still be used.
+}
+)";
}
}
text_shader->set_code(code.as_string());
@@ -464,7 +491,7 @@ String ShaderCreateDialog::_validate_path(const String &p_path) {
}
void ShaderCreateDialog::_msg_script_valid(bool valid, const String &p_msg) {
- error_label->set_text("- " + p_msg);
+ error_label->set_text(String::utf8("• ") + p_msg);
if (valid) {
error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("success_color"), SNAME("Editor")));
} else {
@@ -473,7 +500,7 @@ void ShaderCreateDialog::_msg_script_valid(bool valid, const String &p_msg) {
}
void ShaderCreateDialog::_msg_path_valid(bool valid, const String &p_msg) {
- path_error_label->set_text("- " + p_msg);
+ path_error_label->set_text(String::utf8("• ") + p_msg);
if (valid) {
path_error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("success_color"), SNAME("Editor")));
} else {
diff --git a/editor/translations/editor/ar.po b/editor/translations/editor/ar.po
index 152f0c6523..2cbd33332d 100644
--- a/editor/translations/editor/ar.po
+++ b/editor/translations/editor/ar.po
@@ -80,12 +80,14 @@
# بسام العوفي <co-able@hotmail.com>, 2023.
# Abdulkarim <abwkhaldalhwsawy@gmail.com>, 2023.
# Rémi Verschelde <remi@godotengine.org>, 2023.
+# Omran Alsaedi <Omran2222@outlook.sa>, 2023.
+# Android Prime <abodinagdat16@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-20 03:05+0000\n"
+"PO-Revision-Date: 2023-07-05 13:48+0000\n"
"Last-Translator: بسام العوفي <co-able@hotmail.com>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/"
"godot/ar/>\n"
@@ -95,7 +97,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Unset"
msgstr "غير محدد"
@@ -247,6 +249,9 @@ msgstr "ذراع التحكم d%"
msgid "Pressure:"
msgstr "الضغط:"
+msgid "canceled"
+msgstr "أُلغيَ"
+
msgid "touched"
msgstr "لُمست"
@@ -876,6 +881,11 @@ msgid "Blend Shape tracks only apply to MeshInstance3D nodes."
msgstr ""
"مقاطع \"خلط الأشكال\" تنطبق فقط على عُقد مثيل-مجسم-ثلاثي (MeshInstance3D)."
+msgid "Position/Rotation/Scale 3D tracks only apply to 3D-based nodes."
+msgstr ""
+"مقاطع التموضع/الاستدارة/التكبير الثلاثية تنطبق فقط على العقد ذات الأصل "
+"الثلاثي."
+
msgid ""
"Audio tracks can only point to nodes of type:\n"
"-AudioStreamPlayer\n"
@@ -1011,6 +1021,9 @@ msgstr "تكبير المحدد"
msgid "Scale From Cursor"
msgstr "تكبير من المؤشر"
+msgid "Make Easing Selection"
+msgstr "تسهيل المحدد"
+
msgid "Duplicate Selection"
msgstr "مضاعفة المحدد"
@@ -1029,6 +1042,9 @@ msgstr "عُد إلى الخطوة السابقة"
msgid "Apply Reset"
msgstr "إعادة تعيين"
+msgid "Bake Animation"
+msgstr "حمس التحريك"
+
msgid "Optimize Animation (no undo)"
msgstr "تحسين التحريك (لا تراجع)"
@@ -1047,6 +1063,15 @@ msgstr "إنشاء \"استئناف للمقطع\""
msgid "Animation Optimizer"
msgstr "مُحسن التحريك"
+msgid "Max Velocity Error:"
+msgstr "أقصى خطأ للسرعة:"
+
+msgid "Max Angular Error:"
+msgstr "أقصى خطأ للزاوي:"
+
+msgid "Max Precision Error:"
+msgstr "أقصى خطأ للدقة:"
+
msgid "Optimize"
msgstr "تحسين"
@@ -1071,6 +1096,71 @@ msgstr "نسبة التكبير:"
msgid "Select Transition and Easing"
msgstr "حدد الانتقال والتيسير"
+msgctxt "Transition Type"
+msgid "Linear"
+msgstr "الخطي"
+
+msgctxt "Transition Type"
+msgid "Sine"
+msgstr "جيبية"
+
+msgctxt "Transition Type"
+msgid "Quart"
+msgstr "ربع"
+
+msgctxt "Transition Type"
+msgid "Quad"
+msgstr "الرباعي"
+
+msgctxt "Transition Type"
+msgid "Expo"
+msgstr "المعرض"
+
+msgctxt "Transition Type"
+msgid "Elastic"
+msgstr "المرن"
+
+msgctxt "Transition Type"
+msgid "Cubic"
+msgstr "المكعبي"
+
+msgctxt "Transition Type"
+msgid "Circ"
+msgstr "الدائري"
+
+msgctxt "Transition Type"
+msgid "Bounce"
+msgstr "الوثب"
+
+msgctxt "Transition Type"
+msgid "Back"
+msgstr "المتعاود"
+
+msgctxt "Transition Type"
+msgid "Spring"
+msgstr "النابض"
+
+msgid "Transition Type:"
+msgstr "نوع الانتقال:"
+
+msgid "Ease Type:"
+msgstr "نوع التسهيل:"
+
+msgid "FPS:"
+msgstr "ط ث :"
+
+msgid "Animation Baker"
+msgstr "حامس التحريك"
+
+msgid "3D Pos/Rot/Scl Track:"
+msgstr "مقطع التموضع/الاستدارة/التكبير الثلاثية:"
+
+msgid "Blendshape Track:"
+msgstr "مقطع شكل-ممزوج:"
+
+msgid "Value Track:"
+msgstr "قيمة المقطع:"
+
msgid "Select Tracks to Copy"
msgstr "اختر المقاطع؛ لنسخها"
@@ -1084,19 +1174,19 @@ msgid "Change Audio Track Clip Start Offset"
msgstr "تغيير موضع بداية مقطع صوت"
msgid "Change Audio Track Clip End Offset"
-msgstr "تغيير موضع نهاية مقطع صوت"
+msgstr "تغيير موضع نهاية مقطع الصوت"
msgid "Go to Line"
-msgstr "اذهب إلى الخط"
+msgstr "اذهب إلى السطر"
msgid "Line Number:"
-msgstr "رقم الخط:"
+msgstr "رقم السطر:"
msgid "%d replaced."
-msgstr "تم إستبدال %d."
+msgstr "تم الإستبدال %d."
msgid "Match Case"
-msgstr "قضية تشابه"
+msgstr "حالة مطابقة"
msgid "Whole Words"
msgstr "كل الكلمات"
@@ -1144,6 +1234,9 @@ msgstr ""
"الدالة المستهدفة غير موجودة. حدّد دالة سليمة أو ألحق نصا برمجيا للعقدة "
"المستهدفة."
+msgid "Attached Script"
+msgstr "النص البرمجي الملحق"
+
msgid "Connect to Node:"
msgstr "صلها بالعقدة:"
@@ -1156,6 +1249,9 @@ msgstr "من إشارة:"
msgid "Filter Nodes"
msgstr "تصفية العُقد"
+msgid "Go to Source"
+msgstr "الذهاب للمصدر"
+
msgid "Scene does not contain any script."
msgstr "لا يحتوي المشهد علي اي برنامج نصي."
@@ -1168,6 +1264,12 @@ msgstr "تصفية الدوال"
msgid "No method found matching given filters."
msgstr "ما وجدنا الدالة المطلوبة في المصافي."
+msgid "Script Methods Only"
+msgstr "دوال النص البرمجي فقط"
+
+msgid "Compatible Methods Only"
+msgstr "الدوال المتوافقة فقط"
+
msgid "Remove"
msgstr "امسح"
@@ -1180,6 +1282,9 @@ msgstr "وسائط إستدعاء إضافية :"
msgid "Allows to drop arguments sent by signal emitter."
msgstr "يسمح بإسقاط الحجج المرسلة بواسطة باعث الإشارة."
+msgid "Unbind Signal Arguments:"
+msgstr "فك إشارة الوسائط:"
+
msgid "Receiver Method:"
msgstr "الدالة المُتلقية:"
@@ -1193,6 +1298,9 @@ msgid ""
"Defers the signal, storing it in a queue and only firing it at idle time."
msgstr "تأخير الإشارة وتخزينها في قائمة الانتظار و تشغيلها فقط في وقت الفراغ."
+msgid "One Shot"
+msgstr "محاولة واحدة"
+
msgid "Disconnects the signal after its first emission."
msgstr "فصل الإشارة بعد انبعاثها الأول."
@@ -1256,6 +1364,9 @@ msgstr "تعديل..."
msgid "Go to Method"
msgstr "اذهب إلى الدالة"
+msgid "Change Type of \"%s\""
+msgstr "تغيير نوع الـ\"%s\""
+
msgid "Change"
msgstr "تغير"
@@ -1280,6 +1391,9 @@ msgstr "المفضلة:"
msgid "Recent:"
msgstr "الحالي:"
+msgid "(Un)favorite selected item."
+msgstr "إخراج العنصر المختار من المفضلة."
+
msgid "Search:"
msgstr "بحث:"
@@ -1319,6 +1433,27 @@ msgstr ""
msgid "Toggle Visibility"
msgstr "تشغيل/إطفاء الوضوحية Visibility"
+msgid "Updating assets on target device:"
+msgstr "تحديث الأصول والملحقات في الجهاز المستهدف:"
+
+msgid "Syncing headers"
+msgstr "مزامنة الترويسات"
+
+msgid "Getting remote file system"
+msgstr "تحصيل نظام الملفات البعيد"
+
+msgid "Decompressing remote file system"
+msgstr "توسيع(ضغط) نظام الملفات البعيد"
+
+msgid "Scanning for local changes"
+msgstr "الفحص عن التغييرات القريبة"
+
+msgid "Sending list of changed files:"
+msgstr "إرسال قائمة بالملفات المتغيرة:"
+
+msgid "Sending file:"
+msgstr "إرسال ملف:"
+
msgid "ms"
msgstr "ms"
@@ -1391,6 +1526,18 @@ msgstr "الوقت"
msgid "Calls"
msgstr "إستدعاءات"
+msgid "Fit to Frame"
+msgstr "المناسبة للإطار"
+
+msgid "Linked"
+msgstr "المربوط"
+
+msgid "CPU"
+msgstr "المعالج"
+
+msgid "GPU"
+msgstr "بطاقة الشاشة"
+
msgid "Execution resumed."
msgstr "استئناف التنفيذ."
@@ -1409,15 +1556,36 @@ msgstr "%s خطأ"
msgid "%s Error:"
msgstr "%s خطأ:"
+msgid "%s Source"
+msgstr "الأصل %s"
+
+msgid "%s Source:"
+msgstr "الأصل: %s"
+
msgid "Stack Trace"
msgstr "تتبع المُكدس Stack Trace"
+msgid "Stack Trace:"
+msgstr "متابعة التراكمات:"
+
msgid "Debug session started."
msgstr "قد بدأتْ جلسة التنقيح."
msgid "Debug session closed."
msgstr "تم إغلاق جلسة التصحيح."
+msgid "Line %d"
+msgstr "السطر %d"
+
+msgid "Delete Breakpoint"
+msgstr "حذف المِفحَصَة"
+
+msgid "Delete All Breakpoints in:"
+msgstr "حذف كل المِفحَصات في:"
+
+msgid "Delete All Breakpoints"
+msgstr "حذف كل المِفحَصات"
+
msgid "Copy Error"
msgstr "خطأ في نسخ"
@@ -1546,12 +1714,24 @@ msgstr "محرر التبعيات"
msgid "Search Replacement Resource:"
msgstr "البحث عن مورد بديل:"
+msgid "Open Scene"
+msgid_plural "Open Scenes"
+msgstr[0] "فتح مشهد"
+msgstr[1] "فتح المشهد"
+msgstr[2] "فتح المشهدينِ"
+msgstr[3] "فتح المشاهد"
+msgstr[4] "فتح المشاهد"
+msgstr[5] "فتح المشاهد"
+
msgid "Open"
msgstr "افتح"
msgid "Owners of: %s (Total: %d)"
msgstr "مالكو: %s (المجموع: %d)"
+msgid "Localization remap"
+msgstr "إعادة التوطين"
+
msgid "Localization remap for path '%s' and locale '%s'."
msgstr "إعادة تعيين الترجمة للمسار 's%' والإعدادات المحلية 's%'."
@@ -1610,9 +1790,30 @@ msgstr "يملك"
msgid "Resources Without Explicit Ownership:"
msgstr "موارد من غير مالك صريح:"
+msgid "Folder name cannot be empty."
+msgstr "اسم المجلد لا يمكن أن يكون فارغا."
+
+msgid "Folder name contains invalid characters."
+msgstr "اسم المجلد يحوي حروفا لا تصلح."
+
+msgid "File with that name already exists."
+msgstr "وُجدَ ملف بهذا الاسم سابقا."
+
+msgid "Folder with that name already exists."
+msgstr "وُجدَ مجلد بهذا الاسم سابقا."
+
+msgid "Using slashes in folder names will create subfolders recursively."
+msgstr "استعمال العلامة \"المائلة\" في أسماء المجلد يُنشئ مجلدات فرعية متكررة."
+
+msgid "Folder name is valid."
+msgstr "اسم المجلد صالح."
+
msgid "Could not create folder."
msgstr "لا يمكن إنشاء المجلد."
+msgid "Create new folder in %s:"
+msgstr "إنشاء مجلد جديد في %s:"
+
msgid "Create Folder"
msgstr "أنشئ مجلد"
@@ -1631,6 +1832,10 @@ msgstr "مؤسسون المشروع"
msgid "Lead Developer"
msgstr "قائد المطوريين"
+msgctxt "Job Title"
+msgid "Project Manager"
+msgstr "مدير المشروع"
+
msgid "Developers"
msgstr "المطورون"
@@ -1813,6 +2018,9 @@ msgstr "فتح تخطيط مقطع الصوت"
msgid "There is no '%s' file."
msgstr "لا يوجد ملف '%s'."
+msgid "Layout:"
+msgstr "التخطيط:"
+
msgid "Invalid file, not an audio bus layout."
msgstr "ملف خاطئ، ليس تخطيطا لمقطع الصوت."
@@ -1883,6 +2091,9 @@ msgstr "التحميل التلقائي '%s' موجود أصلا!"
msgid "Rename Autoload"
msgstr "إعادة تسمية التحميل التلقائي"
+msgid "Toggle Autoload Globals"
+msgstr "التبديل إلى العمومات تلقائية التحميل"
+
msgid "Move Autoload"
msgstr "نقل التحميل التلقائي"
@@ -1904,6 +2115,9 @@ msgstr "%s مسار غير صالح. الملف غير موجود."
msgid "%s is an invalid path. Not in resource path (res://)."
msgstr "المسار %s غير صالح. غير موجود في مسار الموارد (//:res)."
+msgid "Add Autoload"
+msgstr "إضافة \"تلقائي التحميل\""
+
msgid "Path:"
msgstr "المسار:"
@@ -1931,15 +2145,27 @@ msgstr "تنقل"
msgid "XR"
msgstr "XR"
+msgid "RenderingDevice"
+msgstr "جهاز-التكوين"
+
+msgid "OpenGL"
+msgstr "أُبِن-جي-إل"
+
msgid "Vulkan"
msgstr "فُلقَان"
+msgid "Text Server: Fallback"
+msgstr "خادوم النصوص: الاحتياطي"
+
msgid "Text Server: Advanced"
msgstr "خادم النص: متقدم"
msgid "TTF, OTF, Type 1, WOFF1 Fonts"
msgstr "TTF, OTF, Type 1, WOFF1 خطوط"
+msgid "WOFF2 Fonts"
+msgstr "خطوط WOFF2"
+
msgid "SIL Graphite Fonts"
msgstr "خطوط الجرافيت SIL"
@@ -1957,6 +2183,9 @@ msgstr "عُقد الفيزياء ثنائية الأبعاد و PhysicsServer2D
msgid "3D Physics nodes and PhysicsServer3D."
msgstr "عقد 3D Physics و PhysicsServer3D."
+msgid "Navigation, both 2D and 3D."
+msgstr "التنقل، كلاهما الثنائي والثلاثي."
+
msgid ""
"RenderingDevice based rendering (if disabled, the OpenGL back-end is "
"required)."
@@ -2030,6 +2259,9 @@ msgstr "التعريفة:"
msgid "Reset to Defaults"
msgstr "إعادة للإعدادات الافتراضية"
+msgid "Detect from Project"
+msgstr "الاكتشاف من المشروع"
+
msgid "Actions:"
msgstr "الإجراءات:"
@@ -2232,6 +2464,9 @@ msgstr "هناك عدة مستوردات مخصوصة لعدة أنواع حدد
msgid "(Re)Importing Assets"
msgstr "إعادة استيراد المُلحقات"
+msgid "No return value."
+msgstr "لا قيمة عائدة."
+
msgid "Deprecated"
msgstr "مُهمل"
@@ -2543,6 +2778,9 @@ msgstr "اللغة:"
msgid "Language"
msgstr "اللغة"
+msgid "Country"
+msgstr "الدولة"
+
msgid "Filter Messages"
msgstr "تصفية الرسائل"
@@ -2619,6 +2857,9 @@ msgstr "صيغة الملف المطلوب غير معروفة:"
msgid "Error while saving."
msgstr "خطأ خلال الحفظ."
+msgid "Can't open file '%s'. The file could have been moved or deleted."
+msgstr "لا يمكن فتح الملف '%s'.الملف قد يكون نُقل أو حُذف."
+
msgid "Error while parsing file '%s'."
msgstr "خطأ خلال تحليل الملف '%s'."
@@ -2754,12 +2995,30 @@ msgstr "لا يمكن التراجع أثناء ضغط أزار الفأرة."
msgid "Nothing to undo."
msgstr "لا شيء للتراجع عنه."
+msgid "Global Undo: %s"
+msgstr "تراجع العموم: %s"
+
+msgid "Remote Undo: %s"
+msgstr "تراجع البعيد: %s"
+
+msgid "Scene Undo: %s"
+msgstr "تراجع المشهد: %s"
+
msgid "Can't redo while mouse buttons are pressed."
msgstr "لا يمكن إعادة العمل أثناء ضغط أزرار الفأرة."
msgid "Nothing to redo."
msgstr "لا شيء لإعادة عمله مجدداً."
+msgid "Global Redo: %s"
+msgstr "إلغاء تراجع العموم: %s"
+
+msgid "Remote Redo: %s"
+msgstr "إلغاء تراجع البعيد: %s"
+
+msgid "Scene Redo: %s"
+msgstr "إلغاء تراجع المشهد: %s"
+
msgid "Can't reload a scene that was never saved."
msgstr "لا يمكن إعادة تحميل مشهد لم يتم حفظه من قبل."
@@ -2785,6 +3044,9 @@ msgstr "حفظ و خروج"
msgid "Save modified resources before closing?"
msgstr "هل تريد حفظ التغييرات قبل الإغلاق؟"
+msgid "Save changes to the following scene(s) before reloading?"
+msgstr "هل تريد حفظ التغييرات في المشاهد التالية قبل الإعادة؟"
+
msgid "Save changes to the following scene(s) before quitting?"
msgstr "هل تريد حفظ التغييرات للمشاهد التالية قبل الخروج؟"
@@ -2861,6 +3123,9 @@ msgstr "إخلاء المشاهد الحالية"
msgid "There is no defined scene to run."
msgstr "ليس هناك مشهد محدد ليتم تشغيله."
+msgid "%s - Godot Engine"
+msgstr "%s - محرك جَوْدَتْ"
+
msgid ""
"No main scene has ever been defined, select one?\n"
"You can change it later in \"Project Settings\" under the 'application' "
@@ -3358,9 +3623,15 @@ msgstr ""
msgid "Quick Load"
msgstr "تحميل سريع"
+msgid "Inspect"
+msgstr "الفحص"
+
msgid "Make Unique"
msgstr "اجعلْه فريدًا"
+msgid "Make Unique (Recursive)"
+msgstr "اجعلْه فريدا (متكرر)"
+
msgid "Convert to %s"
msgstr "حوّلْ إلى %s"
@@ -3376,6 +3647,9 @@ msgstr "فتح الكود البرمجي"
msgid "New Shader"
msgstr "تمويه جديد"
+msgid "Remote Debug"
+msgstr "التنقيح البعيد"
+
msgid ""
"No runnable export preset found for this platform.\n"
"Please add a runnable preset in the Export menu or define an existing preset "
@@ -3385,12 +3659,24 @@ msgstr ""
"من فضلك أضفْ إعداد تصدير في قائمة التصدير أو عرف إعداد تصدير موجود كقابل "
"للتشغيل(عامل)."
+msgid "Project Run"
+msgstr "تشغيل المشروع"
+
msgid "Write your logic in the _run() method."
msgstr "أكتب منطقك في الطريقة ()run_."
msgid "There is an edited scene already."
msgstr "يوجد مشهد معدل عليه بالفعل."
+msgid "Undo: %s"
+msgstr "تراجع: %s"
+
+msgid "Redo: %s"
+msgstr "إلغاء التراجع: %s"
+
+msgid "Edit Shortcut"
+msgstr "تعديل الاختصارات"
+
msgid "Common"
msgstr "شائع"
@@ -3412,6 +3698,9 @@ msgstr "الاختصارات"
msgid "Binding"
msgstr "الربط"
+msgid "or"
+msgstr "أو"
+
msgid "All Devices"
msgstr "جميع الأجهزة"
@@ -3478,6 +3767,9 @@ msgstr "نمودج تصحيح الأخطاء غير موجود."
msgid "Custom release template not found."
msgstr "قالب الإصدار المخصص ليس موجود."
+msgid "Prepare Template"
+msgstr "تجهيز القالب"
+
msgid "The given export path doesn't exist."
msgstr "مسار التصدير المُدخَل غير موجود."
@@ -3692,6 +3984,9 @@ msgstr "الموارد المُعدّة للتصدير:"
msgid "Delete preset '%s'?"
msgstr "حذف المُعد مُسبقاً '%s'؟"
+msgid "%s Export"
+msgstr "تصدير %s"
+
msgid "Release"
msgstr "الإصدار"
@@ -3732,6 +4027,9 @@ msgstr "تصدير المشاهد المُختارة (وتبعاتها)"
msgid "Export selected resources (and dependencies)"
msgstr "تصدير الموارد المُختارة (وتبعياتها)"
+msgid "Export as dedicated server"
+msgstr "تصدير بنوع خادوم متخصص"
+
msgid "Export Mode:"
msgstr "وضع التصدير:"
@@ -3761,6 +4059,9 @@ msgstr "مُخصص (مفصول بفاصلة):"
msgid "Feature List:"
msgstr "قائمة المزايا:"
+msgid "Encryption"
+msgstr "التشفير"
+
msgid ""
"Filters to include files/folders\n"
"(comma-separated, e.g: *.tscn, *.tres, scenes/*)"
@@ -3775,6 +4076,9 @@ msgstr ""
"المصافي لاستثناء الملفات/المُجلدات من المشروع\n"
"(مفصولةً بفاصلة، مثلاً: *.json, *.txt, docs/*)"
+msgid "More Info..."
+msgstr "معلومات أكثر..."
+
msgid "Export Project..."
msgstr "تصدير المشروع..."
@@ -3790,18 +4094,33 @@ msgstr "تصدير الكُل..."
msgid "ZIP File"
msgstr "الملف المضغوط ZIP File"
+msgid "Godot Project Pack"
+msgstr "حزمة مشروع جوْدَتْ"
+
msgid "Export templates for this platform are missing:"
msgstr "قوالب التصدير لهذه المنصة مفقودة:"
+msgid "Project Export"
+msgstr "تصدير المشروع"
+
msgid "Manage Export Templates"
msgstr "إدارة قوالب التصدير"
msgid "Export With Debug"
msgstr "التصدير مع مُنقح الأخطاء"
+msgid "Configure FBX Importer"
+msgstr "تهيئة مُستورِد FBX"
+
+msgid "Click this link to download FBX2glTF"
+msgstr "اضغط هذا الرابط لتنزيل FBX2glTF"
+
msgid "Browse"
msgstr "تصفح"
+msgid "Confirm Path"
+msgstr "تأكيد المسار"
+
msgid "Favorites"
msgstr "المفضلات"
@@ -3861,15 +4180,33 @@ msgstr "تعيين كمشهد أساسي"
msgid "Open Scenes"
msgstr "فتح المَشاهِد"
+msgid "Instantiate"
+msgstr "التنسيخ"
+
msgid "Edit Dependencies..."
msgstr "تعديل التبعيات..."
msgid "View Owners..."
msgstr "أظهر المُلاك..."
+msgid "Folder..."
+msgstr "المجلد..."
+
+msgid "Scene..."
+msgstr "المشهد..."
+
+msgid "Script..."
+msgstr "النص البرمجي..."
+
+msgid "Resource..."
+msgstr "المصدر..."
+
msgid "TextFile..."
msgstr "ملف نصي..."
+msgid "Expand Folder"
+msgstr "توسيع المجلد"
+
msgid "Add to Favorites"
msgstr "إضافة إلى المفضلات"
@@ -4210,6 +4547,9 @@ msgstr ""
"المشروع سيشتغل بعدد إطارات FPS ثابت والمُخرجات البصرية والصوتية سوف تُسجّل في "
"ملف مرئي (فِديو)."
+msgid "Show notifications."
+msgstr "إظهار الإشعارات."
+
msgid "Toggle Visible"
msgstr "تشغيل/إطفاء الوضوحية"
@@ -4629,6 +4969,9 @@ msgstr "إزالة إعداد مورد إعادة تعيين الخريطة"
msgid "Removed"
msgstr "قد حُذف"
+msgid "%s cannot be found."
+msgstr "%s غير موجود."
+
msgid "Translations"
msgstr "الترجمات"
@@ -4650,6 +4993,12 @@ msgstr "محلي"
msgid "Files with translation strings:"
msgstr "الملفات ذات سلاسل الترجمة:"
+msgid "Set %s on %d nodes"
+msgstr "اجعل %s في %d العقد"
+
+msgid "%s (%d Selected)"
+msgstr "%s (%d المحدد)"
+
msgid "Select a single node to edit its signals and groups."
msgstr "حدد عقدة منفردة لكي تُعدل إشاراتها ومجموعاتها."
@@ -4896,60 +5245,166 @@ msgstr "إضافة عُقدة..."
msgid "Enable Filtering"
msgstr "تفعيل التصفية"
+msgid "Library Name:"
+msgstr "اسم المكتبة:"
+
msgid "Animation name can't be empty."
msgstr "اسم التحريك لا يمكن أن يكون فارغا."
msgid "Animation name contains invalid characters: '/', ':', ',' or '['."
msgstr "اسم التحريك يحوي حروفا لا تصلح: '/', ':', ',', '['."
+msgid "Animation with the same name already exists."
+msgstr "التحريك بهذا الاسم موجود سابقا."
+
msgid "Enter a library name."
msgstr "أدخل اسم المكتبة."
msgid "Library name contains invalid characters: '/', ':', ',' or '['."
msgstr "اسم المكتبة يحوي حروفا لا تصلح: '/', ':', ',' or '['."
+msgid "Library with the same name already exists."
+msgstr "المكتبة بهذا الاسم موجودة سابقا."
+
+msgid "Animation name is valid."
+msgstr "اسم التحريك صالح."
+
+msgid "Global library will be created."
+msgstr "سوف تُنشأ مكتبة عامة."
+
msgid "Library name is valid."
msgstr "اسم المكتبة صالح."
+msgid "Add Animation to Library: %s"
+msgstr "إضافة التحريك إلى المكتبة: %s"
+
+msgid "Add Animation Library: %s"
+msgstr "إضافة مكتبة تحريك: %s"
+
msgid "Load Animation"
msgstr "تحميل الرسم المتحرك"
msgid ""
+"This animation library can't be saved because it does not belong to the "
+"edited scene. Make it unique first."
+msgstr ""
+"مكتبة التحريك هذه لا يُمكن حفظها؛ لأنها لا تنتمي إلى المشهد المُعدل. اجعلْها "
+"فريدة أولا."
+
+msgid ""
"This animation library can't be saved because it was imported from another "
"file. Make it unique first."
msgstr ""
"مكتبة التحريك هذه لا يمكن حفظها؛ لأنها قد جُلبتْ من ملف آخر. اجعلها فريدةً أولا."
+msgid "Save Library"
+msgstr "حفظ المكتبة"
+
+msgid "Make Animation Library Unique: %s"
+msgstr "اجعلْ مكتبة التحريك فريدة: %s"
+
+msgid ""
+"This animation can't be saved because it does not belong to the edited "
+"scene. Make it unique first."
+msgstr ""
+"هذا التحريك لا يُمكن حفظه؛ لأنه لا يمنتمي إلى المشهد المعدل. اجعلْه فريدا أولا."
+
msgid ""
"This animation can't be saved because it was imported from another file. "
"Make it unique first."
msgstr ""
"مكتبة التحريك هذه لا يمكن حفظها؛ لأنها قد جُلبتْ من ملف آخر. اجعلها فريدةً أولا."
+msgid "Save Animation"
+msgstr "حفظ التحريك"
+
+msgid "Make Animation Unique: %s"
+msgstr "اجعل التحريك فريدا: %s"
+
msgid "Invalid AnimationLibrary file."
msgstr "ملف مكتبة-التحريك لا يصلح."
+msgid "This library is already added to the player."
+msgstr "هذه المكتبة قد أُضيفتْ إلى المُشغّل من قبل."
+
msgid "Invalid Animation file."
msgstr "ملف تحريك لا يصلح."
+msgid "This animation is already added to the library."
+msgstr "هذا التحريك قد أُضيفَ إلى المكتبة من قبل."
+
+msgid "Load Animation into Library: %s"
+msgstr "تنزيل التحريك إلى المكتبة: %s"
+
msgid "Save Animation library to File: %s"
msgstr "حفظ مكتبة التحريك في الملف: %s"
msgid "Save Animation to File: %s"
msgstr "حفظ التحريك في الملف: %s"
+msgid "Rename Animation Library: %s"
+msgstr "تسمية مكتبة التحريك: %s"
+
+msgid "[Global]"
+msgstr "[عمومي]"
+
+msgid "Rename Animation: %s"
+msgstr "تسمية التحريك: %s"
+
msgid "Animation Name:"
msgstr "اسم التحريك:"
+msgid "No animation resource in clipboard!"
+msgstr "لا يوجد تحريك في الحافظة!"
+
msgid "Pasted Animation"
msgstr "تم لصق الرسوم المتحركة"
msgid "Open in Inspector"
msgstr "افتح في المُتصفح"
+msgid "Remove Animation Library: %s"
+msgstr "إزالة مكتبة التحريك: %s"
+
+msgid "Remove Animation from Library: %s"
+msgstr "إزالة التحريك من المكتبة: %s"
+
+msgid "[built-in]"
+msgstr "[مُدمج]"
+
+msgid "[foreign]"
+msgstr "[أجنبي]"
+
+msgid "[imported]"
+msgstr "[مُستورَد]"
+
+msgid "Add Animation to Library"
+msgstr "إضافة التحريك إلى المكتبة"
+
msgid "Load animation from file and add to library"
msgstr "حملْ التحريك من ملف وأضفْه إلى المكتبة"
+msgid "Paste Animation to Library from clipboard"
+msgstr "لصق التحريك إلى المكتبة من الحافظة"
+
+msgid "Save animation library to resource on disk"
+msgstr "حفظ مكتبة التحريك في المصدر على القرص"
+
+msgid "Remove animation library"
+msgstr "إزالة مكتبة التحريك"
+
+msgid "Copy animation to clipboard"
+msgstr "نسخ التحريك إلى الحافظة"
+
+msgid "Save animation to resource on disk"
+msgstr "حفظ التحريك في المصدر على القرص"
+
+msgid "Remove animation from Library"
+msgstr "إزالة التحريك من المكتبة"
+
+msgid "Edit Animation Libraries"
+msgstr "تعديل مكتبات التحريك"
+
msgid "Add Library"
msgstr "إضافة مكتبة"
@@ -4995,6 +5450,12 @@ msgstr "دمج التغيير التالي"
msgid "Change Blend Time"
msgstr "تغيير وقت الدمج"
+msgid "[Global] (create)"
+msgstr "(إنشاء) [عمومي]"
+
+msgid "Duplicated Animation Name:"
+msgstr "أسماء التحريك المتكرر:"
+
msgid "Play selected animation backwards from current pos. (A)"
msgstr "تشغيل الرسم المتحرك المختار بشكل عكسي من الموقع الحالي. (زر A)"
@@ -5022,6 +5483,9 @@ msgstr "أدوات التحريك"
msgid "Animation"
msgstr "التحريك"
+msgid "Manage Animations..."
+msgstr "إدارة التحريكات..."
+
msgid "Edit Transitions..."
msgstr "تحرير الانتقالات..."
@@ -5115,6 +5579,17 @@ msgstr "العُقدة قد حُذفتْ"
msgid "Transition Removed"
msgstr "تمت إزالة الانتقال"
+msgid ""
+"Select and move nodes.\n"
+"RMB: Add node at position clicked.\n"
+"Shift+LMB+Drag: Connects the selected node with another node or creates a "
+"new node if you select an area without nodes."
+msgstr ""
+"اخترْ العقد وانقلْها.\n"
+"الزر-الأيمن: يضيف عقدة عند الموضع المنقور عليه.\n"
+"المناوِب(shift) + الزر-الأيسر + السحب: يصل العقدة المختارة بالأخرى أو يُنشئ "
+"عقدة جديدة إذا كان المكان المختار ليس فيه عُقد."
+
msgid "Create new nodes."
msgstr "إنشاء عُقد جديدة."
@@ -5133,6 +5608,12 @@ msgstr "وضع التشغيل:"
msgid "Delete Selected"
msgstr "حذف المُختار"
+msgid "Delete All"
+msgstr "حذف الكل"
+
+msgid "Root"
+msgstr "الجذر"
+
msgid "AnimationTree"
msgstr "شجرة التحريك"
@@ -5205,6 +5686,9 @@ msgstr "فشل في تجزئة SHA-256"
msgid "Asset Download Error:"
msgstr "خطأ في تنزيل المُلحق:"
+msgid "Ready to install!"
+msgstr "جاهز للتركيب!"
+
msgid "Downloading (%s / %s)..."
msgstr "جاري تنزيل (%s / %s)..."
@@ -5308,6 +5792,12 @@ msgstr "ملف أصول مضغوط"
msgid "Audio Preview Play/Pause"
msgstr "معاينة الصوت شغّل/أوقف"
+msgid "Bone Picker:"
+msgstr "ملقاط العظم:"
+
+msgid "Clear mappings in current group."
+msgstr "مسح التعيينات في هذه المجموعة."
+
msgid "Preview"
msgstr "عرض"
@@ -5401,9 +5891,18 @@ msgstr "أضفْ عُقدة هنا"
msgid "Instantiate Scene Here"
msgstr "تنسيخ مشهد هنا"
+msgid "Paste Node(s) Here"
+msgstr "لصق العقد هنا"
+
msgid "Move Node(s) Here"
msgstr "نقل العُقد هنا"
+msgid "Moving:"
+msgstr "النقل:"
+
+msgid "Rotating:"
+msgstr "الدوران:"
+
msgid "Scaling:"
msgstr "تحجيم:"
@@ -5440,6 +5939,9 @@ msgstr "لصق الوضع"
msgid "Clear Guides"
msgstr "مسح الموجهات"
+msgid "Create Custom Bone2D(s) from Node(s)"
+msgstr "إنشاء عظم-ثنائي مخصص من العقد"
+
msgid "Zoom to 3.125%"
msgstr "التكبير حتى 3.125%"
@@ -5487,8 +5989,8 @@ msgstr "V: تعيين نقطة المحور للوحدة المحددة."
msgid "Alt+RMB: Show list of all nodes at position clicked, including locked."
msgstr ""
-"Alt + زر-الفأرة-الأيمن: أظهر قائمة لكل الوحدات في المنطقة المضغوطة، متضمنة "
-"المقفلة منها."
+"البديل(Alt) + الزر-الأيمن: أظهرْ قائمة العقد في الموضع المنقور عليه، بما فيها "
+"العقد المقفولة."
msgid "RMB: Add node at position clicked."
msgstr "زر-الفأرة-الأيمن: ضف العقد عند موقع الضغط."
@@ -5606,9 +6108,18 @@ msgstr "إظهار العظام"
msgid "View"
msgstr "الرؤية"
+msgid "Show"
+msgstr "العرض"
+
+msgid "Show When Snapping"
+msgstr "العرض عند المحاذاة"
+
msgid "Hide"
msgstr "اخفاء"
+msgid "Toggle Grid"
+msgstr "تبديل الشبكة"
+
msgid "Grid"
msgstr "شبكة"
@@ -5689,6 +6200,12 @@ msgstr "قسم خطوة الشبكة ب 2"
msgid "Adding %s..."
msgstr "يتم إضافة %s..."
+msgid "Drag and drop to add as child of current scene's root node."
+msgstr "اسحبْ وألقِ؛ لإضافته فرعا للعقدة الجذرية للمشهد الحالي."
+
+msgid "Hold Ctrl when dropping to add as child of selected node."
+msgstr "علّقْ على زر التحكم(ctrl) عند الإلقاء؛ لإضافته فرعا للعقدة المختارة."
+
msgid "Cannot instantiate multiple nodes without root."
msgstr "لا يمكن تنسيخ عُقد عديدة بدون أصل تقوم عليه."
diff --git a/editor/translations/editor/de.po b/editor/translations/editor/de.po
index 7787d9ccd3..e3d7160fd4 100644
--- a/editor/translations/editor/de.po
+++ b/editor/translations/editor/de.po
@@ -106,8 +106,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-24 13:53+0000\n"
-"Last-Translator: Least Significant Bite <leastsignificantbite@proton.me>\n"
+"PO-Revision-Date: 2023-07-01 13:07+0000\n"
+"Last-Translator: ‎ <artism90@googlemail.com>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
"Language: de\n"
@@ -115,7 +115,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Unset"
msgstr "Nicht gesetzt"
@@ -2599,6 +2599,11 @@ msgstr "Ressourcen importieren des Typs: %s"
msgid "No return value."
msgstr "Kein Rückgabewert."
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr ""
+"Dieser Wert ist eine Ganzzahl, zusammengesetzt als Bitmaske der folgenden "
+"Flags."
+
msgid "Deprecated"
msgstr "Veraltet"
@@ -4087,7 +4092,7 @@ msgstr "Filtereinstellungen"
msgid "The editor must be restarted for changes to take effect."
msgstr ""
-"Damit die Änderungen Wirkung zeigen muss der Editor neu gestartet werden."
+"Damit die Änderungen Wirkung zeigen, muss der Editor neu gestartet werden."
msgid "Shortcuts"
msgstr "Tastenkürzel"
@@ -4155,6 +4160,12 @@ msgstr "Joystick 4 hoch"
msgid "Joystick 4 Down"
msgstr "Joystick 4 runter"
+msgid "or"
+msgstr "oder"
+
+msgid "Unicode"
+msgstr "Unicode"
+
msgid "Joypad Axis %d %s (%s)"
msgstr "Joypad Achse %d %s (%s)"
@@ -6953,8 +6964,8 @@ msgid ""
"feature."
msgstr ""
"Projektkamera überbrücken\n"
-"Es wird zur Zeit keine Projektinstanz ausgeführt. Um diese Funktion zu "
-"nutzen muss ein Projekt durch den Editor gestartet werden."
+"Es wird zurzeit keine Projektinstanz ausgeführt. Um diese Funktion zu "
+"nutzen, muss ein Projekt im Editor gestartet werden."
msgid "Lock Selected"
msgstr "Sperren ausgewählt"
@@ -7314,13 +7325,13 @@ msgid "Fill"
msgstr "Füllen"
msgid "Shrink Begin"
-msgstr "Anfang verkleinern"
+msgstr "Zum Anfang verkleinern"
msgid "Shrink Center"
-msgstr "Mitte verkleinern"
+msgstr "Zur Mitte verkleinern"
msgid "Shrink End"
-msgstr "Ende verkleinern"
+msgstr "Zum Ende verkleinern"
msgid "Custom"
msgstr "Eigenes"
@@ -8303,6 +8314,9 @@ msgstr "Größe: %s (%.1fMP)\n"
msgid "Objects: %d\n"
msgstr "Objekte: %d\n"
+msgid "Primitives: %d\n"
+msgstr "Primitiven: %d\n"
+
msgid "Draw Calls: %d"
msgstr "Zeichenaufrufe: %d"
@@ -10653,6 +10667,13 @@ msgstr "Streuung:"
msgid "Tiles"
msgstr "Kacheln"
+msgid ""
+"This TileMap's TileSet has no source configured. Go to the TileSet bottom "
+"tab to add one."
+msgstr ""
+"Für das TileSet dieses TileMaps wurde keine Quelle konfiguriert. Im unteren "
+"Reiter des TileSets kann eine hinzugefügt werden."
+
msgid "Sort sources"
msgstr "Quellen sortieren"
@@ -10729,6 +10750,14 @@ msgstr "Sichtbarkeit des Gitters umschalten."
msgid "Automatically Replace Tiles with Proxies"
msgstr "Automatisch Kacheln mit Stellvertretern ersetzen"
+msgid ""
+"The edited TileMap node has no TileSet resource.\n"
+"Create or load a TileSet resource in the Tile Set property in the inspector."
+msgstr ""
+"Das bearbeitete TileMap-Node hat keine zugewiesene TileSet-Ressource.\n"
+"Unter der TileSet-Einstellung im Inspektor kann eine TileSet-Ressource "
+"erstellt oder geladen werden."
+
msgid "Remove Tile Proxies"
msgstr "Kachel-Stellvertreter entfernen"
@@ -10946,6 +10975,16 @@ msgstr "Werkzeug zum Zusammenführen von Atlanten öffnen"
msgid "Manage Tile Proxies"
msgstr "Kachel-Stellvertreter verwalten"
+msgid ""
+"No TileSet source selected. Select or create a TileSet source.\n"
+"You can create a new source by using the Add button on the left or by "
+"dropping a tileset texture onto the source list."
+msgstr ""
+"Keine TileSet-Quelle ausgewählt. Bitte auswählen oder erstellen.\n"
+"Eine neue Quelle kann erstellt werden indem der Hinzufügen-Knopf links "
+"betätigt wird oder indem eine TileSet-Textur auf die Quellliste gezogen und "
+"fallengelassen wird."
+
msgid "Add new patterns in the TileMap editing mode."
msgstr "Neue Muster im TileMap-Bearbeitungsmodus hinzufügen."
@@ -12539,7 +12578,7 @@ msgstr "Git"
msgid "The project uses features unsupported by the current build:"
msgstr ""
-"Dieses Projekt verwendet Funktionen die von dieser Godot-Version nicht "
+"Dieses Projekt verwendet Funktionen, die von dieser Godot-Version nicht "
"unterstützt werden:"
msgid "Error: Project is missing on the filesystem."
@@ -12694,7 +12733,7 @@ msgid ""
"Opening will upgrade or downgrade the project to Godot %s.\n"
"\n"
msgstr ""
-"Achtung: Diese Projekt wurde mit Godot %s erstellt.\n"
+"Achtung: Dieses Projekt wurde mit Godot %s erstellt.\n"
"Öffnen des Projekts wird es zu Godot %s auf- bzw abstufen.\n"
"\n"
@@ -12751,7 +12790,7 @@ msgid "Remove %d projects from the list?"
msgstr "%d Projekte aus Liste entfernen?"
msgid "Remove this project from the list?"
-msgstr "Dieses Projekt von Liste entfernen?"
+msgstr "Dieses Projekt von der Liste entfernen?"
msgid ""
"Remove all missing projects from the list?\n"
@@ -12789,7 +12828,7 @@ msgid ""
msgstr ""
"Diese Suchmaske filtert Projekte nach ihrem Namen oder der letzten "
"Komponente ihres Pfadnamens.\n"
-"Um nach dem kompletten Pfad zu filtern muss mindestens ein ‚/‘-Zeichen in "
+"Um nach dem kompletten Pfad zu filtern, muss mindestens ein ‚/‘-Zeichen in "
"der Suchanfrage vorhanden sein."
msgid "Loading, please wait..."
@@ -13088,6 +13127,9 @@ msgstr "Dateiname ungültig."
msgid "File already exists."
msgstr "Datei existiert bereits."
+msgid "Root node valid."
+msgstr "Wurzel-Node gültig."
+
msgid "Invalid root node name."
msgstr "Ungültiger Name des Wurzel-Nodes."
@@ -13448,7 +13490,7 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
-"Falls ausgewählt wird das Panel für den Fern-Szenenbaum jedes mal beim "
+"Falls ausgewählt, wird das Panel für den Fern-Szenenbaum jedes Mal beim "
"Aktualisieren das Projekt zum Ruckeln bringen.\n"
"Für bessere Geschwindigkeit sollte diese Option auf Lokaler Szenenbaum "
"gestellt werden."
@@ -14058,8 +14100,8 @@ msgstr ""
msgid "A NavigationMesh resource must be set or created for this node to work."
msgstr ""
-"Damit dieser Node funktionieren kann, muss eine NavigationMesh Ressource "
-"erzeugt oder gesetzt werden."
+"Damit dieser Node funktionieren kann, muss eine NavigationMesh-Ressource "
+"gesetzt oder neu erzeugt werden."
msgid ""
"Cannot generate navigation mesh because it does not belong to the edited "
@@ -14297,11 +14339,25 @@ msgid "Could not execute on device."
msgstr "Ließ sich nicht auf Gerät ausführen."
msgid ""
+"Exporting to Android is currently not supported in Godot 4 when using C#/."
+"NET. Use Godot 3 to target Android with C#/Mono instead."
+msgstr ""
+"Androidexport wird zur Zeit nicht von Godot 4 mit C#/.Net unterstützt. Um "
+"Android mit C#/Mono zu unterstützen muss zur Zeit Godot 3 verwendet werden."
+
+msgid ""
+"If this project does not use C#, use a non-C# editor build to export the "
+"project."
+msgstr ""
+"Sofern dieses Projekt kein C# verwendet, sollte ein Editor-Build ohne C#-"
+"Unterstützung verwendet werden, um das Projekt zu exportieren."
+
+msgid ""
"Android build template not installed in the project. Install it from the "
"Project menu."
msgstr ""
-"Es wurde keine Android-Buildvorlage für dieses Projekt installiert. Es kann "
-"im Projektmenü installiert werden."
+"Es wurde keine Android-Build-Vorlage für dieses Projekt installiert. Diese "
+"kann im Projektmenü festgelegt werden."
msgid ""
"Either Debug Keystore, Debug User AND Debug Password settings must be "
@@ -14554,6 +14610,13 @@ msgstr ""
".ipa können nur unter MacOS gebaut werden. Das Xcode-Projekt wird verlassen "
"ohne das Paket zu bauen."
+msgid ""
+"Exporting to iOS is currently not supported in Godot 4 when using C#/.NET. "
+"Use Godot 3 to target iOS with C#/Mono instead."
+msgstr ""
+"IOS-Export wird zur Zeit nicht von Godot 4 mit C#/.Net unterstützt. Um IOS "
+"mit C#/Mono zu unterstützen muss zur Zeit Godot 3 verwendet werden."
+
msgid "Identifier is missing."
msgstr "Bezeichner fehlt."
@@ -14566,6 +14629,12 @@ msgstr "Skript-Export debuggen"
msgid "Could not open file \"%s\"."
msgstr "Datei „%s“ konnte nicht geöffnet werden."
+msgid "Debug Console Export"
+msgstr "Debug-Konsole exportieren"
+
+msgid "Could not create console wrapper."
+msgstr "Konsolen-Wrapper konnte nicht erstellt werden."
+
msgid "Failed to open executable file \"%s\"."
msgstr "Fehler beim Öffnen von ausführbarer Datei „%s“."
@@ -15037,6 +15106,14 @@ msgstr "Datei konnte nicht gelesen werden: „%s“."
msgid "PWA"
msgstr "PWA"
+msgid ""
+"Exporting to Web is currently not supported in Godot 4 when using C#/.NET. "
+"Use Godot 3 to target Web with C#/Mono instead."
+msgstr ""
+"Web-Export wird zur Zeit nicht von Godot 4 mit C#/.Net unterstützt. Um die "
+"Webplattform mit C#/Mono zu unterstützen muss zur Zeit Godot 3 verwendet "
+"werden."
+
msgid "Could not read HTML shell: \"%s\"."
msgstr "HTML-Shell konnte nicht gelesen werden „%s“."
@@ -15259,6 +15336,13 @@ msgstr ""
"Partikelspuren werden nur vom Forward+ oder Mobile Rendering-Backend "
"unterstützt."
+msgid ""
+"Particle sub-emitters are not available when using the GL Compatibility "
+"rendering backend."
+msgstr ""
+"Partikel-Subemitter sind nicht verfügbar wenn das GL-Kompatibilitäts-Render-"
+"Backend verwendet wird."
+
msgid "Node A and Node B must be PhysicsBody2Ds"
msgstr "Node A und Node B müssen PhysicsBody2D-Nodes sein"
@@ -15284,7 +15368,7 @@ msgstr ""
msgid ""
"An occluder polygon must be set (or drawn) for this occluder to take effect."
msgstr ""
-"Ein Occluder Polygon muss gesetzt oder gezeichnet werden, damit dieser "
+"Ein Occluder-Polygon muss gesetzt (oder gezeichnet) werden, damit dieser "
"Occluder funktioniert."
msgid "The occluder polygon for this occluder is empty. Please draw a polygon."
@@ -15607,6 +15691,13 @@ msgstr ""
"nicht für Spur-Rendern aktiviert."
msgid ""
+"Particle sub-emitters are only available when using the Forward+ or Mobile "
+"rendering backends."
+msgstr ""
+"Partikel-Subemitter werden nur vom Forward+ oder Mobile Rendering-Backend "
+"unterstützt."
+
+msgid ""
"The Bake Mask has no bits enabled, which means baking will not produce any "
"collision for this GPUParticlesCollisionSDF3D.\n"
"To resolve this, enable at least one bit in the Bake Mask property."
@@ -16268,6 +16359,17 @@ msgid "Invalid BMFont block type."
msgstr "Ungültiger BMFont-Blocktyp."
msgid ""
+"An incoming node's name clashes with %s already in the scene (presumably, "
+"from a more nested instance).\n"
+"The less nested node will be renamed. Please fix and re-save the scene."
+msgstr ""
+"Der Name eines eingehenden Nodes steht im Konflikt mit %s, welches bereits "
+"in der Szene enthalten ist (möglicherweise aus einer tiefer verschachtelten "
+"Instanz).\n"
+"Das weniger tief verschachtelte Node wird umbenannt. Bitte Szene reparieren "
+"und erneut speichern."
+
+msgid ""
"Shader keywords cannot be used as parameter names.\n"
"Choose another name."
msgstr ""
diff --git a/editor/translations/editor/es.po b/editor/translations/editor/es.po
index 6caa41672c..9f39af2a78 100644
--- a/editor/translations/editor/es.po
+++ b/editor/translations/editor/es.po
@@ -106,13 +106,16 @@
# Pedro Zebenzui Ortega Diaz <pipo.tf@gmail.com>, 2023.
# Santiago Valencia <santv05082011@gmail.com>, 2023.
# Ghislain <ghyslainnen@gmail.com>, 2023.
+# Alvaro Tejada <santi_evil@yahoo.com>, 2023.
+# Braulio León Madrid Escobar <brauliomadrid.developer@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-23 12:52+0000\n"
-"Last-Translator: Ghislain <ghyslainnen@gmail.com>\n"
+"PO-Revision-Date: 2023-07-05 13:48+0000\n"
+"Last-Translator: Braulio León Madrid Escobar <brauliomadrid.developer@gmail."
+"com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
"Language: es\n"
@@ -120,7 +123,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Unset"
msgstr "Desactivar"
@@ -1151,6 +1154,10 @@ msgid "Select Transition and Easing"
msgstr "Seleccione Transición y Easing"
msgctxt "Transition Type"
+msgid "Linear"
+msgstr "Lineal"
+
+msgctxt "Transition Type"
msgid "Sine"
msgstr "Seno"
@@ -1179,15 +1186,57 @@ msgid "Cubic"
msgstr "Cúbica"
msgctxt "Transition Type"
+msgid "Circ"
+msgstr "Circular"
+
+msgctxt "Transition Type"
msgid "Bounce"
msgstr "Rebote"
msgctxt "Transition Type"
+msgid "Back"
+msgstr "Regreso"
+
+msgctxt "Transition Type"
msgid "Spring"
msgstr "Resorte"
+msgctxt "Ease Type"
+msgid "In"
+msgstr "Entrada"
+
+msgctxt "Ease Type"
+msgid "Out"
+msgstr "Salida"
+
+msgctxt "Ease Type"
+msgid "InOut"
+msgstr "EntradaSalida"
+
+msgctxt "Ease Type"
+msgid "OutIn"
+msgstr "SalidaEntrada"
+
+msgid "Transition Type:"
+msgstr "Tipo de Transición:"
+
+msgid "Ease Type:"
+msgstr "Tipo de Interpolación:"
+
+msgid "FPS:"
+msgstr "FPS:"
+
msgid "Animation Baker"
-msgstr "Baker de Animación"
+msgstr "Bakeador de Animaciones"
+
+msgid "3D Pos/Rot/Scl Track:"
+msgstr "Pista de Pos/Rot/Escala 3D:"
+
+msgid "Blendshape Track:"
+msgstr "Pista de Forma Combinada:"
+
+msgid "Value Track:"
+msgstr "Pista de Escala 3D:"
msgid "Select Tracks to Copy"
msgstr "Selecciona las Pistas a Copiar"
@@ -1478,6 +1527,27 @@ msgstr ""
msgid "Toggle Visibility"
msgstr "Cambiar Visibilidad"
+msgid "Updating assets on target device:"
+msgstr "Actualizando complementos en el dispositivo de destino:"
+
+msgid "Syncing headers"
+msgstr "Sincronizando cabeceras"
+
+msgid "Getting remote file system"
+msgstr "Obteniendo sistema de ficheros remoto"
+
+msgid "Decompressing remote file system"
+msgstr "Descomprimiendo sistema de ficheros remoto"
+
+msgid "Scanning for local changes"
+msgstr "Escaneando cambios locales"
+
+msgid "Sending list of changed files:"
+msgstr "Enviando lista de ficheros modificados:"
+
+msgid "Sending file:"
+msgstr "Enviando archivo:"
+
msgid "ms"
msgstr "ms"
@@ -1738,6 +1808,11 @@ msgstr "Editor de Dependencias"
msgid "Search Replacement Resource:"
msgstr "Buscar Recurso de Reemplazo:"
+msgid "Open Scene"
+msgid_plural "Open Scenes"
+msgstr[0] "Abrir Escena"
+msgstr[1] "Abrir Escenas"
+
msgid "Open"
msgstr "Abrir"
@@ -1809,9 +1884,32 @@ msgstr "Propietario"
msgid "Resources Without Explicit Ownership:"
msgstr "Recursos Sin Propietario Explícito:"
+msgid "Folder name cannot be empty."
+msgstr "El nombre de la carpeta no puede estar vacío."
+
+msgid "Folder name contains invalid characters."
+msgstr "El nombre de la carpeta contiene caracteres inválidos."
+
+msgid "File with that name already exists."
+msgstr "Ya existe un fichero con ese nombre."
+
+msgid "Folder with that name already exists."
+msgstr "Ya existe una carpeta con ese nombre."
+
+msgid "Using slashes in folder names will create subfolders recursively."
+msgstr ""
+"Al usar la barra invertida en el nombre de las carpetas se crearán "
+"subcarpetas de forma recursiva."
+
+msgid "Folder name is valid."
+msgstr "El nombre de la carpeta es válido."
+
msgid "Could not create folder."
msgstr "No se pudo crear la carpeta."
+msgid "Create new folder in %s:"
+msgstr "Crear nueva carpeta en %s:"
+
msgid "Create Folder"
msgstr "Crear Carpeta"
@@ -2506,8 +2604,13 @@ msgstr "Importar recursos del tipo: %s"
msgid "No return value."
msgstr "No retorna ningún valor."
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr ""
+"Este valor es un entero compuesto como una máscara de bits de los siguientes "
+"indicadores."
+
msgid "Deprecated"
-msgstr "Obsoleta"
+msgstr "Obsoleto"
msgid "Experimental"
msgstr "Experimental"
@@ -2763,6 +2866,11 @@ msgstr "Fijar un valor obliga a guardarlo aunque sea igual al predeterminado."
msgid "Open Documentation"
msgstr "Abrir Documentación"
+msgid "(%d change)"
+msgid_plural "(%d changes)"
+msgstr[0] "(%d cambio)"
+msgstr[1] "(%d cambios)"
+
msgid "Add element to property array with prefix %s."
msgstr "Añadir elemento a la matriz de propiedades con el prefijo %s."
@@ -3319,6 +3427,9 @@ msgstr "Limpiar escenas recientes"
msgid "There is no defined scene to run."
msgstr "No hay escena definida para ejecutar."
+msgid "%s - Godot Engine"
+msgstr "%s - Godot Engine"
+
msgid ""
"No main scene has ever been defined, select one?\n"
"You can change it later in \"Project Settings\" under the 'application' "
@@ -3465,7 +3576,7 @@ msgid "Export As..."
msgstr "Exportar Como..."
msgid "MeshLibrary..."
-msgstr "MeshLibrary..."
+msgstr "Libreria de Mallas..."
msgid "Close Scene"
msgstr "Cerrar Escena"
@@ -3562,6 +3673,14 @@ msgstr "Preguntas & Respuestas"
msgid "Report a Bug"
msgstr "Reportar un Bug"
+msgid "Copy System Info"
+msgstr "Copiar Información del Sistema"
+
+msgid "Copies the system info as a single-line text into the clipboard."
+msgstr ""
+"Copia la información del sistema como una única linea de texto en el "
+"portapapeles."
+
msgid "Suggest a Feature"
msgstr "Sugerir una característica"
@@ -3881,6 +4000,9 @@ msgstr "Cadena Localizable (tamaño %d)"
msgid "Add Translation"
msgstr "Añadir Traducción"
+msgid "Lock/Unlock Component Ratio"
+msgstr "Bloquea/Desbloquea Ratio del Componente"
+
msgid ""
"The selected resource (%s) does not match any type expected for this "
"property (%s)."
@@ -3946,6 +4068,12 @@ msgstr ""
"No se pudo ejecutar el script del editor, ¿olvidaste sobrescribir el método "
"'_run'?"
+msgid "Undo: %s"
+msgstr "Deshacer: %s"
+
+msgid "Redo: %s"
+msgstr "Rehacer: %s"
+
msgid "Edit Built-in Action"
msgstr "Editar Acción Integrada"
@@ -4033,6 +4161,12 @@ msgstr "Joystick 4 Arriba"
msgid "Joystick 4 Down"
msgstr "Joystick 4 Abajo"
+msgid "or"
+msgstr "o"
+
+msgid "Unicode"
+msgstr "Unicode"
+
msgid "Joypad Axis %d %s (%s)"
msgstr "Eje del Joypad %d %s (%s)"
@@ -4152,10 +4286,10 @@ msgid "Uninstall these templates."
msgstr "Desinstalar estas plantillas."
msgid "There are no mirrors available."
-msgstr "No hay espejos disponibles."
+msgstr "No hay mirrors disponibles."
msgid "Retrieving the mirror list..."
-msgstr "Recuperar el listado de mirrors..."
+msgstr "Recuperar el listado de mirror..."
msgid "Starting the download..."
msgstr "Comenzando la descarga..."
@@ -4370,6 +4504,9 @@ msgstr "Recursos a exportar:"
msgid "Delete preset '%s'?"
msgstr "¿Eliminar preajuste '%s'?"
+msgid "(Inherited)"
+msgstr "(Heredado)"
+
msgid "%s Export"
msgstr "Exportar %s"
@@ -4622,6 +4759,15 @@ msgid "Unable to update dependencies:"
msgstr "No se han podido actualizar las dependencias:"
msgid ""
+"This filename begins with a dot rendering the file invisible to the editor.\n"
+"If you want to rename it anyway, use your operating system's file manager."
+msgstr ""
+"Este nombre de archivo comienza con un punto, lo que hace que el archivo sea "
+"invisible para el editor.\n"
+"Si deseas cambiarle el nombre de todos modos, utiliza el administrador de "
+"archivos de tu sistema operativo."
+
+msgid ""
"This file extension is not recognized by the editor.\n"
"If you want to rename it anyway, use your operating system's file manager.\n"
"After renaming to an unknown extension, the file won't be shown in the "
@@ -4636,6 +4782,19 @@ msgstr ""
msgid "A file or folder with this name already exists."
msgstr "Ya existe un archivo o carpeta con este nombre."
+msgid ""
+"The following files or folders conflict with items in the target location "
+"'%s':"
+msgstr ""
+"Los siguientes archivos o carpetas entran en conflicto con elementos en la "
+"ubicación de destino '%s':"
+
+msgid "Do you wish to overwrite them or rename the copied files?"
+msgstr "¿Deseas sobreescribir o renombrar los ficheros copiados?"
+
+msgid "Do you wish to overwrite them or rename the moved files?"
+msgstr "¿Deseas sobreescribir o renombrar los ficheros movidos?"
+
msgid "Duplicating file:"
msgstr "Duplicando archivo:"
@@ -4660,6 +4819,9 @@ msgstr "Editar Dependencias..."
msgid "View Owners..."
msgstr "Ver Propietarios..."
+msgid "Create New"
+msgstr "Crear Nuevo"
+
msgid "Folder..."
msgstr "Carpeta..."
@@ -4675,6 +4837,18 @@ msgstr "Recurso..."
msgid "TextFile..."
msgstr "Archivo de Texto..."
+msgid "Expand Folder"
+msgstr "Expandir Carpeta"
+
+msgid "Expand Hierarchy"
+msgstr "Expandir Jerarquía"
+
+msgid "Collapse Hierarchy"
+msgstr "Colapsar Jerarquía"
+
+msgid "Move/Duplicate To..."
+msgstr "Mover/Duplicar a..."
+
msgid "Add to Favorites"
msgstr "Agregar a Favoritos"
@@ -4760,6 +4934,9 @@ msgstr ""
msgid "Overwrite"
msgstr "Sobreescribir"
+msgid "Keep Both"
+msgstr "Mantener Ambos"
+
msgid "Create Script"
msgstr "Crear Script"
@@ -4857,6 +5034,9 @@ msgstr "No se ha podido crear la carpeta. Ya existe un archivo con ese nombre."
msgid "Choose a Directory"
msgstr "Selecciona un directorio"
+msgid "Copy File(s)"
+msgstr "Copiar Archivo(s)"
+
msgid "Network"
msgstr "Red"
@@ -5138,6 +5318,9 @@ msgstr ""
"El AnimationPlayer esta pineado.\n"
"Haz clic para despinear."
+msgid "\"%s\" is not a known filter."
+msgstr "\"%s\" no es un filtro conocido."
+
msgid "Invalid node name, the following characters are not allowed:"
msgstr ""
"El nombre del nodo no es correcto, las siguientes letras no están permitidas:"
@@ -5951,7 +6134,7 @@ msgid "Select and move points, create points with RMB."
msgstr "Seleccionar y mover puntos, crear puntos con clic derecho."
msgid "Enable snap and show grid."
-msgstr "Activar snap y mostrar cuadrícula."
+msgstr "Activar ajuste y mostrar cuadrícula."
msgid "Sync:"
msgstr "Sincronizar:"
@@ -6670,7 +6853,7 @@ msgid "Preview"
msgstr "Vista Previa"
msgid "Configure Snap"
-msgstr "Configurar Snap"
+msgstr "Configurar Ajuste"
msgid "Grid Offset:"
msgstr "Offset de Cuadrícula:"
@@ -6905,37 +7088,37 @@ msgid "Ruler Mode"
msgstr "Modo de Regla"
msgid "Toggle smart snapping."
-msgstr "Act./Desact. snap inteligente."
+msgstr "Act./Desact. Ajuste Inteligente."
msgid "Use Smart Snap"
-msgstr "Usar Snap Inteligente"
+msgstr "Usar Ajuste Inteligente"
msgid "Toggle grid snapping."
-msgstr "Act./Desact. snapping de cuadrícula."
+msgstr "Act./Desact. Ajuste de cuadrícula."
msgid "Use Grid Snap"
-msgstr "Usar Snap de Cuadrícula"
+msgstr "Usar Ajuste de Cuadrícula"
msgid "Snapping Options"
-msgstr "Opciones de Snapping"
+msgstr "Opciones de Ajuste"
msgid "Use Rotation Snap"
-msgstr "Usar Snap de Rotación"
+msgstr "Usar Ajuste de Rotación"
msgid "Use Scale Snap"
-msgstr "Usar Snap de Escala"
+msgstr "Usar Ajuste de Escala"
msgid "Snap Relative"
-msgstr "Snap Relativo"
+msgstr "Ajuste Relativo"
msgid "Use Pixel Snap"
-msgstr "Usar Snap de Píxeles"
+msgstr "Usar Ajuste de Píxeles"
msgid "Smart Snapping"
-msgstr "Snapping Inteligente"
+msgstr "Ajuste Inteligente"
msgid "Configure Snap..."
-msgstr "Configurar Snap..."
+msgstr "Configurar Ajuste..."
msgid "Snap to Parent"
msgstr "Ajustar al Padre"
@@ -7311,12 +7494,27 @@ msgstr "Crear Puntos de Emisión Desde el Nodo"
msgid "Load Curve Preset"
msgstr "Cargar Preset de Curva"
+msgid "Add Curve Point"
+msgstr "Añadir Punto de Curva"
+
msgid "Remove Curve Point"
msgstr "Eliminar Punto de Curva"
msgid "Modify Curve Point"
msgstr "Modificar Punto de Curva"
+msgid "Modify Curve Point's Tangents"
+msgstr "Modificar Tangentes de los Puntos de Curva"
+
+msgid "Modify Curve Point's Left Tangent"
+msgstr "Modificar Tangente Izquierda del Punto de Curva"
+
+msgid "Modify Curve Point's Right Tangent"
+msgstr "Modificar Tangente Derecha del Punto de Curva"
+
+msgid "Toggle Linear Curve Point's Tangent"
+msgstr "Act./Desact. Puntos de la Curva Lineal"
+
msgid "Hold Shift to edit tangents individually"
msgstr "Mantén Shift para editar las tangentes individualmente"
@@ -7330,7 +7528,7 @@ msgid "Smoothstep"
msgstr "Suavizado"
msgid "Toggle Grid Snap"
-msgstr "Cambiar Snap de Cuadrícula"
+msgstr "Act./Desact. Ajuste de Cuadrícula"
msgid "Debug with External Editor"
msgstr "Depurar con Editor Externo"
@@ -7401,6 +7599,16 @@ msgstr ""
"Cuando esta opción está activada, las mallas de navegación y los polígonos "
"serán visibles en el proyecto en ejecución."
+msgid "Visible Avoidance"
+msgstr "Evitar Visibilidad"
+
+msgid ""
+"When this option is enabled, avoidance objects shapes, radius and velocities "
+"will be visible in the running project."
+msgstr ""
+"Cuando esta opción está activada, las formas, radios y velocidades de los "
+"objetos de evasión serán visibles en el proyecto en ejecución."
+
msgid "Synchronize Scene Changes"
msgstr "Sincronizar Cambios de Escena"
@@ -7448,6 +7656,12 @@ msgid_plural "Run %d Instances"
msgstr[0] "Ejecutar %d Instancia"
msgstr[1] "Ejecutar %d Instancias"
+msgid "Size: %s"
+msgstr "Tamaño: %s"
+
+msgid "Type: %s"
+msgstr "Tipo: %s"
+
msgid "Overrides (%d)"
msgstr "Anulaciones (%d)"
@@ -7653,6 +7867,9 @@ msgstr "Degradado Editado"
msgid "Reverse/mirror gradient."
msgstr "Gradiente inverso/espejo."
+msgid "Move GradientTexture2D Fill Point"
+msgstr "Mover Punto de Relleno de GradientTexture2D"
+
msgid "Swap GradientTexture2D Fill Points"
msgstr "Intercambiar Puntos de Relleno de GradientTexture2D"
@@ -8006,6 +8223,12 @@ msgstr "Establecer posición inicial"
msgid "Set end_position"
msgstr "Establecer posición final"
+msgid "Set NavigationObstacle3D Vertices"
+msgstr "Establecer Vértices NavigationObstacle3D"
+
+msgid "Edit Vertices"
+msgstr "Editar Vértices"
+
msgid "Edit Poly"
msgstr "Editar Polígono"
@@ -8108,6 +8331,9 @@ msgstr "Tamaño: %s (%.1fMP)\n"
msgid "Objects: %d\n"
msgstr "Objetos: %d\n"
+msgid "Primitives: %d\n"
+msgstr "Primitivos: %d\n"
+
msgid "Draw Calls: %d"
msgstr "Llamadas de Dibujado: %d"
@@ -8413,7 +8639,25 @@ msgid "Use Local Space"
msgstr "Usar Espacio Local"
msgid "Use Snap"
-msgstr "Usar Snap"
+msgstr "Usar Ajuste"
+
+msgid ""
+"Toggle preview sunlight.\n"
+"If a DirectionalLight3D node is added to the scene, preview sunlight is "
+"disabled."
+msgstr ""
+"Cambiando a previsualización de la luz solar.\n"
+"Si un nodo DirectionalLight3D es añadido a la escena, la previsualización de "
+"la luz solar es deshabilitada."
+
+msgid ""
+"Toggle preview environment.\n"
+"If a WorldEnvironment node is added to the scene, preview environment is "
+"disabled."
+msgstr ""
+"Cambiando a previsualización del entorno.\n"
+"Si un nodo WorldEnvironment es añadido a la escena, la previsualización es "
+"deshabilitada."
msgid "Edit Sun and Environment settings."
msgstr "Editar Sol y Configuraciones del Entorno."
@@ -8518,7 +8762,7 @@ msgid "Snap Settings"
msgstr "Configuración de Ajuste"
msgid "Translate Snap:"
-msgstr "Ajuste de Traslación:"
+msgstr "Ajuste de Translado:"
msgid "Rotate Snap (deg.):"
msgstr "Ajuste de Rotación (grados):"
@@ -8583,8 +8827,19 @@ msgstr "Distancia Máxima de la Sombra"
msgid "Add Sun to Scene"
msgstr "Añadir un Sol a la Escena"
+msgid ""
+"Adds a DirectionalLight3D node matching the preview sun settings to the "
+"current scene.\n"
+"Hold Shift while clicking to also add the preview environment to the current "
+"scene."
+msgstr ""
+"Añade un nodo DirectionalLight3D con la configuración de luz correspondiente "
+"a la escena actual.\n"
+"Mantén Shift mientras haces clic para añadir también el entorno a la escena "
+"actual."
+
msgid "Preview Environment"
-msgstr "Previsualizar el Entorno"
+msgstr "Previsualizar Entorno"
msgid "Sky Color"
msgstr "Color del Cielo"
@@ -8614,6 +8869,16 @@ msgid "Add Environment to Scene"
msgstr "Añadir Entorno a la Escena"
msgid ""
+"Adds a WorldEnvironment node matching the preview environment settings to "
+"the current scene.\n"
+"Hold Shift while clicking to also add the preview sun to the current scene."
+msgstr ""
+"Añade un nodo WorldEnvironment con la configuración de entorno "
+"correspondiente a la escena actual.\n"
+"Mantén Shift mientras haces clic para añadir también la luz a la escena "
+"actual."
+
+msgid ""
"Can't determine a save path for the occluder.\n"
"Save your scene and try again."
msgstr ""
@@ -8853,7 +9118,7 @@ msgid "Snap"
msgstr "Ajuste"
msgid "Enable Snap"
-msgstr "Activar Snap"
+msgstr "Activar Ajuste"
msgid "Show Grid"
msgstr "Ver Cuadrícula"
@@ -8949,6 +9214,9 @@ msgstr "Guardar Archivo Como..."
msgid "Can't obtain the script for reloading."
msgstr "No se puede obtener el script para recargar."
+msgid "Reload only takes effect on tool scripts."
+msgstr "Recargar solo afecta a scripts de herramientas."
+
msgid "Can't obtain the script for running."
msgstr "No se puede obtener el script para ejecutarlo."
@@ -8976,6 +9244,9 @@ msgstr "Error al guardar"
msgid "Save Theme As..."
msgstr "Guardar Theme Como..."
+msgid "Unsaved file."
+msgstr "Fichero sin guardar."
+
msgid "%s Class Reference"
msgstr "%s Referencia de Clase"
@@ -9063,6 +9334,9 @@ msgstr "Ir a anterior documento editado."
msgid "Go to next edited document."
msgstr "Ir a siguiente documento editado."
+msgid "Make the script editor floating."
+msgstr "Hacer que el editor de scripts sea flotante."
+
msgid "Discard"
msgstr "Descartar"
@@ -9085,6 +9359,9 @@ msgstr "Estándar"
msgid "Plain Text"
msgstr "Texto Sin Formato"
+msgid "JSON"
+msgstr "JSON"
+
msgid "Connections to method:"
msgstr "Conexiones al método:"
@@ -9094,6 +9371,9 @@ msgstr "Fuente"
msgid "Target"
msgstr "Objetivo"
+msgid "Error at (%d, %d):"
+msgstr "Error en (%d, %d):"
+
msgid ""
"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
msgstr ""
@@ -9173,6 +9453,9 @@ msgstr "Desplegar Todas las Líneas"
msgid "Evaluate Selection"
msgstr "Evaluar Selección"
+msgid "Toggle Word Wrap"
+msgstr "Act./Desact. Ajuste de Línea"
+
msgid "Trim Trailing Whitespace"
msgstr "Eliminar Espacios Sobrantes al Final"
@@ -9248,12 +9531,22 @@ msgstr "Abrir Archivo en el Inspector"
msgid "Close File"
msgstr "Cerrar Archivo"
+msgid "Make the shader editor floating."
+msgstr "Hace flotante el editor de shaders."
+
msgid "No valid shader stages found."
msgstr "No se encontraron etapas de shader válidas."
msgid "Shader stage compiled without errors."
msgstr "Etapa de shader compilada sin errores."
+msgid ""
+"File structure for '%s' contains unrecoverable errors:\n"
+"\n"
+msgstr ""
+"Estructura de archivos para '%s' contiene errores irrecuperables:\n"
+"\n"
+
msgid "ShaderFile"
msgstr "ShaderFile"
@@ -9281,9 +9574,16 @@ msgstr "Establecer Transformación de Hueso"
msgid "Set Bone Rest"
msgstr "Establecer Pose de Descanso de los Huesos"
+msgid "Cannot create a physical skeleton for a Skeleton3D node with no bones."
+msgstr "No se puede crear un esqueleto sin huesos para un nodo Skeleton3D."
+
msgid "Create physical bones"
msgstr "Crear huesos físicos"
+msgid "Cannot export a SkeletonProfile for a Skeleton3D node with no bones."
+msgstr ""
+"No se puede exportar un SkeletonProfile para un nodo Skeleton3D sin huesos."
+
msgid "Export Skeleton Profile As..."
msgstr "Exportar Perfil de Esqueleto Como..."
@@ -9299,14 +9599,31 @@ msgstr "Restablecer Todas las Poses de Huesos"
msgid "Reset Selected Poses"
msgstr "Restablecer Poses Seleccionadas"
+msgid "Apply All Poses to Rests"
+msgstr "Aplicar todas las poses a los descansos"
+
+msgid "Apply Selected Poses to Rests"
+msgstr "Aplicar Poses Seleccionadas a los Descansos"
+
msgid "Create Physical Skeleton"
msgstr "Crear Esqueleto Físico"
msgid "Export Skeleton Profile"
msgstr "Exportar Perfil del Esqueleto"
+msgid ""
+"Edit Mode\n"
+"Show buttons on joints."
+msgstr ""
+"Modo Edición\n"
+"Mostrar botones en las uniones."
+
+msgid "Insert key of bone poses already exist track."
+msgstr ""
+"Insertar clave de poses de huesos en una pista que ya tiene poses existentes."
+
msgid "Insert key of all bone poses."
-msgstr "Insertar clave de todas las poses de los huesos."
+msgstr "Insertar clave de todas las poses de huesos."
msgid "Insert Key (All Bones)"
msgstr "Insertar Clave (Todos los Huesos)"
@@ -9444,6 +9761,9 @@ msgstr "Filtrar Animaciones"
msgid "Delete Animation"
msgstr "Eliminar Animación"
+msgid "This resource does not have any animations."
+msgstr "Este recurso no tiene animaciones."
+
msgid "Animation Frames:"
msgstr "Fotogramas de Animación:"
@@ -9480,15 +9800,72 @@ msgstr "Mover Fotograma a Derecha"
msgid "Select Frames"
msgstr "Seleccionar Fotogramas"
+msgid "Frame Order"
+msgstr "Orden de Fotogramas"
+
+msgid "As Selected"
+msgstr "Como Seleccionado"
+
+msgid "By Row"
+msgstr "Por Fila"
+
+msgid "Left to Right, Top to Bottom"
+msgstr "De Izquierda a Derecha, de Arriba a Abajo"
+
+msgid "Left to Right, Bottom to Top"
+msgstr "De Izquierda a Derecha, de Abajo a Arriba"
+
+msgid "Right to Left, Top to Bottom"
+msgstr "De Derecha a Izquierda, de Arriba a Abajo"
+
+msgid "Right to Left, Bottom to Top"
+msgstr "De Derecha a Izquierda, de Abajo a Arriba"
+
+msgid "By Column"
+msgstr "Por Columna"
+
+msgid "Top to Bottom, Left to Right"
+msgstr "De Arriba a Abajo, de Izquierda a Derecha"
+
+msgid "Top to Bottom, Right to Left"
+msgstr "De Arriba a Abajo, de Derecha a Izquierda"
+
+msgid "Bottom to Top, Left to Right"
+msgstr "De Abajo a Arriba, de Izquierda a Derecha"
+
+msgid "Bottom to Top, Right to Left"
+msgstr "De Abajo a Arriba, de Derecha a Izquierda"
+
+msgid "Select None"
+msgstr "No Seleccionar"
+
+msgid "Toggle Settings Panel"
+msgstr "Act./Desact. Panel de Ajustes"
+
+msgid "Horizontal"
+msgstr "Horizontal"
+
+msgid "Vertical"
+msgstr "Vertical"
+
msgid "Size"
msgstr "Tamaño"
+msgid "Separation"
+msgstr "Separación"
+
+msgid "Offset"
+msgstr "Desplazamiento"
+
msgid "Create Frames from Sprite Sheet"
msgstr "Crear Fotogramas a partir de un Sprite Sheet"
msgid "SpriteFrames"
msgstr "SpriteFrames"
+msgid "Warnings should be fixed to prevent errors."
+msgstr "Los avisos deberían arreglarse para prevenir errores."
+
msgid ""
"This shader has been modified on disk.\n"
"What action should be taken?"
@@ -10097,12 +10474,39 @@ msgstr "%s (ID: %d)"
msgid "Atlas Merging"
msgstr "Combinar Atlas"
+msgid "Merge (Keep original Atlases)"
+msgstr "Unir (Mantener Atlas originales)"
+
msgid "Merge"
msgstr "Combinar"
+msgid "Next Line After Column"
+msgstr "Siguiente Línea Después de la Columna"
+
msgid "Please select two atlases or more."
msgstr "Por favor, selecciona dos o más atlas."
+msgid ""
+"Source: %d\n"
+"Atlas coordinates: %s\n"
+"Alternative: 0"
+msgstr ""
+"Origen: %d\n"
+"Coordenadas del Atlas: %s\n"
+"Alternativa: 0"
+
+msgid ""
+"Source: %d\n"
+"Atlas coordinates: %s\n"
+"Alternative: %d"
+msgstr ""
+"Origen: %d\n"
+"Coordenadas del Atlas: %s\n"
+"Alternativa: %d"
+
+msgid "No atlas source with a valid texture selected."
+msgstr "Ninguna fuente de atlas seleccionada con texturas válidas."
+
msgid "Base Tiles"
msgstr "Tiles Base"
@@ -10154,6 +10558,12 @@ msgstr "Voltear Horizontalmente"
msgid "Flip Vertically"
msgstr "Voltear Verticalmente"
+msgid "Disable Snap"
+msgstr "Desactivar Ajuste"
+
+msgid "Half-Pixel Snap"
+msgstr "Ajuste de Medio Píxel"
+
msgid "Painting Tiles Property"
msgstr "Propiedad de Pintar Tiles"
@@ -10163,24 +10573,45 @@ msgstr "Pintando:"
msgid "Picker"
msgstr "Selector"
+msgid "No terrains"
+msgstr "Sin terrenos"
+
+msgid "No terrain"
+msgstr "Sin terreno"
+
msgid "Painting Terrain Set"
msgstr "Set de Pintura del Terreno"
msgid "Painting Terrain"
msgstr "Pintura del Terreno"
+msgid "No Texture Atlas Source (ID: %d)"
+msgstr "Sin Fuente de Textura de Atlas (ID: %d)"
+
+msgid "Scene Collection Source (ID: %d)"
+msgstr "Fuente de Colección de Escenas (ID: %d)"
+
+msgid "Unknown Type Source (ID: %d)"
+msgstr "Tipo desconocido de fuente (ID: %d)"
+
msgid "Add TileSet pattern"
msgstr "Añadir Patrón de TileSet"
msgid "Remove TileSet patterns"
msgstr "Eliminar Patrones de TileSet"
+msgid "Index: %d"
+msgstr "Índice: %d"
+
msgid "Tile with Invalid Scene"
msgstr "Tile con Escena Inválida"
msgid "Delete tiles"
msgstr "Eliminar tiles"
+msgid "Drawing Rect:"
+msgstr "Dibujando Rectángulo:"
+
msgid "Change selection"
msgstr "Cambiar selección"
@@ -10199,6 +10630,9 @@ msgstr "Selección"
msgid "Paint"
msgstr "Pintar"
+msgid "Shift: Draw line."
+msgstr "Shift: Dibujar linea."
+
msgid "Shift+Ctrl: Draw rectangle."
msgstr "Shift+Ctrl: Dibujar rectángulo."
@@ -10209,8 +10643,22 @@ msgstr "Línea"
msgid "Rect"
msgstr "Rectángulo"
+msgid "Bucket"
+msgstr "Balde"
+
+msgid "Alternatively hold Ctrl with other tools to pick tile."
+msgstr ""
+"Alternativamente, manten Ctrl pulsado con otras herramientas para "
+"seleccionar un tile."
+
+msgid "Eraser"
+msgstr "Borrador"
+
+msgid "Alternatively use RMB to erase tiles."
+msgstr "Alternativamente, usa el botón derecho del mouse para borrar tiles."
+
msgid "Contiguous"
-msgstr "Contiguo"
+msgstr "Contiguos"
msgid "Place Random Tile"
msgstr "Colocar Tile Aleatorio"
@@ -10227,6 +10675,13 @@ msgstr "Dispersión:"
msgid "Tiles"
msgstr "Tiles"
+msgid ""
+"This TileMap's TileSet has no source configured. Go to the TileSet bottom "
+"tab to add one."
+msgstr ""
+"El TileSet de este TileMap no tiene una fuente configurada. Ve a la pestaña "
+"inferior del TileSet para añadir una."
+
msgid "Sort sources"
msgstr "Ordenar recursos"
@@ -10303,6 +10758,13 @@ msgstr "Cambiar visibilidad de la cuadrícula."
msgid "Automatically Replace Tiles with Proxies"
msgstr "Reemplazar Automáticamente los Tiles con Proxies"
+msgid ""
+"The edited TileMap node has no TileSet resource.\n"
+"Create or load a TileSet resource in the Tile Set property in the inspector."
+msgstr ""
+"El nodo editado TileMap no tiene asignado un recurso del tipo TileSet.\n"
+"Crea o carga un recurso TileSet en la propiedad Tile Set en el inspector."
+
msgid "Remove Tile Proxies"
msgstr "Eliminar Proxies de Tiles"
@@ -10369,6 +10831,17 @@ msgstr "Tile Base"
msgid "Alternative Tile"
msgstr "Tile Alternativo"
+msgid ""
+"Selected tile:\n"
+"Source: %d\n"
+"Atlas coordinates: %s\n"
+"Alternative: %d"
+msgstr ""
+"Tile seleccionado:\n"
+"Fuente: %d\n"
+"Coordenadas del Atlas: %s\n"
+"Alternativa: %d"
+
msgid "Rendering"
msgstr "Renderizado"
@@ -10432,6 +10905,22 @@ msgstr "Eliminar tile"
msgid "Create tile alternatives"
msgstr "Crear tiles alternativos"
+msgid "Create tiles in non-transparent texture regions"
+msgstr "Crea tiles en regiones con texturas no transparentes"
+
+msgid "Remove tiles in fully transparent texture regions"
+msgstr "Elimina tiles en regiones con texturas completamente transparentes"
+
+msgid "Setup"
+msgstr "Configuración"
+
+msgid ""
+"Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, "
+"control for rectangle editing)."
+msgstr ""
+"Configuración del Atlas. Herramienta para Añadir/Eliminar tiles (usa la "
+"tecla shift para crear tiles grandes, ctrl para edición rectangular)."
+
msgid "Select tiles."
msgstr "Seleccionar tiles."
@@ -10444,12 +10933,29 @@ msgstr "No hay tiles seleccionados."
msgid "Paint Properties:"
msgstr "Propiedades de Pintura:"
+msgid "Create Tiles in Non-Transparent Texture Regions"
+msgstr "Crear Tiles en Regiones no Transparentes de la Textura"
+
+msgid "Remove Tiles in Fully Transparent Texture Regions"
+msgstr "Eliminar Tiles en Regiones Totalmente Transparentes de la Textura"
+
msgid "Create an Alternative Tile"
msgstr "Crear un Tile Alternativo"
msgid "Create a Tile"
msgstr "Crear un Tile"
+msgid "Auto Create Tiles in Non-Transparent Texture Regions?"
+msgstr ""
+"¿Crear automáticamente tiles en regiones con texturas no transparentes?"
+
+msgid ""
+"The atlas's texture was modified.\n"
+"Would you like to automatically create tiles in the atlas?"
+msgstr ""
+"La textura del atlas fue modificada.\n"
+"¿Te gustaría crear automáticamente tiles en el atlas?"
+
msgid "Yes"
msgstr "Sí"
@@ -10471,9 +10977,25 @@ msgstr "Ordenar Fuentes"
msgid "Scenes Collection"
msgstr "Colección de Escenas"
+msgid "Open Atlas Merging Tool"
+msgstr "Abrir Herramienta de Unión de Atlas"
+
msgid "Manage Tile Proxies"
msgstr "Administrar Proxies de Tiles"
+msgid ""
+"No TileSet source selected. Select or create a TileSet source.\n"
+"You can create a new source by using the Add button on the left or by "
+"dropping a tileset texture onto the source list."
+msgstr ""
+"No se ha seleccionado ninguna fuente de TileSet. Seleccione o cree una "
+"fuente de TileSet.\n"
+"Puede crear una nueva fuente utilizando el botón Agregar a la izquierda o "
+"arrastrando una textura de tileset a la lista de fuentes."
+
+msgid "Add new patterns in the TileMap editing mode."
+msgstr "Agregue nuevos patrones en el modo de edición de TileMap."
+
msgid "Add a Scene Tile"
msgstr "Añadir un Tile de Escena"
@@ -10492,6 +11014,13 @@ msgstr "TileSet"
msgid "TileMap"
msgstr "TileMap"
+msgid ""
+"No VCS plugins are available in the project. Install a VCS plugin to use VCS "
+"integration features."
+msgstr ""
+"No hay complementos de VCS disponibles en el proyecto. Instale un "
+"complemento de VCS para utilizar las características de integración de VCS."
+
msgid "Error"
msgstr "Error"
@@ -10534,6 +11063,9 @@ msgstr "¿Quieres eliminar el %s remoto?"
msgid "Create VCS metadata files for:"
msgstr "Crear archivos de metadatos VCS para:"
+msgid "Existing VCS metadata files will be overwritten."
+msgstr "Los archivos de metadatos de VCS existentes serán sobrescritos."
+
msgid "Local Settings"
msgstr "Ajustes Locales"
@@ -10576,6 +11108,10 @@ msgstr "Detectar nuevos cambios"
msgid "Discard all changes"
msgstr "Descartar todos los cambios"
+msgid "This operation is IRREVERSIBLE. Your changes will be deleted FOREVER."
+msgstr ""
+"Esta operación es IRREVERSIBLE. Tus cambios serán eliminados PARA SIEMPRE."
+
msgid "Permanentally delete my changes"
msgstr "Eliminar permanentemente mis cambios"
@@ -10651,6 +11187,9 @@ msgstr "Cambio de Tipo"
msgid "Unmerged"
msgstr "Sin fusionar"
+msgid "View file diffs before committing them to the latest version"
+msgstr "Ver diferencias de archivos antes de confirmarlos a la última versión"
+
msgid "View:"
msgstr "Ver:"
@@ -10690,9 +11229,15 @@ msgstr "Añadir Entrada"
msgid "Add Output"
msgstr "Añadir Salida"
+msgid "Float"
+msgstr "Float"
+
msgid "Int"
msgstr "Int"
+msgid "UInt"
+msgstr "UInt"
+
msgid "Vector2"
msgstr "Vector2"
@@ -10711,6 +11256,13 @@ msgstr "Sampler"
msgid "[default]"
msgstr "[default]"
+msgid ""
+"The 2D preview cannot correctly show the result retrieved from instance "
+"parameter."
+msgstr ""
+"La vista previa 2D no puede mostrar el resultado obtenido del parámetro de "
+"instancia."
+
msgid "Add Input Port"
msgstr "Añadir Puerto de Entrada"
@@ -10777,6 +11329,9 @@ msgstr "Eliminar Variación al Visual Shader: %s"
msgid "Node(s) Moved"
msgstr "Nodo(s) Movido(s)"
+msgid "Convert Constant Node(s) To Parameter(s)"
+msgstr "Convertir Nodo(s) Contantes a Parametro(s)"
+
msgid "Delete VisualShader Node"
msgstr "Eliminar Nodo VisualShader"
@@ -11087,6 +11642,13 @@ msgstr ""
"Parámetro de entrada %s' de procesamiento y colisión de los modos de "
"sombreado."
+msgid ""
+"A node for help to multiply a position input vector by rotation using "
+"specific axis. Intended to work with emitters."
+msgstr ""
+"Un nodo para ayudar a multiplicar un vector de entrada de posición por una "
+"rotación utilizando un eje específico. Diseñado para funcionar con emisores."
+
msgid "Float function."
msgstr "Función de coma flotante."
@@ -11135,6 +11697,12 @@ msgstr ""
"entero."
msgid ""
+"Returns the result of bitwise NOT (~a) operation on the unsigned integer."
+msgstr ""
+"Devuelve el resultado de la operación bitwise NOT (~a) sobre el entero sin "
+"signo."
+
+msgid ""
"Finds the nearest integer that is greater than or equal to the parameter."
msgstr "Encuentra el entero más cercano que es mayor o igual al parámetro."
@@ -11194,6 +11762,11 @@ msgstr "Devuelve el menor de dos valores."
msgid "Linear interpolation between two scalars."
msgstr "Interpolación lineal entre dos escalares."
+msgid "Performs a fused multiply-add operation (a * b + c) on scalars."
+msgstr ""
+"Realiza una operación de multiplicación y suma fusionada (a * b + c) en "
+"escalares."
+
msgid "Returns the opposite value of the parameter."
msgstr "Devuelve el valor opuesto del parámetro."
@@ -11488,6 +12061,14 @@ msgstr "Se descompone y transforma en cuatro vectores."
msgid "Calculates the determinant of a transform."
msgstr "Calcula el determinante de una transformación."
+msgid ""
+"Calculates how the object should face the camera to be applied on Model View "
+"Matrix output port for 3D objects."
+msgstr ""
+"Calcula cómo el objeto debe enfrentar la cámara para ser aplicado en el "
+"puerto de salida de la Matriz de Vista de Modelo (Model View Matrix) para "
+"objetos 3D."
+
msgid "Calculates the inverse of a transform."
msgstr "Calcula el inverso de una transformación."
@@ -11503,6 +12084,9 @@ msgstr "Divide dos transformaciones."
msgid "Multiplies two transforms."
msgstr "Multiplica dos transformaciones."
+msgid "Performs per-component multiplication of two transforms."
+msgstr "Realiza una multiplicación por componente de dos transformaciones."
+
msgid "Subtracts two transforms."
msgstr "Resta dos transformaciones."
@@ -11515,6 +12099,24 @@ msgstr "Constante de transformación."
msgid "Transform parameter."
msgstr "Parámetro de transformación."
+msgid ""
+"The distance fade effect fades out each pixel based on its distance to "
+"another object."
+msgstr ""
+"El efecto de atenuación de distancia desvanece cada píxel en función de su "
+"distancia a otro objeto."
+
+msgid ""
+"The proximity fade effect fades out each pixel based on its distance to "
+"another object."
+msgstr ""
+"El efecto de atenuación de proximidad desvanece cada píxel en función de su "
+"distancia a otro objeto."
+
+msgid "Returns a random value between the minimum and maximum input values."
+msgstr ""
+"Devuelve un valor aleatorio entre los valores mínimos y máximos de entrada."
+
msgid "Vector function."
msgstr "Función Vector."
@@ -11955,6 +12557,10 @@ msgstr "Metadatos de Control de Versión:"
msgid "Git"
msgstr "Git"
+msgid "The project uses features unsupported by the current build:"
+msgstr ""
+"El proyecto utiliza características no compatibles con la versión actual:"
+
msgid "Error: Project is missing on the filesystem."
msgstr "Error: Proyecto faltante en el sistema de archivos."
@@ -12144,6 +12750,15 @@ msgstr ""
msgid "Are you sure to run %d projects at once?"
msgstr "¿Estás seguro de ejecutar %d proyectos a la vez?"
+msgid "Tag name can't be empty."
+msgstr "El nombre de la etiqueta no puede estar vacío."
+
+msgid "Tag name can't contain spaces."
+msgstr "El nombre de la etiqueta no puede contener espacios."
+
+msgid "These characters are not allowed in tags: %s."
+msgstr "Estos caracteres no están permitidos en las etiquetas: %s."
+
msgid "Remove %d projects from the list?"
msgstr "¿Quitar %d proyectos de la lista?"
@@ -12211,6 +12826,9 @@ msgstr "Escanear Proyectos"
msgid "Edit Project"
msgstr "Editar Proyecto"
+msgid "Manage Tags"
+msgstr "Administrar Etiquetas"
+
msgid "Remove Project"
msgstr "Eliminar Proyecto"
@@ -12267,6 +12885,18 @@ msgstr ""
"Actualmente, no tienes ningún proyecto.\n"
"¿Quieres explorar proyectos de ejemplo oficiales en la Librería de Assets?"
+msgid "Manage Project Tags"
+msgstr "Administrar Etiquetas de Proyectos"
+
+msgid "Project Tags"
+msgstr "Etiquetas de Proyecto"
+
+msgid "All Tags"
+msgstr "Todas las Etiquetas"
+
+msgid "Create New Tag"
+msgstr "Crear Nueva Etiqueta"
+
msgid "Add Project Setting"
msgstr "Añadir Configuración del Proyecto"
@@ -12458,6 +13088,9 @@ msgstr "El nombre del archivo es inválido."
msgid "File already exists."
msgstr "El archivo ya existe."
+msgid "Root node valid."
+msgstr "Nodo raíz válido."
+
msgid "Invalid root node name."
msgstr "Nombre de nodo raíz inválido."
@@ -12718,6 +13351,9 @@ msgstr "Cargar Como Placeholder"
msgid "Auto Expand to Selected"
msgstr "Auto Expandir a Seleccionado"
+msgid "All Scene Sub-Resources"
+msgstr "Todos los Subrecursos de Escena"
+
msgid "Filters"
msgstr "Filtros"
@@ -12745,6 +13381,12 @@ msgstr "No se puede pegar el nodo raíz en la misma escena."
msgid "Paste Node(s)"
msgstr "Pegar Nodo(s)"
+msgid "<Unnamed> at %s"
+msgstr "<Sin nombre> en %s"
+
+msgid "(used %d times)"
+msgstr "(usado %d veces)"
+
msgid "Add Child Node"
msgstr "Añadir Nodo Hijo"
@@ -12797,6 +13439,9 @@ msgstr ""
"framerate en el proyecto cada vez que se actualice.\n"
"Vuelve a seleccionar el árbol de escena Local para mejorar el rendimiento."
+msgid "Delete Related Animation Tracks"
+msgstr "Eliminar Pistas de Animación Relacionadas"
+
msgid "Clear Inheritance? (No Undo!)"
msgstr "¿Quieres limpiar la herencia? (No se puede deshacer)"
@@ -12965,6 +13610,9 @@ msgstr "El parámetro de shader global '%s' ya existe"
msgid "Add Shader Global Parameter"
msgstr "Añadir Parámetro Global en el Shader"
+msgid "Select Screen"
+msgstr "Seleccionar Pantalla"
+
msgid "Change Cylinder Radius"
msgstr "Cambiar Radio de Cylinder"
@@ -13272,6 +13920,9 @@ msgstr ""
msgid "Add from path"
msgstr "Añadir desde ruta"
+msgid "Watch"
+msgstr "Ver"
+
msgid "Please select a MultiplayerSynchronizer first."
msgstr "Por favor, selecciona primero un MultiplayerSynchronizer."
@@ -13281,6 +13932,9 @@ msgstr "Establecer propiedad de spawn"
msgid "Set sync property"
msgstr "Establecer propiedad de sincronización"
+msgid "Set watch property"
+msgstr "Establecer propiedad de seguimiento"
+
msgid "Delete Property?"
msgstr "¿Eliminar Propiedad?"
@@ -13703,6 +14357,9 @@ msgstr "Alineando APK..."
msgid "Could not unzip temporary unaligned APK."
msgstr "No se pudo descomprimir el APK no alineado temporal."
+msgid "App Store Team ID not specified."
+msgstr "No se ha especificado el ID del equipo de la App Store."
+
msgid "Invalid Identifier:"
msgstr "Identificador inválido:"
@@ -13730,6 +14387,12 @@ msgstr "Exportación de Script de Depuración"
msgid "Could not open file \"%s\"."
msgstr "No se ha podido abrir el archivo \"%s\"."
+msgid "Debug Console Export"
+msgstr "Exportación de la Consola de Depuración"
+
+msgid "Could not create console wrapper."
+msgstr "No se pudo crear el envoltorio de la consola."
+
msgid "Failed to open executable file \"%s\"."
msgstr "Fallo al abrir el archivo ejecutable \"%s\"."
@@ -13823,6 +14486,97 @@ msgstr "Tipo de objeto desconocido."
msgid "Invalid bundle identifier:"
msgstr "Identificador de paquete no válido:"
+msgid "App Store distribution with ad-hoc code signing is not supported."
+msgstr ""
+"La distribución en la App Store con la firma de código ad-hoc no es "
+"compatible."
+
+msgid "Notarization with an ad-hoc signature is not supported."
+msgstr "La notarización con una firma ad-hoc no es compatible."
+
+msgid "Apple Team ID is required for App Store distribution."
+msgstr ""
+"Se requiere el ID del equipo de Apple para la distribución en la App Store."
+
+msgid "Apple Team ID is required for notarization."
+msgstr "Se requiere el ID de equipo de Apple para la notarización."
+
+msgid "Provisioning profile is required for App Store distribution."
+msgstr ""
+"Se requiere un perfil de aprovisionamiento para la distribución en la App "
+"Store."
+
+msgid "Installer signing identity is required for App Store distribution."
+msgstr ""
+"Se requiere la identidad de firma del instalador para la distribución en la "
+"App Store."
+
+msgid "App sandbox is required for App Store distribution."
+msgstr ""
+"Se requiere un sandbox de aplicación para la distribución en la App Store."
+
+msgid "Code signing is required for App Store distribution."
+msgstr "Se requiere la firma de código para la distribución en la App Store."
+
+msgid "Code signing is required for notarization."
+msgstr "La firma de código es necesaria para la notarización."
+
+msgid ""
+"Neither Apple ID name nor App Store Connect issuer ID name not specified."
+msgstr ""
+"No se ha especificado ni el nombre de Apple ID ni el nombre del emisor de "
+"App Store Connect."
+
+msgid ""
+"Both Apple ID name and App Store Connect issuer ID name are specified, only "
+"one should be set at the same time."
+msgstr ""
+"Tanto el nombre de Apple ID como el nombre del emisor de App Store Connect "
+"están especificados. Solo se debe configurar uno de ellos a la vez."
+
+msgid "Apple ID password not specified."
+msgstr "Contraseña de Apple ID no especificada."
+
+msgid "App Store Connect API key ID not specified."
+msgstr "El ID de la clave de API de App Store Connect no se ha especificado."
+
+msgid "App Store Connect issuer ID name not specified."
+msgstr ""
+"No se ha especificado el nombre del emisor del ID de App Store Connect."
+
+msgid "Microphone access is enabled, but usage description is not specified."
+msgstr ""
+"El acceso al micrófono está habilitado, pero no se ha especificado una "
+"descripción de uso."
+
+msgid "Camera access is enabled, but usage description is not specified."
+msgstr ""
+"El acceso a la cámara está habilitado, pero no se ha especificado una "
+"descripción de uso."
+
+msgid ""
+"Location information access is enabled, but usage description is not "
+"specified."
+msgstr ""
+"El acceso a la información de ubicación está habilitado, pero no se ha "
+"especificado una descripción de uso."
+
+msgid "Address book access is enabled, but usage description is not specified."
+msgstr ""
+"El acceso a la libreta de direcciones está habilitado, pero no se ha "
+"especificado una descripción de uso."
+
+msgid "Calendar access is enabled, but usage description is not specified."
+msgstr ""
+"El acceso al calendario está habilitado, pero no se ha especificado una "
+"descripción de uso."
+
+msgid ""
+"Photo library access is enabled, but usage description is not specified."
+msgstr ""
+"El acceso a la librería de fotos está habilitado, pero no se ha especificado "
+"una descripción de uso."
+
msgid "Icon Creation"
msgstr "Creación de Iconos"
@@ -13839,9 +14593,20 @@ msgstr ""
"La ruta de \"rcodesign\" no se ha establecido. Configura la ruta de "
"\"rcodesign\" en la configuración del editor (Exportar > macOS > rcodesign)."
+msgid "Could not start rcodesign executable."
+msgstr "No se pudo iniciar el ejecutable de rcodesign."
+
+msgid "Notarization failed, see editor log for details."
+msgstr ""
+"La notarización falló, consulta el registro del editor para obtener más "
+"detalles."
+
msgid "Notarization request UUID: \"%s\""
msgstr "Solicitud de notarización UUID: \"%s\""
+msgid "The notarization process generally takes less than an hour."
+msgstr "El proceso de notarización generalmente toma menos de una hora."
+
msgid ""
"You can check progress manually by opening a Terminal and running the "
"following command:"
@@ -13856,6 +14621,9 @@ msgstr ""
"Ejecute el siguiente comando para engrapar el boleto de certificación "
"notarial a la aplicación exportada (opcional):"
+msgid "Xcode command line tools are not installed."
+msgstr "Las herramientas de línea de comandos de Xcode no están instaladas."
+
msgid "Could not start xcrun executable."
msgstr "No se ha podido iniciar el ejecutable xcrun."
@@ -13873,11 +14641,18 @@ msgid "Built-in CodeSign require regex module."
msgstr "El CodeSign incorporado requiere un módulo regex."
msgid ""
+"Xrcodesign path is not set. Configure rcodesign path in the Editor Settings "
+"(Export > macOS > rcodesign)."
+msgstr ""
+"La ruta de Xrcodesign no está establecida. Configura la ruta de rcodesign en "
+"la Configuración del Editor (Exportar > macOS > rcodesign)."
+
+msgid ""
"Could not start codesign executable, make sure Xcode command line tools are "
"installed."
msgstr ""
-"No se ha podido iniciar el ejecutable de codificación, asegúrate de que las "
-"herramientas de línea de comandos de Xcode están instaladas."
+"No se pudo iniciar el ejecutable codesign. Asegúrate de que las herramientas "
+"de línea de comandos de Xcode estén instaladas."
msgid "Cannot sign file %s."
msgstr "No se puede firmar el archivo %s."
@@ -13887,6 +14662,15 @@ msgstr ""
"Los enlaces simbólicos relativos no son compatibles, ¡los \"%s\" exportados "
"podrían estar rotos!"
+msgid "PKG Creation"
+msgstr "Creación de PKG"
+
+msgid "Could not start productbuild executable."
+msgstr "No se pudo iniciar el ejecutable de productbuild."
+
+msgid "`productbuild` failed."
+msgstr "`productbuild` falló."
+
msgid "DMG Creation"
msgstr "Creación de DMG"
@@ -13909,6 +14693,12 @@ msgstr ""
msgid "Invalid export format."
msgstr "Formato de exportación inválido."
+msgid "Could not create directory: \"%s\"."
+msgstr "No se pudo crear el directorio: \"%s\"."
+
+msgid "Could not create directory \"%s\"."
+msgstr "No se pudo crear el directorio \"%s\"."
+
msgid ""
"Relative symlinks are not supported on this OS, the exported project might "
"be broken!"
@@ -13919,6 +14709,9 @@ msgstr ""
msgid "Could not created symlink \"%s\" -> \"%s\"."
msgstr "No se pudo crear el enlace simbólico \"%s\" -> \"%s\"."
+msgid "Could not open \"%s\"."
+msgstr "No se pudo abrir \"%s\"."
+
msgid ""
"Requested template binary \"%s\" not found. It might be missing from your "
"template archive."
@@ -13929,6 +14722,9 @@ msgstr ""
msgid "Making PKG"
msgstr "haciendo paquete"
+msgid "Entitlements Modified"
+msgstr "Entitlements Modificados"
+
msgid ""
"Ad-hoc signed applications require the 'Disable Library Validation' "
"entitlement to load dynamic libraries."
@@ -13936,6 +14732,12 @@ msgstr ""
"Las aplicaciones firmadas ad-hoc requieren la autorización 'Desactivar "
"Validación de Librería' para cargar librerías dinámicas."
+msgid "Could not create entitlements file."
+msgstr "No se pudo crear el archivo de entitlements."
+
+msgid "Could not create helper entitlements file."
+msgstr "No se pudo crear el archivo de entitlements auxiliar."
+
msgid "Code signing bundle"
msgstr "Paquete de firma de código"
@@ -13945,6 +14747,9 @@ msgstr "Haciendo DMG"
msgid "Code signing DMG"
msgstr "Firma de código DMG"
+msgid "Making PKG installer"
+msgstr "Creando Instalador PKG"
+
msgid "Making ZIP"
msgstr "Haciendo ZIP"
@@ -13958,6 +14763,18 @@ msgstr ""
msgid "Sending archive for notarization"
msgstr "Enviando archivo para notarización"
+msgid "Notarization: Xcode command line tools are not installed."
+msgstr ""
+"Notarización: Las herramientas de línea de comandos de Xcode no están "
+"instaladas."
+
+msgid ""
+"Notarization: rcodesign path is not set. Configure rcodesign path in the "
+"Editor Settings (Export > macOS > rcodesign)."
+msgstr ""
+"Notarización: la ruta de rcodesign no está establecida. Configura la ruta de "
+"rcodesign en la Configuración del Editor (Exportar > macOS > rcodesign)."
+
msgid ""
"Warning: Notarization is disabled. The exported project will be blocked by "
"Gatekeeper if it's downloaded from an unknown source."
@@ -13979,6 +14796,24 @@ msgstr ""
"Firma del código: Se utiliza una firma ad-hoc. El proyecto exportado será "
"bloqueado por Gatekeeper"
+msgid "Code signing: Xcode command line tools are not installed."
+msgstr ""
+"Firma de código: Las herramientas de línea de comandos de Xcode no están "
+"instaladas."
+
+msgid ""
+"Code signing: rcodesign path is not set. Configure rcodesign path in the "
+"Editor Settings (Export > macOS > rcodesign)."
+msgstr ""
+"Firma de código: la ruta de rcodesign no está establecida. Configura la ruta "
+"de rcodesign en la Configuración del Editor (Exportar > macOS > rcodesign)."
+
+msgid "Run on remote macOS system"
+msgstr "Ejecutar en sistema remoto macOS"
+
+msgid "Run exported project on remote macOS system"
+msgstr "Ejecutar el proyecto exportado en un sistema macOS remoto"
+
msgid "Invalid package short name."
msgstr "Nombre corto del paquete inválido."
@@ -14071,12 +14906,33 @@ msgstr "Falta el tamaño del icono \"%d\"."
msgid "Failed to rename temporary file \"%s\"."
msgstr "Fallo al renombrar el archivo temporal \"%s\"."
+msgid "Invalid icon path."
+msgstr "Ruta de icono inválida."
+
+msgid "Invalid file version."
+msgstr "Versión de archivo inválida."
+
+msgid "Invalid product version."
+msgstr "Versión de producto inválida."
+
msgid "Could not find rcedit executable at \"%s\"."
msgstr "No se pudo encontrar el ejecutable rcedit en \"%s\"."
msgid "Could not find wine executable at \"%s\"."
msgstr "No se pudo encontrar el ejecutable de wine en \"%s\"."
+msgid "Invalid icon file \"%s\"."
+msgstr "Archivo de icono \"%s\" inválido."
+
+msgid ""
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
+msgstr ""
+"No se pudo iniciar el ejecutable rcedit. Configura la ruta de rcedit en la "
+"Configuración del Editor (Exportar > Windows > rcedit), o deshabilita "
+"\"Aplicación > Modificar Recursos\" en la configuración de exportación."
+
msgid "rcedit failed to modify executable: %s."
msgstr "rcedit falló al modificar el ejecutable: %s."
@@ -14095,15 +14951,62 @@ msgstr "Tipo de identificador inválido."
msgid "Invalid timestamp server."
msgstr "Servidor de marcas de tiempo inválido."
+msgid ""
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > signtool), or disable \"Codesign\" in the "
+"export preset."
+msgstr ""
+"No se pudo iniciar el ejecutable signtool. Configura la ruta de signtool en "
+"la Configuración del Editor (Exportar > Windows > signtool), o deshabilita "
+"\"Codesign\" en la configuración de exportación."
+
+msgid ""
+"Could not start osslsigncode executable. Configure signtool path in the "
+"Editor Settings (Export > Windows > osslsigncode), or disable \"Codesign\" "
+"in the export preset."
+msgstr ""
+"No se pudo iniciar el ejecutable osslsigncode. Configura la ruta de signtool "
+"en la configuración del Editor (Exportar > Windows > osslsigncode), o "
+"desactiva \"Codesign\" en la configuración de exportación."
+
msgid "Signtool failed to sign executable: %s."
msgstr "Signtool no pudo firmar el ejecutable: %s."
msgid "Failed to remove temporary file \"%s\"."
msgstr "No se ha podido eliminar el archivo temporal \"%s\"."
+msgid ""
+"The rcedit tool must be configured in the Editor Settings (Export > Windows "
+"> rcedit) to change the icon or app information data."
+msgstr ""
+"La herramienta rcedit debe configurarse en la Configuración del Editor "
+"(Exportar > Windows > rcedit) para cambiar el icono o los datos de "
+"información de la aplicación."
+
msgid "Windows executables cannot be >= 4 GiB."
msgstr "Los ejecutables de Windows no pueden ser >= 4 GiB."
+msgid "Run on remote Windows system"
+msgstr "Ejecutar en un sistema Windows remoto"
+
+msgid "Run exported project on remote Windows system"
+msgstr "Ejecutar el proyecto exportado en un sistema Windows remoto"
+
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite2D to display frames."
+msgstr ""
+"Se debe crear o establecer un recurso de SpriteFrames en la propiedad "
+"\"Frames\" para que AnimatedSprite2D muestre los fotogramas."
+
+msgid ""
+"Only one visible CanvasModulate is allowed per scene (or set of instantiated "
+"scenes). The first created one will work, while the rest will be ignored."
+msgstr ""
+"Solo se permite un CanvasModulate visible por escena (o conjunto de escenas "
+"instanciadas). El primero creado funcionará, mientras que los demás serán "
+"ignorados."
+
msgid ""
"This node has no shape, so it can't collide or interact with other objects.\n"
"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
@@ -14114,6 +15017,15 @@ msgstr ""
"Considera agregarle un nodo hijo de tipo CollisionShape2D o "
"CollisionPolygon2D para definir su forma."
+msgid ""
+"CollisionPolygon2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."
+msgstr ""
+"CollisionPolygon2D solo se utiliza para proporcionar una forma de colisión a "
+"un nodo derivado de CollisionObject2D. Úsalo solo como hijo de Area2D, "
+"StaticBody2D, RigidBody2D, CharacterBody2D, etc., para darles una forma."
+
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Un CollisionPolygon2D vacío no tiene ningún efecto en las colisiones."
@@ -14128,6 +15040,23 @@ msgstr ""
"'Segments'."
msgid ""
+"The One Way Collision property will be ignored when the collision object is "
+"an Area2D."
+msgstr ""
+"La propiedad de colisión de una sola dirección (One Way Collision) se "
+"ignorará cuando el objeto de colisión sea un Area2D."
+
+msgid ""
+"CollisionShape2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."
+msgstr ""
+"CollisionShape2D solo se utiliza para proporcionar una forma de colisión a "
+"un nodo derivado de CollisionObject2D. Por favor, úsalo únicamente como hijo "
+"de nodos como Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc., para "
+"asignarles una forma de colisión."
+
+msgid ""
"A shape must be provided for CollisionShape2D to function. Please create a "
"shape resource for it!"
msgstr ""
@@ -14202,6 +15131,20 @@ msgstr ""
"El NavigationAgent2D solo puede usarse con un nodo padre del tipo Node2D."
msgid ""
+"NavigationLink2D start position should be different than the end position to "
+"be useful."
+msgstr ""
+"La posición de inicio de NavigationLink2D debe ser diferente a la posición "
+"final para que sea útil."
+
+msgid ""
+"A NavigationMesh resource must be set or created for this node to work. "
+"Please set a property or draw a polygon."
+msgstr ""
+"Se debe establecer o crear un recurso NavigationMesh para que este nodo "
+"funcione. Por favor, establece una propiedad o dibuja un polígono."
+
+msgid ""
"ParallaxLayer node only works when set as child of a ParallaxBackground node."
msgstr ""
"En nodo ParallaxLayer solo funciona cuando esta posicionado como hijo de un "
@@ -14218,9 +15161,39 @@ msgstr ""
"¡Un PhysicalBone2D sólo funciona con un Skeleton2D u otro PhysicalBone2D "
"como nodo padre!"
+msgid ""
+"A PhysicalBone2D needs to be assigned to a Bone2D node in order to function! "
+"Please set a Bone2D node in the inspector."
+msgstr ""
+"Se necesita asignar un PhysicalBone2D a un nodo Bone2D para que funcione "
+"correctamente. Por favor, establece un nodo Bone2D en el inspector."
+
+msgid ""
+"A PhysicalBone2D node should have a Joint2D-based child node to keep bones "
+"connected! Please add a Joint2D-based node as a child to this node!"
+msgstr ""
+"Un nodo PhysicalBone2D debe tener un nodo hijo basado en Joint2D para "
+"mantener los huesos conectados. ¡Por favor, agrega un nodo basado en Joint2D "
+"como hijo de este nodo!"
+
+msgid ""
+"Size changes to RigidBody2D will be overridden by the physics engine when "
+"running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+"Los cambios de tamaño en RigidBody2D serán sobrescritos por el motor de "
+"física durante la ejecución.\n"
+"Cambia el tamaño en las formas de colisión de los hijos en su lugar."
+
msgid "Path property must point to a valid Node2D node to work."
msgstr "La propiedad Path debe apuntar a un nodo Node2D válido para funcionar."
+msgid ""
+"This node cannot interact with other objects unless a Shape2D is assigned."
+msgstr ""
+"Este nodo no puede interactuar con otros objetos a menos que se le asigne "
+"una Shape2D."
+
msgid "This Bone2D chain should end at a Skeleton2D node."
msgstr "Esta cadena Bone2D debería terminar en un nodo Skeleton2D."
@@ -14235,6 +15208,16 @@ msgstr ""
"asígnale una."
msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape3D or CollisionPolygon3D as a child to "
+"define its shape."
+msgstr ""
+"Este nodo no tiene una forma, por lo que no puede colisionar o interactuar "
+"con otros objetos.\n"
+"Considera agregar un CollisionShape3D o CollisionPolygon3D como hijo para "
+"definir su forma."
+
+msgid ""
"CollisionPolygon3D only serves to provide a collision shape to a "
"CollisionObject3D derived node.\n"
"Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, "
@@ -14245,6 +15228,9 @@ msgstr ""
"Por favor, úsalo solo como hijo de Area3D, StaticBody3D, RigidBody3D, "
"CharacterBody3D, etc. para darles una forma."
+msgid "An empty CollisionPolygon3D has no effect on collision."
+msgstr "Un CollisionPolygon3D vacío no tiene efecto en la colisión."
+
msgid ""
"CollisionShape3D only serves to provide a collision shape to a "
"CollisionObject3D derived node.\n"
@@ -14256,16 +15242,50 @@ msgstr ""
"Por favor, úsalo solo como hijo de Area3D, StaticBody3D, RigidBody3D, "
"CharacterBody3D, etc. para darles una forma."
+msgid ""
+"A shape must be provided for CollisionShape3D to function. Please create a "
+"shape resource for it."
+msgstr ""
+"Se debe proporcionar una forma para que CollisionShape3D funcione. Por "
+"favor, crea un recurso de forma para él."
+
+msgid ""
+"ConcavePolygonShape3D doesn't support RigidBody3D in another mode than "
+"static."
+msgstr ""
+"ConcavePolygonShape3D no admite RigidBody3D en ningún modo que no sea "
+"estático."
+
+msgid ""
+"WorldBoundaryShape3D doesn't support RigidBody3D in another mode than static."
+msgstr ""
+"WorldBoundaryShape3D no admite RigidBody3D en ningún modo que no sea "
+"estático."
+
msgid "Nothing is visible because no mesh has been assigned."
msgstr "No hay nada visible porque no se ha asignado ninguna malla."
msgid ""
+"CPUParticles3D animation requires the usage of a StandardMaterial3D whose "
+"Billboard Mode is set to \"Particle Billboard\"."
+msgstr ""
+"La animación de CPUParticles3D requiere el uso de un StandardMaterial3D cuyo "
+"modo Billboard esté configurado en \"Particle Billboard\"."
+
+msgid ""
"Nothing is visible because meshes have not been assigned to draw passes."
msgstr ""
"No hay nada visible porque no se han asignado mallas para los pases de "
"dibujo."
msgid ""
+"Particles animation requires the usage of a BaseMaterial3D whose Billboard "
+"Mode is set to \"Particle Billboard\"."
+msgstr ""
+"La animación de partículas requiere el uso de un BaseMaterial3D cuyo modo "
+"Billboard esté configurado en \"Particle Billboard\"."
+
+msgid ""
"The Bake Mask has no bits enabled, which means baking will not produce any "
"collision for this GPUParticlesCollisionSDF3D.\n"
"To resolve this, enable at least one bit in the Bake Mask property."
@@ -14275,16 +15295,50 @@ msgstr ""
"Para resolver esto, habilita al menos un bit en la propiedad Máscara de "
"Bakeo."
+msgid "Node A and Node B must be PhysicsBody3Ds"
+msgstr "El nodo A y B deben ser de tipo PhysicsBody3D"
+
+msgid "Node A must be a PhysicsBody3D"
+msgstr "El nodo A debe ser un PhysicsBody3D"
+
+msgid "Node B must be a PhysicsBody3D"
+msgstr "El nodo B debe ser un PhysicsBody3D"
+
+msgid "Joint is not connected to any PhysicsBody3Ds"
+msgstr "La unión no está conectada a ningún PhysicsBody3D"
+
+msgid "Node A and Node B must be different PhysicsBody3Ds"
+msgstr "El nodo A y B deben ser PhysicsBody3Ds diferentes"
+
+msgid "A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."
+msgstr ""
+"Un SpotLight3D con un ángulo mayor a 90 grados no puede proyectar sombras."
+
msgid "Finding meshes, lights and probes"
msgstr "Encontrar mallas, luces y sondas"
+msgid "Preparing geometry %d/%d"
+msgstr "Preparando geometría %d/%d"
+
msgid "Creating probes"
msgstr "Crear sondas"
+msgid "Preparing Lightmapper"
+msgstr "Preparando el mapeador de luz"
+
+msgid "Preparing Environment"
+msgstr "Preparando entorno"
+
msgid "Generating Probe Volumes"
msgstr "Generando Volúmenes de Sonda"
msgid ""
+"The NavigationAgent3D can be used only under a Node3D inheriting parent node."
+msgstr ""
+"El NavigationAgent3D solo puede ser utilizado bajo un nodo padre que herede "
+"de Node3D."
+
+msgid ""
"The Bake Mask has no bits enabled, which means baking will not produce any "
"occluder meshes for this OccluderInstance3D.\n"
"To resolve this, enable at least one bit in the Bake Mask property."
@@ -14295,6 +15349,34 @@ msgstr ""
"Para resolver esto, habilita al menos un bit en la propiedad Máscara de "
"Bakeo."
+msgid "PathFollow3D only works when set as a child of a Path3D node."
+msgstr ""
+"PathFollow3D solo funciona cuando se establece como hijo de un nodo Path3D."
+
+msgid ""
+"PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its "
+"parent Path3D's Curve resource."
+msgstr ""
+"ROTATION_ORIENTED de PathFollow3D requiere que el `Up Vector` esté activado "
+"en el recurso de Curve del nodo Path3D padre."
+
+msgid ""
+"Scale changes to RigidBody3D will be overridden by the physics engine when "
+"running.\n"
+"Please change the size in children collision shapes instead."
+msgstr ""
+"Los cambios de escala en RigidBody3D serán sobre escritos por el motor de "
+"física durante la ejecución.\n"
+"Por favor, cambia el tamaño en las formas de colisión de los hijos en su "
+"lugar."
+
+msgid ""
+"The \"Remote Path\" property must point to a valid Node3D or Node3D-derived "
+"node to work."
+msgstr ""
+"La propiedad \"Remote Path\" debe apuntar a un Node3D valido o un Node3D "
+"derivado para que funcione."
+
msgid "This body will be ignored until you set a mesh."
msgstr "Este cuerpo será ignorado hasta que se establezca una malla."
@@ -14305,12 +15387,22 @@ msgstr ""
"Se debe crear o establecer un recurso SpriteFrames en la propiedad "
"\"Frames\" para que AnimatedSprite3D pueda mostrar los fotogramas."
+msgid ""
+"VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please "
+"use it as a child of a VehicleBody3D."
+msgstr ""
+"VehicleWheel3D sirve para proporcionar un sistema de ruedas a un "
+"VehicleBody3D. Por favor, úsalo como hijo de un VehicleBody3D."
+
msgid "Plotting Meshes"
msgstr "Trazando Mallas"
msgid "Finishing Plot"
msgstr "Finalizar Trazado"
+msgid "Generating Distance Field"
+msgstr "Generando Campo de Distancia"
+
msgid "On BlendTree node '%s', animation not found: '%s'"
msgstr "En el nodo BlendTree '%s', no se encontró la animación: '%s'"
@@ -14708,6 +15800,9 @@ msgstr "Ifdef inválido."
msgid "Invalid ifndef."
msgstr "Ifndef inválido."
+msgid "Shader include file does not exist:"
+msgstr "El archivo de inclusión del shader no existe:"
+
msgid ""
"Shader include load failed. Does the shader include exist? Is there a cyclic "
"dependency?"
@@ -14718,6 +15813,9 @@ msgstr ""
msgid "Shader include resource type is wrong."
msgstr "El tipo de recurso de inclusión del shader es incorrecto."
+msgid "Cyclic include found"
+msgstr "Inclusión cíclica encontrada"
+
msgid "Shader max include depth exceeded."
msgstr "Se superó la profundidad máxima de inclusión de shaders."
diff --git a/editor/translations/editor/fr.po b/editor/translations/editor/fr.po
index da8956c1fa..03009026be 100644
--- a/editor/translations/editor/fr.po
+++ b/editor/translations/editor/fr.po
@@ -4092,6 +4092,12 @@ msgstr "Joystick 4 direction haut"
msgid "Joystick 4 Down"
msgstr "Joystick 4 direction bas"
+msgid "or"
+msgstr "ou"
+
+msgid "Unicode"
+msgstr "Unicode"
+
msgid "Joypad Axis %d %s (%s)"
msgstr "Joypad axe %d %s (%s)"
@@ -7499,6 +7505,15 @@ msgid_plural "Run %d Instances"
msgstr[0] "Exécuter une instance %d"
msgstr[1] "Exécuter des instances %d"
+msgid "Size: %s"
+msgstr "Taille : %s"
+
+msgid "Type: %s"
+msgstr "Type : %s"
+
+msgid "Dimensions: %d × %d"
+msgstr "Dimensions : %d × %d"
+
msgid "Overrides (%d)"
msgstr "Redéfinitions (%d)"
diff --git a/editor/translations/editor/ko.po b/editor/translations/editor/ko.po
index 2a6097498f..f15fa4bbd1 100644
--- a/editor/translations/editor/ko.po
+++ b/editor/translations/editor/ko.po
@@ -57,8 +57,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-23 13:10+0000\n"
-"Last-Translator: 최시현 <hihyun1234@ajou.ac.kr>\n"
+"PO-Revision-Date: 2023-07-05 13:48+0000\n"
+"Last-Translator: nulta <un5450@naver.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot/ko/>\n"
"Language: ko\n"
@@ -66,7 +66,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Unset"
msgstr "설정 해제"
@@ -573,6 +573,9 @@ msgstr "애니메이션 키프레임 복제"
msgid "Animation Delete Keys"
msgstr "애니메이션 키프레임 삭제"
+msgid "Focus"
+msgstr "포커스"
+
msgid "Select All Keys"
msgstr "모든 키 선택"
@@ -585,11 +588,17 @@ msgstr "애니메이션 변경 전환"
msgid "Animation Change %s"
msgstr "애니메이션 변경 %s"
+msgid "Animation Change Keyframe Value"
+msgstr "애니메이션 변경 키프레임 값"
+
+msgid "Animation Change Call"
+msgstr "애니메이션 변경 호출"
+
msgid "Animation Multi Change Transition"
msgstr "애니메이션 다중 변경 전환"
msgid "Animation Multi Change %s"
-msgstr "애니메이션 다중 변경"
+msgstr "애니메이션 다중 변경 %s"
msgid "Animation Multi Change Keyframe Value"
msgstr "애니메이션 다중 키프레임 값 변경"
@@ -655,6 +664,9 @@ msgstr "함수:"
msgid "Audio Clips:"
msgstr "오디오 클립:"
+msgid "Animation Clips:"
+msgstr "애니메이션 클립:"
+
msgid "Change Track Path"
msgstr "트랙 경로 바꾸기"
@@ -754,6 +766,12 @@ msgstr "직선형"
msgid "Cubic"
msgstr "입방형"
+msgid "Linear Angle"
+msgstr "직선형 회전"
+
+msgid "Cubic Angle"
+msgstr "입방형 회전"
+
msgid "Clamp Loop Interp"
msgstr "루프 보간 고정"
@@ -781,6 +799,9 @@ msgstr "애니메이션 보간 모드 바꾸기"
msgid "Change Animation Loop Mode"
msgstr "애니메이션 루프 모드 바꾸기"
+msgid "Change Animation Use Blend"
+msgstr "애니메이션 블렌드 사용 바꾸기"
+
msgid ""
"Compressed tracks can't be edited or removed. Re-import the animation with "
"compression disabled in order to edit."
@@ -800,6 +821,9 @@ msgstr "%d개의 새로운 트랙을 생성하고 키를 삽입하시겠습니
msgid "Create"
msgstr "만들기"
+msgid "Animation Insert Key"
+msgstr "애니메이션 키 삽입"
+
msgid "node '%s'"
msgstr "노드 '%s'"
@@ -876,6 +900,9 @@ msgstr "메서드 트랙 키 추가"
msgid "Method not found in object:"
msgstr "오브젝트에 메서드가 없음:"
+msgid "Animation Move Keys"
+msgstr "애니메이션 키 이동"
+
msgid "Position"
msgstr "위치"
@@ -885,6 +912,9 @@ msgstr "회전"
msgid "Scale"
msgstr "크기"
+msgid "BlendShape"
+msgstr "블렌드 모양"
+
msgid "Methods"
msgstr "방법"
@@ -900,6 +930,9 @@ msgstr "클립보드가 비었습니다!"
msgid "Paste Tracks"
msgstr "트랙 붙여 넣기"
+msgid "Animation Scale Keys"
+msgstr "애니메이션 스케일 키"
+
msgid "Make Easing Keys"
msgstr "완화 키 만들기"
@@ -908,12 +941,40 @@ msgid ""
msgstr ""
"이 설정은 단일 트랙에만 적용 가능하므로 베지어 편집에 사용할 수 없습니다."
+msgid "Animation Add RESET Keys"
+msgstr "애니메이션 리셋 키 추가"
+
+msgid "Bake Animation as Linear keys."
+msgstr "애니메이션을 직선형 키로 굽습니다."
+
+msgid ""
+"This animation belongs to an imported scene, so changes to imported tracks "
+"will not be saved.\n"
+"\n"
+"To modify this animation, navigate to the scene's Advanced Import settings "
+"and select the animation.\n"
+"Some options, including looping, are available here. To add custom tracks, "
+"enable \"Save To File\" and\n"
+"\"Keep Custom Tracks\"."
+msgstr ""
+"이 애니메이션은 가져온 씬에 속해 있습니다. 가져온 트랙의 변경사항은 저장되지 "
+"않습니다.\n"
+"\n"
+"이 애니메이션을 수정하려면, 씬의 고급 가져오기 설정에서 애니메이션을 선택하세"
+"요.\n"
+"루핑을 포함한 몇몇 옵션은 여기서 설정할 수 있습니다. 새로운 트랙을 추가하려"
+"면,\n"
+"\"파일으로 저장\"과 \"커스텀 트랙 유지\"를 켜세요."
+
msgid "Warning: Editing imported animation"
msgstr "경고: 가져온 애니메이션을 편집하고 있음"
msgid "Select an AnimationPlayer node to create and edit animations."
msgstr "애니메이션을 만들고 편집하려면 AnimationPlayer노드를 선택하세요."
+msgid "Imported Scene"
+msgstr "가져온 씬"
+
msgid "Toggle between the bezier curve editor and track editor."
msgstr "베지어 커브 편집기와 트랙 편집기 사이를 전환합니다."
@@ -927,7 +988,7 @@ msgid "Snap:"
msgstr "스냅:"
msgid "Animation step value."
-msgstr "애니메이션 단계 값."
+msgstr "애니메이션 단계 값입니다."
msgid "Seconds"
msgstr "초"
@@ -939,7 +1000,7 @@ msgid "Edit"
msgstr "편집"
msgid "Animation properties."
-msgstr "애니메이션 속성."
+msgstr "애니메이션 속성입니다."
msgid "Copy Tracks"
msgstr "트랙 복사"
@@ -950,6 +1011,9 @@ msgstr "선택 항목 스케일 조절"
msgid "Scale From Cursor"
msgstr "커서 위치에서 스케일 조절"
+msgid "Make Easing Selection"
+msgstr "완화 선택 만들기"
+
msgid "Duplicate Selection"
msgstr "선택 항목 복제"
@@ -968,12 +1032,36 @@ msgstr "이전 단계로 이동"
msgid "Apply Reset"
msgstr "재설정 적용"
+msgid "Bake Animation"
+msgstr "애니메이션 굽기"
+
+msgid "Optimize Animation (no undo)"
+msgstr "애니메이션 최적화 (되돌릴 수 없음)"
+
+msgid "Clean-Up Animation (no undo)"
+msgstr "애니메이션 정리 (되돌릴 수 없음)"
+
+msgid "Pick a node to animate:"
+msgstr "애니메이션을 줄 노드를 선택하세요:"
+
msgid "Use Bezier Curves"
msgstr "베지어 곡선 사용"
msgid "Create RESET Track(s)"
msgstr "재설정 트랙 만들기"
+msgid "Animation Optimizer"
+msgstr "애니메이션 최적화"
+
+msgid "Max Velocity Error:"
+msgstr "최대 속도 오차:"
+
+msgid "Max Angular Error:"
+msgstr "최대 각도 오차:"
+
+msgid "Max Precision Error:"
+msgstr "최대 정밀도 오류:"
+
msgid "Optimize"
msgstr "최적화"
@@ -999,24 +1087,90 @@ msgid "Select Transition and Easing"
msgstr "전환 및 완화 선택"
msgctxt "Transition Type"
+msgid "Linear"
+msgstr "직선형 (Linear)"
+
+msgctxt "Transition Type"
msgid "Sine"
-msgstr "사인"
+msgstr "사인형 (Sine)"
msgctxt "Transition Type"
msgid "Quint"
-msgstr "퀸텟트"
+msgstr "5차곡선형 (Quint)"
msgctxt "Transition Type"
msgid "Quart"
-msgstr "쿼트"
+msgstr "4차곡선형 (Quart)"
msgctxt "Transition Type"
msgid "Quad"
-msgstr "쿼드"
+msgstr "2차곡선형 (Quad)"
+
+msgctxt "Transition Type"
+msgid "Expo"
+msgstr "지수곡선형 (Expo)"
+
+msgctxt "Transition Type"
+msgid "Elastic"
+msgstr "탄성형 (Elastic)"
+
+msgctxt "Transition Type"
+msgid "Cubic"
+msgstr "입방형 (Cubic)"
+
+msgctxt "Transition Type"
+msgid "Circ"
+msgstr "원형 (Circ)"
+
+msgctxt "Transition Type"
+msgid "Bounce"
+msgstr "바운스 (Bounce)"
+
+msgctxt "Transition Type"
+msgid "Back"
+msgstr "되돌이 (Back)"
+
+msgctxt "Transition Type"
+msgid "Spring"
+msgstr "스프링 (Spring)"
+
+msgctxt "Ease Type"
+msgid "In"
+msgstr "서서히 가속 (EaseIn)"
+
+msgctxt "Ease Type"
+msgid "Out"
+msgstr "서서히 감속 (EaseOut)"
+
+msgctxt "Ease Type"
+msgid "InOut"
+msgstr "가속/감속 (EaseInOut)"
+
+msgctxt "Ease Type"
+msgid "OutIn"
+msgstr "가속/감속/가속 (EaseOutIn)"
+
+msgid "Transition Type:"
+msgstr "전환 종류:"
+
+msgid "Ease Type:"
+msgstr "완화 종류:"
+
+msgid "FPS:"
+msgstr "FPS:"
msgid "Animation Baker"
msgstr "애니메이션 베이커"
+msgid "3D Pos/Rot/Scl Track:"
+msgstr "3D 위치/각도/크기 트랙:"
+
+msgid "Blendshape Track:"
+msgstr "블렌드 모양 트랙:"
+
+msgid "Value Track:"
+msgstr "값 트랙:"
+
msgid "Select Tracks to Copy"
msgstr "복사할 트랙 선택"
@@ -1042,7 +1196,7 @@ msgid "Line Number:"
msgstr "행 번호:"
msgid "%d replaced."
-msgstr "%d개 찾아 바꿈."
+msgstr "%d개를 찾아 바꿨습니다."
msgid "%d match"
msgid_plural "%d matches"
@@ -1101,6 +1255,9 @@ msgstr ""
"대상 메서드를 찾을 수 없습니다. 올바른 메서드를 지정하거나 대상 노드에 스크립"
"트를 붙여보세요."
+msgid "Attached Script"
+msgstr "부착된 스크립트"
+
msgid "Connect to Node:"
msgstr "이 노드에 연결:"
@@ -1110,15 +1267,30 @@ msgstr "이 스크립트에 연결:"
msgid "From Signal:"
msgstr "이 시그널에서:"
+msgid "Filter Nodes"
+msgstr "노드 필터"
+
+msgid "Go to Source"
+msgstr "소스로 이동"
+
msgid "Scene does not contain any script."
msgstr "씬에 스크립트가 없습니다."
msgid "Select Method"
msgstr "메서드 선택"
+msgid "Filter Methods"
+msgstr "메서드 필터"
+
msgid "No method found matching given filters."
msgstr "지정된 필터와 일치하는 메서드를 찾을 수 없습니다."
+msgid "Script Methods Only"
+msgstr "스크립트 메서드만 표시"
+
+msgid "Compatible Methods Only"
+msgstr "호환되는 메서드만 표시"
+
msgid "Remove"
msgstr "제거"
@@ -1131,6 +1303,9 @@ msgstr "별도의 호출 인수:"
msgid "Allows to drop arguments sent by signal emitter."
msgstr "신호 이미터에서 보낸 인수를 삭제할 수 있습니다."
+msgid "Unbind Signal Arguments:"
+msgstr "시그널 인수 바인드 해제:"
+
msgid "Receiver Method:"
msgstr "받는 메서드:"
@@ -1146,6 +1321,9 @@ msgstr ""
"시그널을 지연합니다. 지연된 시그널은 큐에 보관되었다가 대기 상태가 되면 발생"
"됩니다."
+msgid "One Shot"
+msgstr "원샷"
+
msgid "Disconnects the signal after its first emission."
msgstr "시그널이 처음 발생된 이후 시그널의 연결을 끊습니다."
@@ -1161,6 +1339,9 @@ msgstr "연결"
msgid "Signal:"
msgstr "시그널:"
+msgid "No description."
+msgstr "설명이 없습니다."
+
msgid "Connect '%s' to '%s'"
msgstr "'%s'을(를) '%s'에 연결"
@@ -1179,24 +1360,36 @@ msgstr "연결 끊기"
msgid "Connect a Signal to a Method"
msgstr "시그널을 메서드에 연결"
+msgid "Edit Connection: '%s'"
+msgstr "연결 변경: '%s'"
+
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
msgstr "\"%s\" 시그널의 모든 연결을 제거하시겠습니까?"
msgid "Signals"
msgstr "신호"
+msgid "Filter Signals"
+msgstr "시그널 필터"
+
msgid "Are you sure you want to remove all connections from this signal?"
msgstr "이 시그널의 모든 연결을 제거하시겠습니까?"
msgid "Disconnect All"
msgstr "연결 모두 끊기"
+msgid "Copy Name"
+msgstr "이름 복사"
+
msgid "Edit..."
msgstr "편집..."
msgid "Go to Method"
msgstr "메서드로 이동"
+msgid "Change Type of \"%s\""
+msgstr "\"%s\"의 타입 변경"
+
msgid "Change"
msgstr "바꾸기"
@@ -1221,6 +1414,9 @@ msgstr "즐겨찾기:"
msgid "Recent:"
msgstr "최근 기록:"
+msgid "(Un)favorite selected item."
+msgstr "선택된 항목ㅇ 즐겨찾기 설정/즐겨찾기 해제합니다."
+
msgid "Search:"
msgstr "검색:"
@@ -1260,6 +1456,27 @@ msgstr ""
msgid "Toggle Visibility"
msgstr "가시성 토글"
+msgid "Updating assets on target device:"
+msgstr "목표 디바이스에 에셋을 적용하는 중:"
+
+msgid "Syncing headers"
+msgstr "헤더 동기화 중"
+
+msgid "Getting remote file system"
+msgstr "원격 파일 시스템 얻어오는 중"
+
+msgid "Decompressing remote file system"
+msgstr "원격 파일 시스템 압축 해제 중"
+
+msgid "Scanning for local changes"
+msgstr "로컬 변경사항을 탐색하는 중"
+
+msgid "Sending list of changed files:"
+msgstr "변경된 파일 목록을 보내는 중:"
+
+msgid "Sending file:"
+msgstr "파일 전송 중:"
+
msgid "ms"
msgstr "ms"
@@ -1332,6 +1549,18 @@ msgstr "시간"
msgid "Calls"
msgstr "호출"
+msgid "Fit to Frame"
+msgstr "프레임에 맞추기"
+
+msgid "Linked"
+msgstr "연결됨"
+
+msgid "CPU"
+msgstr "CPU"
+
+msgid "GPU"
+msgstr "GPU"
+
msgid "Execution resumed."
msgstr "실행이 재개되었습니다."
@@ -1347,12 +1576,39 @@ msgstr "오류:"
msgid "%s Error"
msgstr "%s 오류"
+msgid "%s Error:"
+msgstr "%s 오류:"
+
+msgid "%s Source"
+msgstr "%s 소스"
+
+msgid "%s Source:"
+msgstr "%s 소스:"
+
msgid "Stack Trace"
msgstr "스택 추적"
+msgid "Stack Trace:"
+msgstr "스택 추적:"
+
+msgid "Debug session started."
+msgstr "디버그 세션이 시작되었습니다."
+
msgid "Debug session closed."
msgstr "디버그 세션이 종료되었습니다."
+msgid "Line %d"
+msgstr "행 %d"
+
+msgid "Delete Breakpoint"
+msgstr "중단점 제거"
+
+msgid "Delete All Breakpoints in:"
+msgstr "모든 중단점 제거:"
+
+msgid "Delete All Breakpoints"
+msgstr "모든 중단점 제거"
+
msgid "Copy Error"
msgstr "오류 복사"
@@ -1383,6 +1639,9 @@ msgstr "계속"
msgid "Stack Frames"
msgstr "스택 프레임"
+msgid "Filter Stack Variables"
+msgstr "스택 변수 필터"
+
msgid "Breakpoints"
msgstr "중단점"
@@ -1395,6 +1654,9 @@ msgstr "모두 접기"
msgid "Profiler"
msgstr "프로파일러"
+msgid "Visual Profiler"
+msgstr "비주얼 프로파일러"
+
msgid "List of Video Memory Usage by Resource:"
msgstr "리소스 별 비디오 메모리 사용량 목록:"
@@ -1475,14 +1737,21 @@ msgstr "종속 관계 에디터"
msgid "Search Replacement Resource:"
msgstr "대체 리소스 검색:"
+msgid "Open Scene"
+msgid_plural "Open Scenes"
+msgstr[0] "씬 열기"
+
msgid "Open"
msgstr "열기"
msgid "Owners of: %s (Total: %d)"
msgstr "소유자: %s(총: %d)"
+msgid "Localization remap"
+msgstr "현지화 리맵핑"
+
msgid "Localization remap for path '%s' and locale '%s'."
-msgstr "경로 '%s' 및 로케일 '%s'에 대한 지역화 재매핑."
+msgstr "경로 '%s' 및 로케일 '%s'에 대한 현지화 리맵핑입니다."
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
@@ -1540,9 +1809,31 @@ msgstr "소유함"
msgid "Resources Without Explicit Ownership:"
msgstr "명확한 소유 관계가 없는 리소스:"
+msgid "Folder name cannot be empty."
+msgstr "폴더 이름은 비워둘 수 없습니다."
+
+msgid "Folder name contains invalid characters."
+msgstr "폴더 이름에 잘못된 문자가 있습니다."
+
+msgid "File with that name already exists."
+msgstr "이 이름으로 된 파일이 이미 있습니다."
+
+msgid "Folder with that name already exists."
+msgstr "이 이름으로 된 폴더가 이미 있습니다."
+
+msgid "Using slashes in folder names will create subfolders recursively."
+msgstr ""
+"폴더 이름에 슬래시를 사용하면 해당하는 하위 폴더들을 재귀적으로 만듭니다."
+
+msgid "Folder name is valid."
+msgstr "폴더 이름이 올바릅니다."
+
msgid "Could not create folder."
msgstr "폴더를 만들 수 없습니다."
+msgid "Create new folder in %s:"
+msgstr "%s에 새 폴더 생성:"
+
msgid "Create Folder"
msgstr "폴더 만들기"
@@ -1639,7 +1930,7 @@ msgid "Uncompressing Assets"
msgstr "애셋 압축 풀기"
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "다음 파일을 애셋에서 압축 푸는 데 실패함:"
+msgstr "에셋 \"%s\"에서 다음 파일의 압축 해제를 실패함:"
msgid "(and %s more files)"
msgstr "(및 더 많은 파일 %s개)"
@@ -1704,6 +1995,12 @@ msgstr "바이패스"
msgid "Bus Options"
msgstr "버스 옵션"
+msgid "Duplicate Bus"
+msgstr "버스 복제"
+
+msgid "Delete Bus"
+msgstr "버스 삭제"
+
msgid "Reset Volume"
msgstr "볼륨 재설정"
@@ -1791,18 +2088,27 @@ msgstr "올바른 문자:"
msgid "Must not collide with an existing engine class name."
msgstr "엔진에 이미 있는 클래스 이름과 겹치지 않아야 합니다."
+msgid "Must not collide with an existing global script class name."
+msgstr "이미 있는 전역 스크립트 클래스 이름과 겹치지 않아야 합니다."
+
msgid "Must not collide with an existing built-in type name."
msgstr "기존 내장 타입과 이름과 겹치지 않아야 합니다."
msgid "Must not collide with an existing global constant name."
msgstr "전역 상수와 이름이 겹치지 않아야 합니다."
+msgid "Keyword cannot be used as an Autoload name."
+msgstr "키워드를 오토로드 이름으로 사용할 수 없습니다."
+
msgid "Autoload '%s' already exists!"
msgstr "오토로드 '%s'이(가) 이미 있습니다!"
msgid "Rename Autoload"
msgstr "오토로드 이름 바꾸기"
+msgid "Toggle Autoload Globals"
+msgstr "전역 오토로드 토글"
+
msgid "Move Autoload"
msgstr "오토로드 이동"
@@ -1815,12 +2121,18 @@ msgstr "활성화"
msgid "Rearrange Autoloads"
msgstr "오토로드 다시 정렬"
+msgid "Can't add Autoload:"
+msgstr "오토로드를 추가할 수 없음:"
+
msgid "%s is an invalid path. File does not exist."
msgstr "%s는 잘못된 경로입니다. 파일이 존재하지 않습니다."
msgid "%s is an invalid path. Not in resource path (res://)."
msgstr "%s는 잘못된 경로입니다. 리소스 경로(res://)에 있지 않습니다."
+msgid "Add Autoload"
+msgstr "오토로드 추가"
+
msgid "Path:"
msgstr "경로:"
@@ -1833,6 +2145,9 @@ msgstr "노드 이름:"
msgid "Global Variable"
msgstr "전역 변수"
+msgid "3D Engine"
+msgstr "3D 엔진"
+
msgid "2D Physics"
msgstr "2D 물리"
@@ -1845,48 +2160,69 @@ msgstr "네비게이션"
msgid "XR"
msgstr "XR"
+msgid "RenderingDevice"
+msgstr "RenderingDevice"
+
+msgid "OpenGL"
+msgstr "OpenGL"
+
msgid "Vulkan"
-msgstr "벌칸"
+msgstr "Vulkan"
+
+msgid "Text Server: Fallback"
+msgstr "텍스트 서버: 폴백"
msgid "Text Server: Advanced"
msgstr "텍스트 서버: 고급"
msgid "TTF, OTF, Type 1, WOFF1 Fonts"
-msgstr "TTF, OTF, 유형 1, WOFF1 글꼴"
+msgstr "TTF, OTF, Type 1, WOFF1 글꼴"
+
+msgid "WOFF2 Fonts"
+msgstr "WOFF2 글꼴"
+
+msgid "SIL Graphite Fonts"
+msgstr "SIL Graphite 글꼴"
msgid "Multi-channel Signed Distance Field Font Rendering"
-msgstr "멀티 채널 부호화된 디스턴스 필드 폰트 렌더링"
+msgstr "멀티 채널 SDF 폰트 렌더링"
msgid "3D Nodes as well as RenderingServer access to 3D features."
-msgstr "3D 노드뿐만 아니라 3D 기능에 대한 렌더링 서버 액세스도 가능합니다."
+msgstr "3D 노드 지원과 더불어 렌더링 서버가 3D 기능을 사용할 수 있게 합니다."
msgid "2D Physics nodes and PhysicsServer2D."
-msgstr "2D 피직스 노드 및 PhysicsServer2D."
+msgstr "2D 물리 노드와 PhysicsServer2D입니다."
msgid "3D Physics nodes and PhysicsServer3D."
-msgstr "3D 피직스 노드 및 PhysicsServer3D."
+msgstr "3D 물리 노드와 PhysicsServer3D입니다."
+
+msgid "Navigation, both 2D and 3D."
+msgstr "2D와 3D에서 사용하는 네비게이션 기능입니다."
msgid "XR (AR and VR)."
-msgstr "XR(AR 및 VR)."
+msgstr "XR (AR 및 VR)입니다."
msgid ""
"RenderingDevice based rendering (if disabled, the OpenGL back-end is "
"required)."
-msgstr "렌더링 장치 기반 렌더링(비활성화하면 OpenGL 백엔드가 필요함)."
+msgstr ""
+"RenderingDevice 기반 렌더링입니다. 비활성화된 경우 OpenGL 백엔드가 필요합니"
+"다."
msgid ""
"OpenGL back-end (if disabled, the RenderingDevice back-end is required)."
-msgstr "OpenGL 백엔드(비활성화된 경우 RenderingDevice 백엔드가 필요함)."
+msgstr ""
+"OpenGL 백엔드입니다. 비활성화된 경우 RenderingDevice 백엔드가 필요합니다."
msgid "Vulkan back-end of RenderingDevice."
-msgstr "RenderingDevice의 벌칸 백엔드."
+msgstr "RenderingDevice가 사용하는 Vulkan 백엔드입니다."
msgid ""
"Fallback implementation of Text Server\n"
"Supports basic text layouts."
msgstr ""
-"텍스트 서버의 폴백 구현\n"
-"기본 텍스트 레이아웃을 지원합니다."
+"텍스트 서버의 대체 구현.\n"
+"기본적인 텍스트 레이아웃만을 지원합니다."
msgid ""
"Text Server implementation powered by ICU and HarfBuzz libraries.\n"
@@ -1899,23 +2235,29 @@ msgid ""
"TrueType, OpenType, Type 1, and WOFF1 font format support using FreeType "
"library (if disabled, WOFF2 support is also disabled)."
msgstr ""
-"FreeType 라이브러리를 사용하여 트루타입, 오픈타입, 타입 1 및 WOFF1 글꼴 형식"
-"을 지원합니다(비활성화하면 WOFF2 지원도 비활성화됩니다)."
+"FreeType 라이브러리를 사용하여 트루타입, 오픈타입, Type 1 및 WOFF1 글꼴 형식"
+"을 지원합니다. 비활성화하면 WOFF2 지원도 비활성화됩니다."
msgid "WOFF2 font format support using FreeType and Brotli libraries."
-msgstr "프리타입 및 브로틀리 라이브러리를 사용한 WOFF2 글꼴 형식 지원."
+msgstr "FreeType 및 Brotli 라이브러리를 사용하여 WOFF2 글꼴 형식을 지원합니다."
msgid ""
"SIL Graphite smart font technology support (supported by Advanced Text "
"Server only)."
-msgstr "SIL 그라파이트 스마트 글꼴 기술 지원(고급 텍스트 서버에서만 지원)."
+msgstr ""
+"SIL Graphite 스마트 글꼴 기술을 지원합니다. 고급 텍스트 서버에서만 사용 가능"
+"합니다."
msgid ""
"Multi-channel signed distance field font rendering support using msdfgen "
"library (pre-rendered MSDF fonts can be used even if this option disabled)."
msgstr ""
-"msdfgen 라이브러리를 사용하여 다중 채널 서명된 거리 필드 글꼴 렌더링 지원(이 "
-"옵션을 비활성화해도 사전 렌더링된 MSDF 글꼴을 사용할 수 있음)."
+"msdfgen 라이브러리를 이용한 멀티 채널 부호 있는 디스턴스 필드(Multi-channel "
+"SDF) 폰트 렌더링을 지원합니다. 이 옵션을 비활성화해도 사전 렌더링된 MSDF 글꼴"
+"은 사용할 수 있습니다."
+
+msgid "General Features:"
+msgstr "주요 기능:"
msgid "Text Rendering and Font Options:"
msgstr "텍스트 렌더링 및 글꼴 옵션:"
@@ -1938,12 +2280,30 @@ msgstr "새로 만들기"
msgid "Save"
msgstr "저장"
+msgid "Profile:"
+msgstr "프로필:"
+
msgid "Reset to Defaults"
msgstr "기본값으로 재설정"
+msgid "Detect from Project"
+msgstr "프로젝트에서 자동 감지"
+
+msgid "Actions:"
+msgstr "액션:"
+
+msgid "Configure Engine Build Profile:"
+msgstr "엔진 빌드 프로필 구성:"
+
+msgid "Please Confirm:"
+msgstr "확인해주세요:"
+
msgid "Engine Build Profile"
msgstr "엔진 빌드 프로필"
+msgid "Load Profile"
+msgstr "프로필 가져오기"
+
msgid "Export Profile"
msgstr "프로필 내보내기"
@@ -1953,6 +2313,9 @@ msgstr "감지 시 강제 클래스:"
msgid "Edit Build Configuration Profile"
msgstr "빌드 설정 프로필 편집"
+msgid "Filter Commands"
+msgstr "명령어 필터"
+
msgid "Paste Params"
msgstr "매개변수 붙여넣기"
@@ -1978,46 +2341,49 @@ msgid "Script Editor"
msgstr "스크립트 에디터"
msgid "Asset Library"
-msgstr "애셋 라이브러리"
+msgstr "에셋 라이브러리"
msgid "Scene Tree Editing"
msgstr "씬 트리 편집"
msgid "Node Dock"
-msgstr "노드 도킹"
+msgstr "노드 독"
msgid "FileSystem Dock"
msgstr "파일시스템 독"
msgid "Import Dock"
-msgstr "독 가져오기"
+msgstr "가져오기 독"
+
+msgid "History Dock"
+msgstr "작업 내역 독"
msgid "Allows to view and edit 3D scenes."
-msgstr "3D 씬을 보고 편집할 수 있게 합니다."
+msgstr "3D 씬을 보고 편집할 수 있습니다."
msgid "Allows to edit scripts using the integrated script editor."
-msgstr "통합 스크립트 에디터를 사용해 스크립트를 편집할 수 있게 합니다."
+msgstr "통합된 스크립트 에디터를 사용해 스크립트를 편집할 수 있습니다."
msgid "Provides built-in access to the Asset Library."
-msgstr "애셋 라이브러리에 내장 접근을 제공합니다."
+msgstr "에셋 라이브러리에 대한 내장된 접근을 제공합니다."
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr "씬 독에서 노드 계층 구조를 편집할 수 있게 합니다."
+msgstr "씬 독에서 노드 계층 구조를 편집할 수 있습니다."
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
-msgstr "씬 독에서 선택된 노드의 신호와 그룹으로 동작할 수 있게 합니다."
+msgstr "씬 독에서 선택된 노드의 시그널과 그룹을 조작할 수 있습니다."
msgid "Allows to browse the local file system via a dedicated dock."
-msgstr "전용 독을 통해 로컬 파일 시스템을 탐색할 수 있게 합니다."
+msgstr "전용 독을 통해 로컬 파일 시스템을 탐색할 수 있습니다."
msgid ""
"Allows to configure import settings for individual assets. Requires the "
"FileSystem dock to function."
msgstr ""
-"개별 애셋에 대한 가져오기 설정을 구성할 수 있게 합니다. 작동하려면 파일시스"
-"템 독이 필요합니다."
+"개별 애셋에 대한 가져오기 설정을 구성할 수 있습니다. 작동하려면 파일시스템 독"
+"이 필요합니다."
msgid "Provides an overview of the editor's and each scene's undo history."
msgstr "편집기 및 각 씬의 실행 취소 기록에 대한 개요를 제공합니다."
@@ -2029,7 +2395,7 @@ msgid "(none)"
msgstr "(없음)"
msgid "Remove currently selected profile, '%s'? Cannot be undone."
-msgstr "현재 선택된 프로필인 '%s'을 제거하시겠습니까? 되돌릴 수 없습니다."
+msgstr "현재 선택된 프로필 '%s'을 제거하시겠습니까? 되돌릴 수 없습니다."
msgid "Profile must be a valid filename and must not contain '.'"
msgstr "프로필 이름은 '.' 이 없는 올바른 파일 이름이어야 합니다"
@@ -2110,6 +2476,9 @@ msgstr "프로필 가져오기"
msgid "Manage Editor Feature Profiles"
msgstr "에디터 기능 프로필 관리"
+msgid "Some extensions need the editor to restart to take effect."
+msgstr "변경사항을 반영하려면 에디터를 다시 시작해야 합니다."
+
msgid "Restart"
msgstr "다시 시작"
@@ -2129,8 +2498,20 @@ msgstr ""
msgid "(Re)Importing Assets"
msgstr "애셋 (다시) 가져오는 중"
+msgid "Import resources of type: %s"
+msgstr "가져올 리소스의 타입: %s"
+
+msgid "No return value."
+msgstr "반환값이 없습니다."
+
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr "이 값은 다음과 같은 플래그들의 비트마스크로 이루어진 정수입니다."
+
+msgid "Deprecated"
+msgstr "사용되지 않음"
+
msgid "Experimental"
-msgstr "실험적인"
+msgstr "실험적"
msgid "This method supports a variable number of arguments."
msgstr "이 메서드는 다양한 인수를 지원합니다."
@@ -2162,8 +2543,15 @@ msgstr "반환된 오류 코드:"
msgid "There is currently no description for this %s."
msgstr "현재 이 %s에 대한 설명이 없습니다."
+msgid ""
+"There is currently no description for this %s. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"현재 이 %s의 설명이 없습니다. [color=$color][url=$url]관련 정보를 기여하여[/"
+"url][/color] 개선할 수 있도록 도와주세요!"
+
msgid "Top"
-msgstr "맨 위"
+msgstr "위쪽"
msgid "Class:"
msgstr "클래스:"
@@ -2185,7 +2573,7 @@ msgid ""
"possible removal in future versions. Use at your own discretion."
msgstr ""
"이 클래스는 실험적이라고 표시되어 있습니다. 향후 버전에서 변경되거나 제거될 "
-"수 있습니다. 사용자 재량에 따라 사용하세요."
+"수 있습니다. 신중하게 사용하세요."
msgid "Description"
msgstr "설명"
@@ -2193,6 +2581,13 @@ msgstr "설명"
msgid "There is currently no description for this class."
msgstr "현재 이 클래스에 대한 설명이 없습니다."
+msgid ""
+"There is currently no description for this class. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"현재 이 클래스의 설명이 없습니다. [color=$color][url=$url]관련 정보를 기여하"
+"여[/url][/color] 개선할 수 있도록 도와주세요!"
+
msgid "Online Tutorials"
msgstr "온라인 튜토리얼"
@@ -2203,7 +2598,10 @@ msgid "overrides %s:"
msgstr "%s 오버라이드:"
msgid "default:"
-msgstr "디폴트:"
+msgstr "기본값:"
+
+msgid "property:"
+msgstr "속성:"
msgid "Constructors"
msgstr "생성자"
@@ -2218,11 +2616,14 @@ msgid "Colors"
msgstr "색상"
msgid "Constants"
-msgstr "상수"
+msgstr "제약"
msgid "Fonts"
msgstr "글꼴"
+msgid "Font Sizes"
+msgstr "글꼴 크기"
+
msgid "Icons"
msgstr "아이콘"
@@ -2232,8 +2633,18 @@ msgstr "스타일"
msgid "Enumerations"
msgstr "목록"
+msgid "Annotations"
+msgstr "어노테이션"
+
msgid "There is currently no description for this annotation."
-msgstr "현재 이 주석에 대한 설명이 없습니다."
+msgstr "현재 이 어노테이션에 대한 설명이 없습니다."
+
+msgid ""
+"There is currently no description for this annotation. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"현재 이 어노테이션의 설명이 없습니다. [color=$color][url=$url]관련 정보를 기"
+"여하여[/url][/color] 개선할 수 있도록 도와주세요!"
msgid "Property Descriptions"
msgstr "속성 설명"
@@ -2281,12 +2692,21 @@ msgstr "모두 표시"
msgid "Classes Only"
msgstr "클래스만"
+msgid "Constructors Only"
+msgstr "생성자만 표시"
+
msgid "Methods Only"
msgstr "메서드만 표시"
+msgid "Operators Only"
+msgstr "연산자만 표시"
+
msgid "Signals Only"
msgstr "시그널만 표시"
+msgid "Annotations Only"
+msgstr "어노테이션만 표시"
+
msgid "Constants Only"
msgstr "상수만 표시"
@@ -2299,6 +2719,9 @@ msgstr "테마 속성만 표시"
msgid "Member Type"
msgstr "멤버 타입"
+msgid "(constructors)"
+msgstr "(생성자)"
+
msgid "Class"
msgstr "클래스"
@@ -2308,6 +2731,9 @@ msgstr "메서드"
msgid "Signal"
msgstr "시그널"
+msgid "Annotation"
+msgstr "어노테이션"
+
msgid "Constant"
msgstr "상수"
@@ -2326,6 +2752,12 @@ msgstr "이 멤버는 실험단계로 표시됩니다."
msgid "Property:"
msgstr "속성:"
+msgid "Pin Value"
+msgstr "값 고정"
+
+msgid "Pin Value [Disabled because '%s' is editor-only]"
+msgstr "값 고정 ['%s'이(가) 에디터 전용이므로 비활성화됨]"
+
msgid ""
"Pinning a value forces it to be saved even if it's equal to the default."
msgstr "값을 고정하면 값이 기본값과 같더라도 강제로 저장됩니다."
@@ -2333,6 +2765,26 @@ msgstr "값을 고정하면 값이 기본값과 같더라도 강제로 저장됩
msgid "Open Documentation"
msgstr "문서 열기"
+msgid "(%d change)"
+msgid_plural "(%d changes)"
+msgstr[0] "(변경 사항 %d개)"
+
+msgid "Add element to property array with prefix %s."
+msgstr "접두어 %s를 가진 속성 배열에 요소를 추가합니다."
+
+msgid "Remove element %d from property array with prefix %s."
+msgstr "요소 %d개를 접두어 %s를 가진 속성 배열에서 제거합니다."
+
+msgid "Move element %d to position %d in property array with prefix %s."
+msgstr ""
+"%d번 요소의 위치를 %d번으로, 접두어 %s를 가진 속성 배열 내에서 이동합니다."
+
+msgid "Clear property array with prefix %s."
+msgstr "접두어 %s를 가진 속성 배열을 완전히 비웁니다."
+
+msgid "Resize property array with prefix %s."
+msgstr "접두어 %s를 가진 속성 배열의 크기를 변경합니다."
+
msgid "Element %d: %s%d*"
msgstr "요소 %d: %s%d*"
@@ -2342,9 +2794,30 @@ msgstr "위로 이동"
msgid "Move Down"
msgstr "아래로 이동"
+msgid "Insert New Before"
+msgstr "앞에 새로 삽입"
+
+msgid "Insert New After"
+msgstr "뒤에 새로 삽입"
+
+msgid "Clear Array"
+msgstr "배열 비우기"
+
+msgid "Resize Array..."
+msgstr "배열 크기 변경..."
+
+msgid "Add Element"
+msgstr "요소 추가"
+
msgid "Resize Array"
msgstr "배열 크기 바꾸기"
+msgid "New Size:"
+msgstr "새로운 크기:"
+
+msgid "Element %s"
+msgstr "요소 %s"
+
msgid "Add Metadata"
msgstr "메타데이터 추가"
@@ -2354,6 +2827,9 @@ msgstr "Set %s"
msgid "Set Multiple:"
msgstr "다수 설정:"
+msgid "Remove metadata %s"
+msgstr "메타데이터 %s 제거"
+
msgid "Pinned %s"
msgstr "%s 고정됨"
@@ -2366,12 +2842,30 @@ msgstr "메타데이터 %s 추가"
msgid "Metadata name can't be empty."
msgstr "메타데이터 이름은 비워둘 수 없습니다."
+msgid "Metadata name must be a valid identifier."
+msgstr "메타데이터 이름은 올바른 식별자여야 합니다."
+
+msgid "Metadata with name \"%s\" already exists."
+msgstr "이름 '%s'을(를) 가진 메타데이터가 이미 있습니다."
+
msgid "Names starting with _ are reserved for editor-only metadata."
msgstr "_로 시작하는 이름은 편집기 전용 메타데이터를 위해 예약되어 있습니다."
+msgid "Metadata name is valid."
+msgstr "메타데이터 이름이 올바릅니다."
+
msgid "Name:"
msgstr "이름:"
+msgid "Add Metadata Property for \"%s\""
+msgstr "\"%s\"에 메타데이터 추가하기"
+
+msgid "Copy Value"
+msgstr "값 복사"
+
+msgid "Paste Value"
+msgstr "값 붙여넣기"
+
msgid "Copy Property Path"
msgstr "속성 경로 복사"
@@ -2381,9 +2875,30 @@ msgstr "메시 미리보기 만드는 중"
msgid "Thumbnail..."
msgstr "썸네일..."
+msgid "Select existing layout:"
+msgstr "존재하는 레이아웃 선택:"
+
+msgid "Or enter new layout name"
+msgstr "또는 새로운 레이아웃 이름 입력"
+
+msgid "Changed Locale Language Filter"
+msgstr "로케일 언어 필터 변경됨"
+
+msgid "Changed Locale Script Filter"
+msgstr "로케일 스크립트 필터 변경됨"
+
+msgid "Changed Locale Country Filter"
+msgstr "로케일 국가 필터 변경됨"
+
msgid "Changed Locale Filter Mode"
msgstr "로케일 필터 모드 변경됨"
+msgid "[Default]"
+msgstr "[기본]"
+
+msgid "Select a Locale"
+msgstr "로케일 선택"
+
msgid "Show All Locales"
msgstr "모든 로케일 보이기"
@@ -2396,12 +2911,29 @@ msgstr "필터 편집"
msgid "Language:"
msgstr "언어:"
+msgctxt "Locale"
+msgid "Script:"
+msgstr "문자:"
+
+msgid "Country:"
+msgstr "국가:"
+
msgid "Language"
msgstr "언어"
+msgctxt "Locale"
+msgid "Script"
+msgstr "문자"
+
+msgid "Country"
+msgstr "국가"
+
msgid "Variant"
msgstr "변종"
+msgid "Filter Messages"
+msgstr "메시지 필터"
+
msgid "Clear Output"
msgstr "출력 지우기"
@@ -2416,6 +2948,18 @@ msgstr ""
msgid "Focus Search/Filter Bar"
msgstr "초점 검색/필터 바"
+msgid "Toggle visibility of standard output messages."
+msgstr "표준 출력 메시지 표시 여부를 토글합니다."
+
+msgid "Toggle visibility of errors."
+msgstr "에러 표시 여부를 토글합니다."
+
+msgid "Toggle visibility of warnings."
+msgstr "경고 표시 여부를 토글합니다."
+
+msgid "Toggle visibility of editor messages."
+msgstr "에디터 메시지 표시 여부를 토글합니다."
+
msgid "Native Shader Source Inspector"
msgstr "네이티브 셰이더 소스 인스펙터"
@@ -2453,6 +2997,13 @@ msgstr ""
"이 리소스는 편집 중인 씬에 속한 것이 아니라서 저장할 수 없습니다. 저장하기 전"
"에 먼저 리소스를 유일하게 만드세요."
+msgid ""
+"This resource can't be saved because it was imported from another file. Make "
+"it unique first."
+msgstr ""
+"이 리소스는 다른 파일에서 가져왔기 때문에 저장할 수 없습니다. 저장하기 전에 "
+"먼저 리소스를 유일하게 만드세요."
+
msgid "Save Resource As..."
msgstr "리소스를 다른 이름으로 저장..."
@@ -2463,10 +3014,23 @@ msgid "Requested file format unknown:"
msgstr "요청한 파일 형식을 알 수 없음:"
msgid "Error while saving."
-msgstr "저장 중 오류."
+msgstr "저장 중 오류가 발생했습니다."
+
+msgid "Can't open file '%s'. The file could have been moved or deleted."
+msgstr ""
+"파일 '%s'을(를) 열 수 없습니다. 파일이 이동했거나 삭제되었을 수 있습니다."
+
+msgid "Error while parsing file '%s'."
+msgstr "'%s' 구문 분석 중 오류가 발생했습니다."
msgid "Scene file '%s' appears to be invalid/corrupt."
-msgstr "장면 파일 '%s'이(가) 잘못되었거나 손상된 것 같습니다."
+msgstr "씬 파일 '%s'이(가) 잘못되었거나 손상된 것 같습니다."
+
+msgid "Missing file '%s' or one its dependencies."
+msgstr "파일 '%s' 또는 이것의 종속 항목이 누락되어 있습니다."
+
+msgid "Error while loading file '%s'."
+msgstr "파일 '%s'을(를) 불러오는 중 오류가 발생했습니다."
msgid "Saving Scene"
msgstr "씬 저장 중"
@@ -2481,6 +3045,13 @@ msgid "This operation can't be done without a tree root."
msgstr "이 작업은 트리 루트가 필요합니다."
msgid ""
+"This scene can't be saved because there is a cyclic instance inclusion.\n"
+"Please resolve it and then attempt to save again."
+msgstr ""
+"이 씬에 순환 인스턴스 관계가 있어서 저장할 수 없습니다.\n"
+"이를 해결한 후 다시 저장해보세요."
+
+msgid ""
"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
"be satisfied."
msgstr ""
@@ -2540,12 +3111,30 @@ msgstr ""
"세요."
msgid ""
+"This resource belongs to a scene that was instantiated or inherited.\n"
+"Changes to it must be made inside the original scene."
+msgstr ""
+"이 리소스는 인스턴스되거나 상속된 씬에 속해 있습니다.\n"
+"변경하기 위해서는 반드시 원본 씬을 조작해야 합니다."
+
+msgid ""
"This resource was imported, so it's not editable. Change its settings in the "
"import panel and then re-import."
msgstr ""
"이 리소스는 가져온 것이므로 편집할 수 없습니다. 가져오기 패널에서 설정을 변경"
"한 뒤 다시 가져오세요."
+msgid ""
+"This scene was imported, so changes to it won't be kept.\n"
+"Instantiating or inheriting it will allow you to make changes to it.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+"이 씬은 가져온 것이므로 변경사항이 유지되지 않습니다.\n"
+"이 씬을 인스턴스화하거나 상속하면 편집할 수 있습니다.\n"
+"이 워크플로를 이해하려면 씬 가져오기(Importing Scenes)와 관련된 문서를 읽어주"
+"세요."
+
msgid "Changes may be lost!"
msgstr "변경사항을 잃을 수도 있습니다!"
@@ -2593,12 +3182,30 @@ msgstr "마우스 버튼을 누르고 있는 동안에는 실행 취소할 수
msgid "Nothing to undo."
msgstr "실행 취소할 것이 없습니다."
+msgid "Global Undo: %s"
+msgstr "전역 실행 취소: %s"
+
+msgid "Remote Undo: %s"
+msgstr "원격 실행 취소: %s"
+
+msgid "Scene Undo: %s"
+msgstr "씬 실행 취소: %s"
+
msgid "Can't redo while mouse buttons are pressed."
msgstr "마우스 버튼을 누르고 있는 동안에는 다시 실행할 수 없습니다."
msgid "Nothing to redo."
msgstr "다시 실행할 것이 없습니다."
+msgid "Global Redo: %s"
+msgstr "전역 다시 실행: %s"
+
+msgid "Remote Redo: %s"
+msgstr "원격 다시 실행: %s"
+
+msgid "Scene Redo: %s"
+msgstr "씬 다시 실행: %s"
+
msgid "Can't reload a scene that was never saved."
msgstr "저장하지 않은 씬은 새로고침할 수 없습니다."
@@ -2615,9 +3222,15 @@ msgstr ""
msgid "Save & Reload"
msgstr "저장 및 새로고침"
+msgid "Save modified resources before reloading?"
+msgstr "새로고침하기 전에 변경사항을 저장하시겠습니까?"
+
msgid "Save & Quit"
msgstr "저장 & 종료"
+msgid "Save modified resources before closing?"
+msgstr "닫기 전에 변경사항을 저장하시겠습니까?"
+
msgid "Save changes to the following scene(s) before reloading?"
msgstr "새로고침하기 전에 해당 씬의 변경사항을 저장하시겠습니까?"
@@ -2698,6 +3311,9 @@ msgstr "최근 씬 지우기"
msgid "There is no defined scene to run."
msgstr "실행할 씬이 정의되지 않았습니다."
+msgid "%s - Godot Engine"
+msgstr "%s - Godot 엔진"
+
msgid ""
"No main scene has ever been defined, select one?\n"
"You can change it later in \"Project Settings\" under the 'application' "
@@ -2781,6 +3397,9 @@ msgstr "팬 보기"
msgid "Dock Position"
msgstr "독 위치"
+msgid "Make Floating"
+msgstr "창 띄우기"
+
msgid "Add a new scene."
msgstr "새 씬을 추가합니다."
@@ -2802,6 +3421,18 @@ msgstr "이전에 열었던 씬으로 이동합니다."
msgid "Copy Text"
msgstr "문자 복사"
+msgid "Next Scene Tab"
+msgstr "다음 씬 탭"
+
+msgid "Previous Scene Tab"
+msgstr "이전 씬 탭"
+
+msgid "Focus FileSystem Filter"
+msgstr "파일시스템 필터로 가기"
+
+msgid "Command Palette"
+msgstr "커맨드 팔레트"
+
msgid "New Scene"
msgstr "새 씬"
@@ -2820,6 +3451,9 @@ msgstr "최근 기록 열기"
msgid "Save Scene"
msgstr "씬 저장"
+msgid "Export As..."
+msgstr "다른 이름으로 내보내기..."
+
msgid "MeshLibrary..."
msgstr "메시 라이브러리..."
@@ -2835,6 +3469,9 @@ msgstr "프로젝트"
msgid "Project Settings..."
msgstr "프로젝트 설정..."
+msgid "Project Settings"
+msgstr "프로젝트 설정"
+
msgid "Version Control"
msgstr "버전 컨트롤"
@@ -2847,6 +3484,9 @@ msgstr "Android 빌드 템플릿 설치..."
msgid "Open User Data Folder"
msgstr "사용자 데이터 폴더 열기"
+msgid "Customize Engine Build Configuration..."
+msgstr "엔진 빌드 설정 커스터마이즈..."
+
msgid "Tools"
msgstr "툴"
@@ -2865,6 +3505,9 @@ msgstr "에디터"
msgid "Editor Settings..."
msgstr "에디터 설정..."
+msgid "Command Palette..."
+msgstr "커맨드 팔레트..."
+
msgid "Editor Layout"
msgstr "에디터 레이아웃"
@@ -2892,6 +3535,9 @@ msgstr "에디터 기능 관리..."
msgid "Manage Export Templates..."
msgstr "내보내기 템플릿 관리..."
+msgid "Configure FBX Importer..."
+msgstr "FBX 가져오기 설정..."
+
msgid "Help"
msgstr "도움말"
@@ -2904,6 +3550,12 @@ msgstr "질문과 답변"
msgid "Report a Bug"
msgstr "버그 보고"
+msgid "Copy System Info"
+msgstr "시스템 정보 복사"
+
+msgid "Copies the system info as a single-line text into the clipboard."
+msgstr "시스템 정보를 클립보드에 복사합니다."
+
msgid "Suggest a Feature"
msgstr "기능 제안"
@@ -2919,15 +3571,27 @@ msgstr "Godot 정보"
msgid "Support Godot Development"
msgstr "Godot 개발 지원"
+msgid "Choose a renderer."
+msgstr "렌더러를 선택하세요."
+
+msgid "Forward+"
+msgstr "Forward+"
+
msgid "Mobile"
msgstr "모바일"
msgid "Compatibility"
msgstr "호환성"
+msgid "Changing the renderer requires restarting the editor."
+msgstr "렌더러를 변경하려면 에디터를 다시 시작해야 합니다."
+
msgid "Update Continuously"
msgstr "상시 업데이트"
+msgid "Update When Changed"
+msgstr "변경되었을 때 업데이트"
+
msgid "Hide Update Spinner"
msgstr "업데이트 스피너 숨기기"
@@ -2940,6 +3604,9 @@ msgstr "인스펙터"
msgid "Node"
msgstr "노드"
+msgid "History"
+msgstr "작업 내역"
+
msgid "Expand Bottom Panel"
msgstr "아래쪽 패널 확장"
@@ -2958,6 +3625,25 @@ msgstr "템플릿 관리"
msgid "Install from file"
msgstr "파일에서 설치"
+msgid "Select Android sources file"
+msgstr "Android 소스 파일 선택"
+
+msgid ""
+"This will set up your project for gradle Android builds by installing the "
+"source template to \"res://android/build\".\n"
+"You can then apply modifications and build your own custom APK on export "
+"(adding modules, changing the AndroidManifest.xml, etc.).\n"
+"Note that in order to make gradle builds instead of using pre-built APKs, "
+"the \"Use Gradle Build\" option should be enabled in the Android export "
+"preset."
+msgstr ""
+"\"res://android/build\"에 소스 템플릿을 설치해서 프로젝트를 Gradle Android 빌"
+"드에 맞게 설정합니다.\n"
+"그런 다음 수정 사항을 적용하고 커스텀 APK를 빌드해서 내보낼 수 있습니다(모듈 "
+"추가, AndroidManifest.xml 변경 등).\n"
+"미리 빌드된 APK를 사용하는 대신 Gradle 빌드를 만들려면, Android 내보내기 프리"
+"셋에서 \"Gradle 빌드 사용\" 설정을 활성화해야 합니다."
+
msgid ""
"The Android build template is already installed in this project and it won't "
"be overwritten.\n"
@@ -2994,7 +3680,7 @@ msgid ""
"What action should be taken?"
msgstr ""
"다음 파일은 디스크에 있는 게 더 최신입니다.\n"
-"조치을 어떻게 취해야 합니까?"
+"어떻게 할까요?"
msgid "Reload"
msgstr "새로고침"
@@ -3002,6 +3688,12 @@ msgstr "새로고침"
msgid "Resave"
msgstr "다시 저장"
+msgid "Create Version Control Metadata"
+msgstr "버전 관리 메타데이터 생성"
+
+msgid "Version Control Settings"
+msgstr "버전 관리 설정"
+
msgid "New Inherited"
msgstr "새 상속 씬"
@@ -3044,6 +3736,9 @@ msgstr "플러그인 편집"
msgid "Installed Plugins:"
msgstr "설치된 플러그인:"
+msgid "Create New Plugin"
+msgstr "새 플러그인 만들기"
+
msgid "Version"
msgstr "버전"
@@ -3059,6 +3754,9 @@ msgstr "문자 편집:"
msgid "On"
msgstr "사용"
+msgid "Renaming layer %d:"
+msgstr "레이어 %d의 이름 변경:"
+
msgid "No name provided."
msgstr "이름을 제공하지 않았습니다."
@@ -3071,8 +3769,23 @@ msgstr "비트 %d, 값 %d"
msgid "Rename"
msgstr "이름 바꾸기"
+msgid "Rename layer"
+msgstr "레이어 이름 바꾸기"
+
+msgid "Layer %d"
+msgstr "레이어 %d"
+
+msgid "No Named Layers"
+msgstr "이름붙인 레이어 없음"
+
+msgid "Edit Layer Names"
+msgstr "레이어 이름 변경"
+
+msgid "<empty>"
+msgstr "<비어 있음>"
+
msgid "Temporary Euler may be changed implicitly!"
-msgstr "임시 오일러는 암시적으로 변경될 수 있습니다!"
+msgstr "임시 오일러가 암시적으로 변경되었을 수 있습니다!"
msgid ""
"Temporary Euler will not be stored in the object with the original value. "
@@ -3131,6 +3844,9 @@ msgstr "크기:"
msgid "Remove Item"
msgstr "항목 제거"
+msgid "Dictionary (Nil)"
+msgstr "딕셔너리 (Nil)"
+
msgid "Dictionary (size %d)"
msgstr "사전(크기 %d)"
@@ -3143,6 +3859,18 @@ msgstr "새 값:"
msgid "Add Key/Value Pair"
msgstr "키/값 쌍 추가"
+msgid "Localizable String (Nil)"
+msgstr "현지화할 수 있는 문자열 (Nil)"
+
+msgid "Localizable String (size %d)"
+msgstr "현지화할 수 있는 문자열 (개수 %d)"
+
+msgid "Add Translation"
+msgstr "번역 추가"
+
+msgid "Lock/Unlock Component Ratio"
+msgstr "성분 간 비율 잠금 설정/해제"
+
msgid ""
"The selected resource (%s) does not match any type expected for this "
"property (%s)."
@@ -3151,9 +3879,15 @@ msgstr "선택한 리소스(%s)가 이 속성(%s)에 적합한 모든 타입에
msgid "Quick Load"
msgstr "빠른 불러오기"
+msgid "Inspect"
+msgstr "자세히"
+
msgid "Make Unique"
msgstr "유일하게 만들기"
+msgid "Make Unique (Recursive)"
+msgstr "유일하게 만들기 (재귀적으로)"
+
msgid "Convert to %s"
msgstr "%s(으)로 변환"
@@ -3166,9 +3900,15 @@ msgstr "새 스크립트"
msgid "Extend Script"
msgstr "스크립트 상속"
+msgid "New Shader"
+msgstr "새 셰이더"
+
msgid "No Remote Debug export presets configured."
msgstr "원격 디버그 내보내기 프리셋이 구성되지 않았습니다."
+msgid "Remote Debug"
+msgstr "원격 디버그"
+
msgid ""
"No runnable export preset found for this platform.\n"
"Please add a runnable preset in the Export menu or define an existing preset "
@@ -3187,6 +3927,24 @@ msgstr "_run() 메서드에 당신의 논리를 작성하세요."
msgid "There is an edited scene already."
msgstr "이미 편집된 씬이 있습니다."
+msgid ""
+"Couldn't run editor script, did you forget to override the '_run' method?"
+msgstr ""
+"에디터 스크립트를 실행할 수 없습니다. '_run' 메서드를 오버라이딩하는 것을 잊"
+"으셨나요?"
+
+msgid "Undo: %s"
+msgstr "실행 취소: %s"
+
+msgid "Redo: %s"
+msgstr "다시 실행: %s"
+
+msgid "Edit Built-in Action"
+msgstr "내장 액션 편집"
+
+msgid "Edit Shortcut"
+msgstr "단축키 편집"
+
msgid "Common"
msgstr "일반"
@@ -3196,6 +3954,9 @@ msgstr "에디터 설정"
msgid "General"
msgstr "일반"
+msgid "Filter Settings"
+msgstr "설정 필터"
+
msgid "The editor must be restarted for changes to take effect."
msgstr "변경사항을 반영하려면 에디터를 다시 시작해야 합니다."
@@ -3265,6 +4026,15 @@ msgstr "조이스틱 4 업"
msgid "Joystick 4 Down"
msgstr "조이스틱 4 아래로"
+msgid "or"
+msgstr "또는"
+
+msgid "Unicode"
+msgstr "유니코드"
+
+msgid "Joypad Axis %d %s (%s)"
+msgstr "조이패드 축 %d %s (%s)"
+
msgid "All Devices"
msgstr "모든 기기"
@@ -3274,6 +4044,23 @@ msgstr "기기"
msgid "Listening for input..."
msgstr "입력 대기 중..."
+msgid "Filter by event..."
+msgstr "이벤트로 필터링..."
+
+msgid ""
+"Target platform requires 'ETC2/ASTC' texture compression. Enable 'Import "
+"ETC2 ASTC' in Project Settings."
+msgstr ""
+"대상 플랫폼에서 'ETC2/ASTC' 텍스처 압축이 필요합니다. 프로젝트 설정에서 "
+"'ETC2 ASTC 가져오기' 설정을 활성화하세요."
+
+msgid ""
+"Target platform requires 'S3TC/BPTC' texture compression. Enable 'Import "
+"S3TC BPTC' in Project Settings."
+msgstr ""
+"대상 플랫폼에서 'S3TC/BPTC' 텍스처 압축이 필요합니다. 프로젝트 설정에서 "
+"'S3TC BPTC 가져오기' 설정을 활성화하세요."
+
msgid "Project export for platform:"
msgstr "플랫폼용 프로젝트 내보내기:"
@@ -3284,13 +4071,19 @@ msgid "Completed successfully."
msgstr "성공적으로 완료되었습니다."
msgid "Failed."
-msgstr "실패함."
+msgstr "실패했습니다."
+
+msgid "Storing File: %s"
+msgstr "파일 저장: %s"
msgid "Storing File:"
msgstr "저장하려는 파일:"
msgid "No export template found at the expected path:"
-msgstr "예상 경로에서 내보내기 템플릿을 찾을 수 없습니다:"
+msgstr "예상한 경로에서 내보내기 템플릿을 찾을 수 없습니다:"
+
+msgid "ZIP Creation"
+msgstr "ZIP 생성"
msgid "Could not open file to read from path \"%s\"."
msgstr "경로 \"%s\"에서 파일을 열지 못했습니다."
@@ -3307,11 +4100,23 @@ msgstr "\"%s\" 파일을 생성할 수 없습니다."
msgid "Failed to export project files."
msgstr "프로젝트 파일을 내보낼 수 없습니다."
+msgid "Can't open file for writing at path \"%s\"."
+msgstr "\"%s\" 경로의 파일을 쓰기 모드로 열 수 없습니다."
+
+msgid "Can't open file for reading-writing at path \"%s\"."
+msgstr "\"%s\" 경로의 파일을 읽기-쓰기 모드로 열 수 없습니다."
+
+msgid "Can't create encrypted file."
+msgstr "암호화된 파일을 만들 수 없습니다."
+
+msgid "Can't open encrypted file to write."
+msgstr "암호화된 파일을 쓰기 위해 열 수 없습니다."
+
msgid "Can't open file to read from path \"%s\"."
msgstr "\"%s\" 경로의 파일을 읽기 위해 열지 못했습니다."
msgid "Save ZIP"
-msgstr "ZIP파일로 저장"
+msgstr "ZIP 파일로 저장"
msgid "Custom debug template not found."
msgstr "커스텀 디버그 템플릿을 찾을 수 없습니다."
@@ -3323,7 +4128,7 @@ msgid "Prepare Template"
msgstr "템플릿 준비"
msgid "The given export path doesn't exist."
-msgstr "Export하려고 했으나 해당 경로가 존재하지 않습니다."
+msgstr "주어진 내보내기 경로는 존재하지 않습니다."
msgid "Template file not found: \"%s\"."
msgstr "템플릿 파일을 찾을 수 없습니다: \"%s\"."
@@ -3365,7 +4170,7 @@ msgid "Can't connect to the mirror."
msgstr "미러에 연결할 수 없습니다."
msgid "No response from the mirror."
-msgstr "미러로부터 응담이 없습니다."
+msgstr "미러로부터 응답이 없습니다."
msgid "Request failed."
msgstr "요청에 실패했습니다."
@@ -3387,7 +4192,7 @@ msgid ""
"The problematic templates archives can be found at '%s'."
msgstr ""
"템플릿 설치에 실패했습니다.\n"
-"문제가 있는 템플릿 기록은 '%s'에서 찾아 볼 수 있습니다."
+"문제가 있는 템플릿의 압축 파일은 '%s'에서 찾아 볼 수 있습니다."
msgid "Error getting the list of mirrors."
msgstr "미러 목록을 가져오는 중 오류."
@@ -3396,7 +4201,7 @@ msgid "Error parsing JSON with the list of mirrors. Please report this issue!"
msgstr "미러 목록의 JSON 구문 분석 중 오류. 이 문제를 신고해주세요!"
msgid "Best available mirror"
-msgstr "최상의 사용 가능한 미러"
+msgstr "사용 가능한 최고의 미러"
msgid ""
"No download links found for this version. Direct download is only available "
@@ -3409,10 +4214,10 @@ msgid "Disconnected"
msgstr "연결 해제됨"
msgid "Resolving"
-msgstr "해결 중"
+msgstr "리졸브 중"
msgid "Can't Resolve"
-msgstr "해결할 수 없음"
+msgstr "리졸브할 수 없음"
msgid "Connecting..."
msgstr "연결 중..."
@@ -3432,6 +4237,9 @@ msgstr "다운로드 중"
msgid "Connection Error"
msgstr "연결 오류"
+msgid "TLS Handshake Error"
+msgstr "TLS 핸드셰이크 오류"
+
msgid "Can't open the export templates file."
msgstr "내보내기 템플릿 파일을 열 수 없습니다."
@@ -3497,7 +4305,8 @@ msgid ""
"Download and install templates for the current version from the best "
"possible mirror."
msgstr ""
-"최상의 가능한 미러에서 현재 버전을 위한 템플릿을 다운로드하고 설치합니다."
+"사용 가능한 최고의 미러에서 현재 버전을 위한 템플릿을 다운로드하고 설치합니"
+"다."
msgid "Official export templates aren't available for development builds."
msgstr "공식 내보내기 템플릿은 개발 빌드에서는 이용할 수 없습니다."
@@ -3541,12 +4350,21 @@ msgstr ""
"모든 사전 설정에는 모두 내보내기가 작동하도록 정의된 내보내기 경로가 있어야 "
"합니다."
+msgid "Resources to exclude:"
+msgstr "제외하는 리소스:"
+
msgid "Resources to export:"
msgstr "내보내는 리소스:"
msgid "Delete preset '%s'?"
msgstr "'%s' 프리셋을 삭제하시겠습니까?"
+msgid "(Inherited)"
+msgstr "(상속됨)"
+
+msgid "%s Export"
+msgstr "%s 내보내기"
+
msgid "Release"
msgstr "출시"
@@ -3570,7 +4388,7 @@ msgstr ""
"플랫폼 당 하나의 프리셋만 실행 가능하다고 표시될 것입니다."
msgid "Export Path"
-msgstr "경로 내보내기"
+msgstr "내보낼 경로"
msgid "Options"
msgstr "설정"
@@ -3587,6 +4405,9 @@ msgstr "선택한 씬 내보내기 (종속된 리소스 포함)"
msgid "Export selected resources (and dependencies)"
msgstr "선택한 리소스 내보내기 (종속된 리소스 포함)"
+msgid "Export all resources in the project except resources checked below"
+msgstr "체크한 리소스를 제외하고 프로젝트의 모든 리소스 내보내기"
+
msgid "Export as dedicated server"
msgstr "전용 서버로 내보내기"
@@ -3626,14 +4447,34 @@ msgstr "커스텀(쉼표로 구분):"
msgid "Feature List:"
msgstr "기능 목록:"
+msgid "Encryption"
+msgstr "암호화"
+
msgid "Encrypt Exported PCK"
msgstr "내보낸 PCK 암호화"
msgid "Encrypt Index (File Names and Info)"
msgstr "인덱스 암호화(파일 이름 및 정보)"
+msgid ""
+"Filters to include files/folders\n"
+"(comma-separated, e.g: *.tscn, *.tres, scenes/*)"
+msgstr ""
+"프로젝트에 포함할 파일/폴더 필터\n"
+"(쉼표로 구분, 예: *.tscn, *.tres, scenes/*)"
+
+msgid ""
+"Filters to exclude files/folders\n"
+"(comma-separated, e.g: *.ctex, *.import, music/*)"
+msgstr ""
+"프로젝트에서 제외할 파일/폴더 필터\n"
+"(쉼표로 구분, 예: *.ctex, *.import, music/*)"
+
msgid "Invalid Encryption Key (must be 64 hexadecimal characters long)"
-msgstr "잘못된 암호화 키 (길이가 16진수 형식의 64자이어야 합니다)"
+msgstr "잘못된 암호화 키 (16진수 형식이고 64글자여야 합니다)"
+
+msgid "Encryption Key (256-bits as hexadecimal):"
+msgstr "암호화 키 (16진수 형식으로 256-비트):"
msgid ""
"Note: Encryption key needs to be stored in the binary,\n"
@@ -3645,6 +4486,9 @@ msgstr ""
msgid "More Info..."
msgstr "추가 정보..."
+msgid "Export PCK/ZIP..."
+msgstr "PCK/ZIP 내보내기..."
+
msgid "Export Project..."
msgstr "프로젝트 내보내기..."
@@ -3675,12 +4519,37 @@ msgstr "내보내기 템플릿 관리"
msgid "Export With Debug"
msgstr "디버그와 함께 내보내기"
+msgid "Disable FBX & Restart"
+msgstr "FBX 비활성화 & 다시 시작"
+
+msgid ""
+"Canceling this dialog will disable the FBX importer.\n"
+"You can re-enable it in the Project Settings under Filesystem > Import > FBX "
+"> Enabled.\n"
+"\n"
+"The editor will restart as importers are registered when the editor starts."
+msgstr ""
+"취소하면 FBX 임포터를 비활성화할 것입니다.\n"
+"프로젝트 설정의 파일시스템 > 가져오기 > FBX > 활성화됨 에서 다시 활성화할 수 "
+"있습니다.\n"
+"\n"
+"임포터는 에디터가 새로 시작될 때 등록되기 때문에, 에디터를 재시작할 것입니다."
+
msgid "Path to FBX2glTF executable is empty."
msgstr "FBX2glTF 실행 파일 경로가 비어 있습니다."
+msgid "Path to FBX2glTF executable is invalid."
+msgstr "FBX2glTF 실행 파일 경로가 잘못되었습니다."
+
msgid "Error executing this file (wrong version or architecture)."
msgstr ""
-"이 파일을 실행하는 동안 오류가 발생했습니다(잘못된 버전 또는 아키텍처)."
+"이 파일을 실행하는 동안 오류가 발생했습니다 (잘못된 버전 또는 아키텍처)."
+
+msgid "FBX2glTF executable is valid."
+msgstr "FBX2glTF 실행 파일이 올바릅니다."
+
+msgid "Configure FBX Importer"
+msgstr "FBX 임포터 설정"
msgid ""
"FBX2glTF is required for importing FBX files.\n"
@@ -3695,6 +4564,9 @@ msgstr "이 링크를 클릭하여 FBX2glTF를 다운로드하세요"
msgid "Browse"
msgstr "검색"
+msgid "Confirm Path"
+msgstr "경로 확인"
+
msgid "Favorites"
msgstr "즐겨찾기"
@@ -3726,10 +4598,23 @@ msgstr "이동 중 오류:"
msgid "Error duplicating:"
msgstr "복제 중 오류:"
+msgid "Failed to save resource at %s: %s"
+msgstr "%s 에 리소스를 저장하지 못했습니다: %s"
+
+msgid "Failed to load resource at %s: %s"
+msgstr "%s 에서 리소스를 불러오지 못했습니다: %s"
+
msgid "Unable to update dependencies:"
msgstr "종속 항목을 업데이트할 수 없음:"
msgid ""
+"This filename begins with a dot rendering the file invisible to the editor.\n"
+"If you want to rename it anyway, use your operating system's file manager."
+msgstr ""
+"점(.)으로 시작하는 파일명은 편집기에서 보이지 않습니다.\n"
+"이름을 변경하려면 운영 체제의 파일 탐색기를 사용하십시오."
+
+msgid ""
"This file extension is not recognized by the editor.\n"
"If you want to rename it anyway, use your operating system's file manager.\n"
"After renaming to an unknown extension, the file won't be shown in the "
@@ -3742,14 +4627,25 @@ msgstr ""
msgid "A file or folder with this name already exists."
msgstr "이 이름은 이미 어떤 파일이나 폴더가 쓰고 있습니다."
+msgid ""
+"The following files or folders conflict with items in the target location "
+"'%s':"
+msgstr "다음 파일이나 폴더가 대상 위치 '%s'의 항목과 충돌합니다:"
+
+msgid "Do you wish to overwrite them or rename the copied files?"
+msgstr "이들을 덮어쓰시겠습니까, 아니면 복사된 파일의 이름을 바꾸시겠습니까?"
+
+msgid "Do you wish to overwrite them or rename the moved files?"
+msgstr "이들을 덮어쓰시겠습니까, 아니면 이동된 파일의 이름을 바꾸시겠습니까?"
+
msgid "Duplicating file:"
-msgstr "파일 복제:"
+msgstr "파일 복제 중:"
msgid "Duplicating folder:"
-msgstr "폴더 복제:"
+msgstr "폴더 복제 중:"
msgid "New Inherited Scene"
-msgstr "새 상속 씬"
+msgstr "새 상속된 씬"
msgid "Set As Main Scene"
msgstr "메인 씬으로 설정"
@@ -3757,12 +4653,45 @@ msgstr "메인 씬으로 설정"
msgid "Open Scenes"
msgstr "씬 열기"
+msgid "Instantiate"
+msgstr "인스턴스화하기"
+
msgid "Edit Dependencies..."
msgstr "종속 관계 편집..."
msgid "View Owners..."
msgstr "소유자 보기..."
+msgid "Create New"
+msgstr "새로 만들기"
+
+msgid "Folder..."
+msgstr "폴더..."
+
+msgid "Scene..."
+msgstr "씬..."
+
+msgid "Script..."
+msgstr "스크립트..."
+
+msgid "Resource..."
+msgstr "리소스..."
+
+msgid "TextFile..."
+msgstr "텍스트 파일..."
+
+msgid "Expand Folder"
+msgstr "폴더 펼치기"
+
+msgid "Expand Hierarchy"
+msgstr "계층 구조 펼치기"
+
+msgid "Collapse Hierarchy"
+msgstr "계층 구조 접기"
+
+msgid "Move/Duplicate To..."
+msgstr "다른 곳으로 이동/복제..."
+
msgid "Add to Favorites"
msgstr "즐겨찾기에 추가"
@@ -3784,6 +4713,12 @@ msgstr "새 스크립트..."
msgid "New Resource..."
msgstr "새 리소스..."
+msgid "New TextFile..."
+msgstr "새 텍스트 파일..."
+
+msgid "Sort Files"
+msgstr "파일 정렬"
+
msgid "Sort by Name (Ascending)"
msgstr "이름순 정렬 (오름차순)"
@@ -3805,18 +4740,33 @@ msgstr "처음으로 수정된 순서로 정렬"
msgid "Copy Path"
msgstr "경로 복사"
+msgid "Copy UID"
+msgstr "UID 복사"
+
msgid "Duplicate..."
msgstr "복제..."
msgid "Rename..."
msgstr "이름 바꾸기..."
+msgid "Open in External Program"
+msgstr "다른 프로그램에서 열기"
+
+msgid "Go to previous selected folder/file."
+msgstr "이전 파일/폴더로 이동합니다."
+
+msgid "Go to next selected folder/file."
+msgstr "다음 파일/폴더로 이동합니다."
+
msgid "Re-Scan Filesystem"
msgstr "파일시스템 다시 스캔"
msgid "Toggle Split Mode"
msgstr "분할 모드 토글"
+msgid "Filter Files"
+msgstr "파일 필터"
+
msgid ""
"Scanning Files,\n"
"Please Wait..."
@@ -3827,6 +4777,9 @@ msgstr ""
msgid "Overwrite"
msgstr "덮어 쓰기"
+msgid "Keep Both"
+msgstr "둘 다 유지"
+
msgid "Create Script"
msgstr "스크립트 만들기"
@@ -3861,9 +4814,21 @@ msgstr "바꾸기..."
msgid "Replace in Files"
msgstr "파일에서 바꾸기"
+msgid "Replace all (no undo)"
+msgstr "모두 바꾸기 (되돌릴 수 없음)"
+
msgid "Searching..."
msgstr "검색 중..."
+msgid "%d match in %d file"
+msgstr "%d개 매치가 %d개 파일 중 있음"
+
+msgid "%d matches in %d file"
+msgstr "%d개 매치가 %d개 파일 중 있음"
+
+msgid "%d matches in %d files"
+msgstr "%d개 매치가 %d개 파일 중 있음"
+
msgid "Add to Group"
msgstr "그룹에 추가"
@@ -3906,9 +4871,15 @@ msgstr "이동"
msgid "Please select a base directory first."
msgstr "먼저 기본 디렉토리를 선택해주세요."
+msgid "Could not create folder. File with that name already exists."
+msgstr "폴더를 만들 수 없습니다. 다른 파일이 이 이름을 이미 쓰고 있습니다."
+
msgid "Choose a Directory"
msgstr "디렉토리를 선택하세요"
+msgid "Copy File(s)"
+msgstr "파일 복사"
+
msgid "Network"
msgstr "네트워크"
@@ -4009,6 +4980,17 @@ msgstr "미리보기:"
msgid "File:"
msgstr "파일:"
+msgid ""
+"Remove the selected files? For safety only files and empty directories can "
+"be deleted from here. (Cannot be undone.)\n"
+"Depending on your filesystem configuration, the files will either be moved "
+"to the system trash or deleted permanently."
+msgstr ""
+"선택된 파일을 제거하시겠습니까? 안전을 위해, 여기서는 파일과 빈 디렉터리만 지"
+"울 수 있습니다. (되돌릴 수 없습니다.)\n"
+"파일시스템 구성에 따라, 파일은 시스템 휴지동으로 이동되거나 완전히 삭제됩니"
+"다."
+
msgid "No sub-resources found."
msgstr "하위 리소스를 찾을 수 없습니다."
@@ -4021,6 +5003,12 @@ msgstr "프로젝트를 실행합니다."
msgid "Play the edited scene."
msgstr "편집하고 있던 씬을 실행합니다."
+msgid "Play a custom scene."
+msgstr "특정한 씬을 실행합니다."
+
+msgid "Reload the played scene."
+msgstr "실행 중인 씬을 재시작합니다."
+
msgid "Quick Run Scene..."
msgstr "씬 빠른 실행..."
@@ -4040,17 +5028,38 @@ msgstr ""
"할 수 있습니다,\n"
"해당 장면을 녹화할 때 사용할 동영상 파일의 경로를 지정할 수 있습니다."
+msgid "Could not start subprocess(es)!"
+msgstr "하위 프로세스를 시작할 수 없습니다!"
+
msgid "Run the project's default scene."
msgstr "프로젝트의 기본 씬을 실행합니다."
msgid "Run Project"
msgstr "프로젝트 실행"
+msgid "Pause the running project's execution for debugging."
+msgstr "디버깅을 위해 현재 프로젝트를 일시 정지합니다."
+
+msgid "Pause Running Project"
+msgstr "프로젝트 일시 정지"
+
+msgid "Stop the currently running project."
+msgstr "현재 프로젝트를 정지합니다."
+
+msgid "Stop Running Project"
+msgstr "프로젝트 정지"
+
+msgid "Run the currently edited scene."
+msgstr "편집하고 있는 씬을 실행합니다."
+
+msgid "Run Current Scene"
+msgstr "현재 씬 실행"
+
msgid "Run a specific scene."
-msgstr "특정 장면을 실행합니다."
+msgstr "특정 씬을 실행합니다."
msgid "Run Specific Scene"
-msgstr "특정 장면 실행"
+msgstr "특정 씬 실행"
msgid ""
"Enable Movie Maker mode.\n"
@@ -4061,6 +5070,22 @@ msgstr ""
"프로젝트가 안정적인 FPS로 실행되고 시각 및 오디오 출력이 비디오 파일로 녹화됩"
"니다."
+msgid ""
+"Hold %s to round to integers.\n"
+"Hold Shift for more precise changes."
+msgstr ""
+"정수로 반올림하려면 %s 키를 누르세요.\n"
+"정밀한 변경을 하려면 Shift 키를 누르세요."
+
+msgid "No notifications."
+msgstr "알림이 없습니다."
+
+msgid "Show notifications."
+msgstr "알림을 보여줍니다."
+
+msgid "Silence the notifications."
+msgstr "알림을 숨깁니다."
+
msgid "Toggle Visible"
msgstr "보이기 토글"
@@ -4096,9 +5121,18 @@ msgid "Node is in this group:"
msgid_plural "Node is in the following groups:"
msgstr[0] "노드가 다음 그룹에 속해 있습니다:"
+msgid "Click to show signals dock."
+msgstr "클릭하여 시그널 독을 봅니다."
+
msgid "Open in Editor"
msgstr "에디터에서 열기"
+msgid "This script is currently running in the editor."
+msgstr "이 스크립트는 에디터에서 실행되고 있습니다."
+
+msgid "This script is a custom type."
+msgstr "이 스크립트는 커스텀 타입입니다."
+
msgid "Open Script:"
msgstr "스크립트 열기:"
@@ -4110,12 +5144,22 @@ msgstr ""
"클릭하면 잠금을 해제합니다."
msgid ""
+"Children are not selectable.\n"
+"Click to make them selectable."
+msgstr ""
+"자식을 선택할 수 없습니다.\n"
+"클릭하면 선택할 수 있습니다."
+
+msgid ""
"AnimationPlayer is pinned.\n"
"Click to unpin."
msgstr ""
"AnimationPlayer가 고정되어 있습니다.\n"
"클릭하면 고정을 해제합니다."
+msgid "\"%s\" is not a known filter."
+msgstr "\"%s\"는 알 수 없는 필터입니다."
+
msgid "Invalid node name, the following characters are not allowed:"
msgstr "잘못된 노드 이름입니다. 다음 문자는 허용하지 않습니다:"
@@ -4132,11 +5176,20 @@ msgid "Select a Node"
msgstr "노드를 선택하세요"
msgid "The Beginning"
-msgstr "시작"
+msgstr "시작점"
+
+msgid "Global"
+msgstr "전역"
+
+msgid "Audio Stream Importer: %s"
+msgstr "오디오 스트림 임포터: %s"
msgid "Reimport"
msgstr "다시 가져오기"
+msgid "Enable looping."
+msgstr "루핑을 활성화합니다."
+
msgid "Offset:"
msgstr "오프셋:"
@@ -4145,6 +5198,9 @@ msgid ""
"ignored."
msgstr "루프 오프셋(시작부터). BPM이 설정되어 있으면 이 설정은 무시됩니다."
+msgid "Loop:"
+msgstr "루프:"
+
msgid "BPM:"
msgstr "BPM:"
@@ -4152,35 +5208,49 @@ msgid ""
"Configure the Beats Per Measure (tempo) used for the interactive streams.\n"
"This is required in order to configure beat information."
msgstr ""
-"인터랙티브 스트림에 사용되는 박자당 비트 수(템포)를 구성합니다.\n"
+"인터랙티브한 스트림에 사용되는 BPM(템포)를 구성합니다.\n"
"이는 비트 정보를 구성하기 위해 필요합니다."
+msgid "Beat Count:"
+msgstr "비트 수:"
+
msgid ""
"Configure the amount of Beats used for music-aware looping. If zero, it will "
"be autodetected from the length.\n"
"It is recommended to set this value (either manually or by clicking on a "
"beat number in the preview) to ensure looping works properly."
msgstr ""
-"음악 인식 루핑에 사용되는 비트의 양을 구성합니다. 0이면 길이에서 자동 감지됩"
-"니다.\n"
-"루핑이 제대로 작동하도록 하려면 이 값을 수동으로 설정하거나 미리보기에서 비"
-"트 번호를 클릭하여 설정하는 것이 좋습니다."
+"음악적인 루핑에 사용되는 비트의 양을 구성합니다. 0이면 길이에서 자동 감지됩니"
+"다.\n"
+"루핑이 제대로 작동하도록 하려면 이 값을 수동으로 또는 미리보기에서 비트 번호"
+"를 클릭하여 제대로 설정하는 것이 좋습니다."
msgid "Bar Beats:"
-msgstr "바 비트:"
+msgstr "마디당 비트:"
msgid ""
"Configure the Beats Per Bar. This used for music-aware transitions between "
"AudioStreams."
-msgstr "바당 비트를 구성합니다. 오디오스트림 간 음악 인식 전환에 사용됩니다."
+msgstr ""
+"마디당 비트를 구성합니다. 오디오스트림 사이를 음악적으로 전환할 때 사용됩니"
+"다."
+
+msgid "Music Playback:"
+msgstr "음악 재생:"
+
+msgid "New Configuration"
+msgstr "새 설정"
+
+msgid "Remove Variation"
+msgstr "바리에이션 제거"
msgid "Preloaded glyphs: %d"
-msgstr "미리 로드된 글리프: %d"
+msgstr "미리 로드할 글리프: %d"
msgid ""
"Warning: There are no configurations specified, no glyphs will be pre-"
"rendered."
-msgstr "경고: 지정된 구성이 없으며 글리프가 미리 렌더링되지 않습니다."
+msgstr "경고: 지정된 구성이 없으며 어떤 글리프도 미리 렌더링하지 않습니다."
msgid ""
"Warning: Multiple configurations have identical settings. Duplicates will be "
@@ -4198,30 +5268,45 @@ msgid ""
"Note: Subpixel positioning is selected, each of the glyphs might be pre-"
"rendered for multiple subpixel offsets (up to 4x)."
msgstr ""
-"참고: 서브픽셀 위치 지정이 선택되면 각 글리프는 여러 서브픽셀 오프셋(최대 4"
-"배)에 대해 미리 렌더링될 수 있습니다."
+"참고: 서브픽셀 위치 지정을 선택하면 여러 서브픽셀 오프셋(최대 4배)에 대해 각 "
+"글리프가 미리 렌더링될 수도 있습니다."
msgid "Advanced Import Settings for '%s'"
msgstr "'%s'에 대한 고급 가져오기 설정"
+msgid "Rendering Options"
+msgstr "렌더링 설정"
+
msgid "Select font rendering options, fallback font, and metadata override:"
msgstr "글꼴 렌더링 옵션, 대체 글꼴 및 메타데이터 재정의 옵션을 선택합니다:"
msgid "Pre-render Configurations"
-msgstr "프리렌더 설정"
+msgstr "프리렌더링 설정"
msgid ""
"Add font size, and variation coordinates, and select glyphs to pre-render:"
msgstr "글꼴 크기와 변형 좌표를 추가하고 미리 렌더링할 글리프를 선택합니다:"
+msgid "Configuration:"
+msgstr "설정:"
+
+msgid "Add configuration"
+msgstr "설정 추가"
+
+msgid "Clear Glyph List"
+msgstr "글리프 목록 지우기"
+
+msgid "Glyphs from the Translations"
+msgstr "번역에서 글리프 가져오기"
+
msgid "Select translations to add all required glyphs to pre-render list:"
msgstr "번역을 선택하여 필요한 모든 글리프를 사전 렌더링 목록에 추가합니다:"
msgid "Shape all Strings in the Translations and Add Glyphs"
-msgstr "번역에서 모든 문자열 모양 만들기 및 글리프 추가하기"
+msgstr "번역의 모든 문자열 모양 및 글리프 추가"
msgid "Glyphs from the Text"
-msgstr "텍스트의 글리프"
+msgstr "텍스트에서 글리프 가져오기"
msgid ""
"Enter a text and select OpenType features to shape and add all required "
@@ -4231,10 +5316,10 @@ msgstr ""
"를 사전 렌더링 목록에 추가합니다:"
msgid "Shape Text and Add Glyphs"
-msgstr "텍스트 모양 및 글리프 추가"
+msgstr "텍스트에서 모양 및 글리프 추가"
msgid "Glyphs from the Character Map"
-msgstr "캐릭터 맵의 문양"
+msgstr "문자 맵에서 글리프 선택하기"
msgid ""
"Add or remove glyphs from the character map to pre-render list:\n"
@@ -4242,15 +5327,15 @@ msgid ""
"correspondence to character, and not shown in this map, use \"Glyphs from "
"the text\" tab to add these."
msgstr ""
-"문자 맵에서 사전 렌더링 목록에 글리프를 추가하거나 제거합니다:\n"
-"참고: 일부 문체 대체 및 글리프 변형은 문자와 일대일 대응이 없으며 이 맵에 표"
-"시되지 않으므로 '텍스트의 글리프' 탭을 사용하여 추가할 수 있습니다."
+"문자 맵으로부터 사전 렌더링 목록에 글리프를 추가하거나 제거합니다:\n"
+"참고: 일부 문체 대체 및 글리프 변형은 문자와 일대일 대응이 없으며, 이 맵에 표"
+"시되지 않으므로 '텍스트 내의 글리프' 탭을 사용하여 추가할 수 있습니다."
msgid "Dynamically rendered TrueType/OpenType font"
msgstr "동적으로 렌더링된 트루타입/오픈타입 글꼴"
msgid "Prerendered multichannel(+true) signed distance field"
-msgstr "미리 렌더링된 다중 채널(+true) 부호화된 거리 필드"
+msgstr "미리 렌더링된 다중 채널(+true) 부호 있는 거리 필드 (Multichannel SDF)"
msgid "Can't load font texture:"
msgstr "글꼴 텍스처를 로드할 수 없습니다:"
@@ -4261,6 +5346,9 @@ msgstr "이미지 여백이 너무 큽니다."
msgid "Character margin too bit."
msgstr "문자 여백이 너무 큽니다."
+msgid "Pre-Import Scene"
+msgstr "씬 미리 가져오기"
+
msgid "Importing Scene..."
msgstr "씬 가져오는 중..."
@@ -4279,6 +5367,10 @@ msgstr "post-impot용 스크립트가 잘못되거나 망가짐 (콘솔을 확
msgid "Error running post-import script:"
msgstr "post-import 스크립트 실행 중 오류:"
+msgid "Did you return a Node-derived object in the `_post_import()` method?"
+msgstr ""
+"`_post_import()` 메서드에서 Node에서 상속받은 오브젝트를 반환하셨습니까?"
+
msgid "Saving..."
msgstr "저장 중..."
@@ -4294,7 +5386,21 @@ msgid ""
"texture compression to reduce memory usage (blue channel is discarded)."
msgstr ""
"%s: 텍스처가 3D에서 노멀 맵으로 사용되는 것으로 감지되었습니다. 메모리 사용량"
-"을 줄이기 위해 빨강-초록 텍스처 압축을 활성화합니다(파란색 채널은 버려짐)."
+"을 줄이기 위해 빨강-초록 텍스처 압축을 활성화합니다(파랑 채널은 버려짐)."
+
+msgid ""
+"%s: Texture detected as used as a roughness map in 3D. Enabling roughness "
+"limiter based on the detected associated normal map at %s."
+msgstr ""
+"%s: 텍스처가 3D에서 굵기 맵으로 사용되는 것으로 감지되었습니다. %s에서 감지"
+"한 연관된 노멀 맵을 기반으로 굵기 제한을 적용합니다."
+
+msgid ""
+"%s: Texture detected as used in 3D. Enabling mipmap generation and setting "
+"the texture compression mode to %s."
+msgstr ""
+"%s: 텍스처가 3D에서 사용된 것으로 감지되었습니다. 밉맵 생성을 활성화하고 텍스"
+"처 압축 모드를 %s 로 설정합니다."
msgid "2D/3D (Auto-Detect)"
msgstr "2D/3D(자동 감지)"
@@ -4305,6 +5411,12 @@ msgstr "2D"
msgid "3D"
msgstr "3D"
+msgid "<Unnamed Material>"
+msgstr "<이름 없는 머티리얼>"
+
+msgid "Import ID: %s"
+msgstr "가져오기 ID: %s"
+
msgid ""
"Type: %s\n"
"Import ID: %s"
@@ -4312,21 +5424,36 @@ msgstr ""
"유형: %s\n"
"가져오기 ID: %s"
+msgid "Error opening scene"
+msgstr "씬 여는 중 오류"
+
msgid "Advanced Import Settings for AnimationLibrary '%s'"
msgstr "애니메이션 라이브러리 '%s'에 대한 고급 가져오기 설정"
msgid "Advanced Import Settings for Scene '%s'"
msgstr "씬 '%s'에 대한 고급 가져오기 설정"
+msgid "Select folder to extract material resources"
+msgstr "머티리얼 리소스를 내보낼 폴더를 선택합니다"
+
msgid "Select folder where mesh resources will save on import"
-msgstr "임포트 시 메시 리소스를 저장할 폴더를 선택합니다"
+msgstr "가져오기 시 메시 리소스를 저장할 폴더를 선택합니다"
msgid "Select folder where animations will save on import"
msgstr "가져오기 시 애니메이션을 저장할 폴더를 선택합니다"
+msgid "Warning: File exists"
+msgstr "주의: 파일 이미 존재함"
+
msgid "Existing file with the same name will be replaced."
msgstr "같은 이름의 기존 파일은 대체됩니다."
+msgid "Will create new file"
+msgstr "새로운 파일을 만듭니다"
+
+msgid "Already External"
+msgstr "이미 외부임"
+
msgid ""
"This material already references an external file, no action will be taken.\n"
"Disable the external property for it to be extracted again."
@@ -4334,6 +5461,9 @@ msgstr ""
"이 자료는 이미 외부 파일을 참조하고 있으므로 아무 조치도 취해지지 않습니다.\n"
"외부 속성을 비활성화하면 다시 추출할 수 있습니다."
+msgid "No import ID"
+msgstr "가져오기 ID 없음"
+
msgid ""
"Material has no name nor any other way to identify on re-import.\n"
"Please name it or ensure it is exported with an unique ID."
@@ -4344,6 +5474,12 @@ msgstr ""
msgid "Extract Materials to Resource Files"
msgstr "리소스 파일로 자료 추출"
+msgid "Extract"
+msgstr "추출"
+
+msgid "Already Saving"
+msgstr "이미 저장됨"
+
msgid ""
"This mesh already saves to an external resource, no action will be taken."
msgstr ""
@@ -4352,6 +5488,9 @@ msgstr ""
msgid "Existing file with the same name will be replaced on import."
msgstr "가져오기 시 같은 이름의 기존 파일이 대체됩니다."
+msgid "Will save to new file"
+msgstr "새 파일에 저장됨"
+
msgid ""
"Mesh has no name nor any other way to identify on re-import.\n"
"Please name it or ensure it is exported with an unique ID."
@@ -4360,7 +5499,10 @@ msgstr ""
"이름을 지정하거나 고유 ID로 내보내야 합니다."
msgid "Set paths to save meshes as resource files on Reimport"
-msgstr "리임포트 시 메시를 리소스 파일로 저장할 경로 설정"
+msgstr "다시 가져오기 시 메시를 리소스 파일로 저장할 경로 설정"
+
+msgid "Set Paths"
+msgstr "경로 설정"
msgid ""
"This animation already saves to an external resource, no action will be "
@@ -4369,9 +5511,21 @@ msgstr ""
"이 애니메이션은 이미 외부 리소스에 저장되어 있으므로 아무 작업도 수행되지 않"
"습니다."
+msgid "Set paths to save animations as resource files on Reimport"
+msgstr "다시 가져오기 시 애니메이션을 리소스 파일로 저장할 경로 설정"
+
msgid "Can't make material external to file, write error:"
msgstr "자료를 파일 외부로 만들 수 없음, 쓰기 오류가 발생했습니다:"
+msgid "Actions..."
+msgstr "액션..."
+
+msgid "Extract Materials"
+msgstr "머티리얼 추출"
+
+msgid "Set Animation Save Paths"
+msgstr "애니메이션 저장 경로 설정"
+
msgid "Set Mesh Save Paths"
msgstr "메시 저장 경로 설정"
@@ -4381,6 +5535,21 @@ msgstr "메쉬"
msgid "Materials"
msgstr "머티리얼"
+msgid "Save Extension:"
+msgstr "저장할 확장자:"
+
+msgid "Text: *.tres"
+msgstr "텍스트: *.tres"
+
+msgid "Binary: *.res"
+msgstr "바이너리: *.res"
+
+msgid "Text Resource"
+msgstr "텍스트 리소스"
+
+msgid "Binary Resource"
+msgstr "바이너리 리소스"
+
msgid "Select Importer"
msgstr "임포터 선택"
@@ -4416,6 +5585,9 @@ msgstr "다음으로 가져오기:"
msgid "Preset"
msgstr "프리셋"
+msgid "Advanced..."
+msgstr "고급..."
+
msgid "Save Scenes, Re-Import, and Restart"
msgstr "장면 저장, 다시 가져오기 및 재시작"
@@ -4441,18 +5613,65 @@ msgstr "구성된 이벤트 없음"
msgid "Keyboard Keys"
msgstr "키보드 키"
+msgid "Mouse Buttons"
+msgstr "마우스 버튼"
+
+msgid "Joypad Buttons"
+msgstr "조이패드 버튼"
+
+msgid "Joypad Axes"
+msgstr "조이패드 축"
+
+msgid "Event Configuration"
+msgstr "이벤트 설정"
+
+msgid "Manual Selection"
+msgstr "수동 지정"
+
+msgid "Filter Inputs"
+msgstr "입력 필터"
+
+msgid "Additional Options"
+msgstr "추가 설정"
+
msgid "Device:"
msgstr "기기:"
+msgid "Command / Control (auto)"
+msgstr "Cmd / Ctrl (자동)"
+
msgid ""
"Automatically remaps between 'Meta' ('Command') and 'Control' depending on "
"current platform."
msgstr ""
-"현재 플랫폼에 따라 '메타'('명령어')와 '제어' 사이를 자동으로 리매핑합니다."
+"현재 플랫폼에 따라 '메타'('커맨드')와 '컨트롤' 사이를 자동으로 재지정합니다."
+
+msgid "Keycode (Latin Equivalent)"
+msgstr "키코드 (라틴 기준)"
+
+msgid "Physical Keycode (Position on US QWERTY Keyboard)"
+msgstr "물리적 키코드 (US QWERTY 키보드에서의 위치)"
+
+msgid "Key Label (Unicode, Case-Insensitive)"
+msgstr "키 라벨 (유니코드, 대소문자 미구분)"
+
+msgid ""
+"The following resources will be duplicated and embedded within this resource/"
+"object."
+msgstr "아래의 리소스를 복제한 뒤 이 리소스/오브젝트에 포함할 것입니다."
+
+msgid "This object has no resources."
+msgstr "이 오브젝트에는 아무 리소스도 없습니다."
msgid "Failed to load resource."
msgstr "리소스를 불러오지 못했습니다."
+msgid "(Current)"
+msgstr "(현재)"
+
+msgid "Expand Non-Default"
+msgstr "기본값 아닌 값 펼치기"
+
msgid "Property Name Style"
msgstr "속성 이름 스타일"
@@ -4478,7 +5697,7 @@ msgid "Make Sub-Resources Unique"
msgstr "하위 리소스를 유일하게 만들기"
msgid "Create a new resource in memory and edit it."
-msgstr "새 리소스를 메모리에서 만들고 편집합니다."
+msgstr "메모리 내에서 새 리소스를 만들고 편집합니다."
msgid "Load an existing resource from disk and edit it."
msgstr "디스크에서 기존 리소스를 불러오고 편집합니다."
@@ -4490,7 +5709,7 @@ msgid "Save As..."
msgstr "다른 이름으로 저장..."
msgid "Extra resource options."
-msgstr "별도의 리소스 옵션."
+msgstr "다른 리소스 옵션입니다."
msgid "Edit Resource from Clipboard"
msgstr "클립보드에서 리소스 편집"
@@ -4501,15 +5720,27 @@ msgstr "리소스 복사"
msgid "Make Resource Built-In"
msgstr "리소스를 내장으로 만들기"
+msgid "Go to previous edited object in history."
+msgstr "작업 내역상 이전에 편집했던 오브젝트로 이동합니다."
+
+msgid "Go to next edited object in history."
+msgstr "작업 내역상 다음에 편집했던 오브젝트로 이동합니다."
+
msgid "History of recently edited objects."
msgstr "최근에 편집한 오브젝트 기록입니다."
msgid "Open documentation for this object."
-msgstr "이 오브젝트를 위한 문서를 엽니다."
+msgstr "이 오브젝트의 문서를 엽니다."
+
+msgid "Filter Properties"
+msgstr "속성 필터"
msgid "Manage object properties."
msgstr "오브젝트 속성을 관리합니다."
+msgid "This cannot be undone. Are you sure?"
+msgstr "이 활동은 되돌릴 수 없습니다. 확실하십니까?"
+
msgid "Add %d Translations"
msgstr "번역 %d개 추가"
@@ -4531,6 +5762,18 @@ msgstr "리소스 리맵핑 제거"
msgid "Remove Resource Remap Option"
msgstr "리소스 리맵핑 옵션 제거"
+msgid "Add %d file(s) for POT generation"
+msgstr "POT 생성에 %d개 파일을 추가"
+
+msgid "Remove file from POT generation"
+msgstr "POT 생성에서 파일을 제거"
+
+msgid "Removed"
+msgstr "제거됨"
+
+msgid "%s cannot be found."
+msgstr "%s 을(를) 찾을 수 없습니다."
+
msgid "Translations"
msgstr "번역"
@@ -4547,11 +5790,38 @@ msgid "Remaps by Locale:"
msgstr "로케일에 따른 리맵핑:"
msgid "Locale"
-msgstr "위치"
+msgstr "로케일"
+
+msgid "POT Generation"
+msgstr "POT 생성"
+
+msgid "Files with translation strings:"
+msgstr "번역 문자열이 있는 파일:"
+
+msgid "Generate POT"
+msgstr "POT 생성"
+
+msgid "Set %s on %d nodes"
+msgstr "%s를 %d개 노드에 설정"
+
+msgid "%s (%d Selected)"
+msgstr "%s (%d개 선택됨)"
msgid "Select a single node to edit its signals and groups."
msgstr "시그널과 그룹을 편집할 단일 노드를 선택하세요."
+msgid "Plugin name cannot be blank."
+msgstr "플러그인 이름이 비어 있습니다."
+
+msgid "Script extension must match chosen language extension (.%s)."
+msgstr "스크립트 확장은 반드시 지정된 언어 확장자와 일치해야 합니다 (.%s)."
+
+msgid "Subfolder name is not a valid folder name."
+msgstr "서브폴더 이름이 올바른 폴더명이 아닙니다."
+
+msgid "Subfolder cannot be one which already exists."
+msgstr "이미 존재하는 서브폴더를 사용할 수 없습니다."
+
msgid "Edit a Plugin"
msgstr "플러그인 편집"
@@ -4621,9 +5891,15 @@ msgstr "불러오기..."
msgid "Move Node Point"
msgstr "노드 점 이동"
+msgid "Change BlendSpace1D Config"
+msgstr "BlendSpace1D 속성 바꾸기"
+
msgid "Change BlendSpace1D Labels"
msgstr "BlendSpace1D 라벨 바꾸기"
+msgid "This type of node can't be used. Only animation nodes are allowed."
+msgstr "이 타입의 노드를 사용할 수 없습니다. 애니메이션 노드만 쓸 수 있습니다."
+
msgid "This type of node can't be used. Only root nodes are allowed."
msgstr "이 타입의 노드를 사용할 수 없습니다. 루트 노드만 쓸 수 있습니다."
@@ -4656,6 +5932,9 @@ msgstr "점을 선택하고 이동합니다. 우클릭으로 점을 만드세요
msgid "Enable snap and show grid."
msgstr "스냅을 활성화하고 격자를 보이게 합니다."
+msgid "Sync:"
+msgstr "동기화:"
+
msgid "Blend:"
msgstr "혼합:"
@@ -4674,6 +5953,9 @@ msgstr "삼각형이 이미 있습니다."
msgid "Add Triangle"
msgstr "삼각형 추가"
+msgid "Change BlendSpace2D Config"
+msgstr "BlendSpace2D 속성 바꾸기"
+
msgid "Change BlendSpace2D Labels"
msgstr "BlendSpace2D 라벨 바꾸기"
@@ -4701,6 +5983,9 @@ msgstr "(수동 대신) 자동으로 혼합 삼각형 만들기"
msgid "Parameter Changed:"
msgstr "매개변수 변경됨:"
+msgid "Inspect Filters"
+msgstr "필터 인스펙트"
+
msgid "Output node can't be added to the blend tree."
msgstr "출력 노드를 혼합 트리에 추가할 수 없습니다."
@@ -4759,6 +6044,9 @@ msgstr "오디오 클립"
msgid "Functions"
msgstr "함수(Function)"
+msgid "Inspect Filtered Tracks:"
+msgstr "필터 트랙 인스펙트:"
+
msgid "Edit Filtered Tracks:"
msgstr "필터 트랙 편집:"
@@ -4771,39 +6059,175 @@ msgstr "노드 추가..."
msgid "Enable Filtering"
msgstr "필터 활성화"
+msgid "Library Name:"
+msgstr "라이브러리 이름:"
+
msgid "Animation name can't be empty."
msgstr "애니메이션 이름은 비워둘 수 없습니다."
+msgid "Animation name contains invalid characters: '/', ':', ',' or '['."
+msgstr "애니메이션 이름에 잘못된 문자가 있습니다: '/', ':', ',', '['."
+
+msgid "Animation with the same name already exists."
+msgstr "이 이름으로 된 애니메이션이 이미 있습니다."
+
+msgid "Enter a library name."
+msgstr "라이브러리 이름을 입력하세요."
+
+msgid "Library name contains invalid characters: '/', ':', ',' or '['."
+msgstr "라이브러리 이름에 잘못된 문자가 있습니다: '/', ':', ',', '['."
+
+msgid "Library with the same name already exists."
+msgstr "이 이름으로 된 라이브러리가 이미 있습니다."
+
+msgid "Animation name is valid."
+msgstr "애니메이션 이름이 올바릅니다."
+
+msgid "Global library will be created."
+msgstr "전역 라이브러리가 생성될 것입니다."
+
+msgid "Library name is valid."
+msgstr "라이브러리 이름이 올바릅니다."
+
+msgid "Add Animation to Library: %s"
+msgstr "라이브러리에 애니메이션 추가: %s"
+
+msgid "Add Animation Library: %s"
+msgstr "애니메이션 라이브러리 추가: %s"
+
msgid "Load Animation"
msgstr "애니메이션 불러오기"
+msgid ""
+"This animation library can't be saved because it does not belong to the "
+"edited scene. Make it unique first."
+msgstr ""
+"이 애니메이션 라이브러리는 편집 중인 씬에 속한 것이 아니라서 저장할 수 없습니"
+"다. 저장하기 전에 먼저 리소스를 유일하게 만드세요."
+
+msgid ""
+"This animation library can't be saved because it was imported from another "
+"file. Make it unique first."
+msgstr ""
+"이 애니메이션 라이브러리는 다른 파일에서 가져왔기 때문에 저장할 수 없습니다. "
+"저장하기 전에 먼저 리소스를 유일하게 만드세요."
+
+msgid "Save Library"
+msgstr "라이브러리 저장"
+
+msgid "Make Animation Library Unique: %s"
+msgstr "애니메이션 라이브러리 유일하게 만들기: %s"
+
+msgid ""
+"This animation can't be saved because it does not belong to the edited "
+"scene. Make it unique first."
+msgstr ""
+"이 애니메이션은 편집 중인 씬에 속한 것이 아니라서 저장할 수 없습니다. 저장하"
+"기 전에 먼저 리소스를 유일하게 만드세요."
+
+msgid ""
+"This animation can't be saved because it was imported from another file. "
+"Make it unique first."
+msgstr ""
+"이 애니메이션은 다른 파일에서 가져왔기 때문에 저장할 수 없습니다. 저장하기 전"
+"에 먼저 리소스를 유일하게 만드세요."
+
+msgid "Save Animation"
+msgstr "애니메이션 저장"
+
+msgid "Make Animation Unique: %s"
+msgstr "애니메이션 유일하게 만들기: %s"
+
msgid "Invalid AnimationLibrary file."
msgstr "잘못된 AnimationLibrary 파일입니다."
+msgid "This library is already added to the player."
+msgstr "이 라이브러리는 이미 플레이어에 추가되었습니다."
+
msgid "Invalid Animation file."
msgstr "잘못된 애니메이션 파일입니다."
+msgid "This animation is already added to the library."
+msgstr "이 애니메이션은 이미 라이브러리에 추가되었습니다."
+
+msgid "Load Animation into Library: %s"
+msgstr "애니메이션을 라이브러리에 불러오기: %s"
+
+msgid "Save Animation library to File: %s"
+msgstr "애니메이션 라이브러리를 파일에 저장: %s"
+
+msgid "Save Animation to File: %s"
+msgstr "애니메이션을 파일에 저장: %s"
+
+msgid "Rename Animation Library: %s"
+msgstr "애니메이션 라이브러리 이름 바꾸기: %s"
+
+msgid "[Global]"
+msgstr "[전역]"
+
+msgid "Rename Animation: %s"
+msgstr "애니메이션 이름 바꾸기: %s"
+
msgid "Animation Name:"
msgstr "애니메이션 이름:"
+msgid "No animation resource in clipboard!"
+msgstr "클립보드에 애니메이션 리소스가 없습니다!"
+
msgid "Pasted Animation"
msgstr "붙여 넣은 애니메이션"
msgid "Open in Inspector"
msgstr "인스펙터에서 열기"
+msgid "Remove Animation Library: %s"
+msgstr "애니메이션 라이브러리 제거: %s"
+
+msgid "Remove Animation from Library: %s"
+msgstr "애니메이션을 라이브러리에서 제거: %s"
+
+msgid "[built-in]"
+msgstr "[내장]"
+
+msgid "[foreign]"
+msgstr "[외부]"
+
+msgid "[imported]"
+msgstr "[가져옴]"
+
+msgid "Add Animation to Library"
+msgstr "애니메이션을 라이브러리에 추가"
+
+msgid "Load animation from file and add to library"
+msgstr "애니메이션을 파일에서 가져온 뒤 라이브러리에 추가"
+
msgid "Paste Animation to Library from clipboard"
msgstr "애니메이션을 클립보드에서 라이브러리로 붙여넣기"
msgid "Save animation library to resource on disk"
msgstr "애니메이션 라이브러리를 디스크에 리소스로 저장"
+msgid "Remove animation library"
+msgstr "애니메이션 라이브러리 제거"
+
msgid "Copy animation to clipboard"
msgstr "애니메이션을 클립보드에 복사"
msgid "Save animation to resource on disk"
msgstr "애니메이션을 디스크에 리소스로 저장"
+msgid "Remove animation from Library"
+msgstr "애니메이션을 라이브러리에서 제거"
+
+msgid "Edit Animation Libraries"
+msgstr "애니메이션 라이브러리 편집"
+
+msgid "Add Library"
+msgstr "라이브러리 추가"
+
+msgid "Load Library"
+msgstr "라이브러리 가져오기"
+
msgid "Storage"
msgstr "보관소"
@@ -4822,12 +6246,18 @@ msgstr "애니메이션 이름 바꾸기"
msgid "Change Animation Name:"
msgstr "애니메이션 이름 바꾸기:"
+msgid "Delete Animation '%s'?"
+msgstr "애니메이션 '%s'을(를) 삭제할까요?"
+
msgid "Remove Animation"
msgstr "애니메이션 제거"
msgid "Invalid animation name!"
msgstr "애니메이션 이름이 잘못되었습니다!"
+msgid "Animation '%s' already exists!"
+msgstr "이름 '%s'을(를) 가진 애니메이션이 이미 있습니다!"
+
msgid "Duplicate Animation"
msgstr "애니메이션 복제"
@@ -4837,12 +6267,21 @@ msgstr "혼합 다음으로 바뀜"
msgid "Change Blend Time"
msgstr "혼합 시간 바꾸기"
+msgid "[Global] (create)"
+msgstr "[전역] (생성)"
+
+msgid "Duplicated Animation Name:"
+msgstr "복제된 애니메이션 이름:"
+
msgid "Play selected animation backwards from current pos. (A)"
msgstr "선택한 애니메이션을 현재 위치에서 거꾸로 재생합니다. (A)"
msgid "Play selected animation backwards from end. (Shift+A)"
msgstr "선택한 애니메이션을 끝에서 거꾸로 재생합니다. (Shift+A)"
+msgid "Pause/stop animation playback. (S)"
+msgstr "애니메이션 재생을 일시 정지/중단합니다. (S)"
+
msgid "Play selected animation from start. (Shift+D)"
msgstr "선택한 애니메이션을 처음부터 재생합니다. (Shift+D)"
@@ -4861,6 +6300,9 @@ msgstr "애니메이션 툴"
msgid "Animation"
msgstr "애니메이션"
+msgid "Manage Animations..."
+msgstr "애니메이션 관리..."
+
msgid "Edit Transitions..."
msgstr "전환 편집..."
@@ -4906,6 +6348,9 @@ msgstr "강제 흰색 조절"
msgid "Include Gizmos (3D)"
msgstr "기즈모 포함 (3D)"
+msgid "Onion Skinning temporarily disabled due to rendering bug."
+msgstr "어니언 스키닝은 렌더링 버그로 인해 임시로 비활성화해 두었습니다."
+
msgid "Pin AnimationPlayer"
msgstr "AnimationPlayer 고정"
@@ -4927,6 +6372,9 @@ msgstr "노드 이동"
msgid "Transition exists!"
msgstr "전환이 있습니다!"
+msgid "Add Node and Transition"
+msgstr "노드와 전환 추가"
+
msgid "Add Transition"
msgstr "전환 추가"
@@ -4951,6 +6399,17 @@ msgstr "노드 제거됨"
msgid "Transition Removed"
msgstr "전환 제거됨"
+msgid ""
+"Select and move nodes.\n"
+"RMB: Add node at position clicked.\n"
+"Shift+LMB+Drag: Connects the selected node with another node or creates a "
+"new node if you select an area without nodes."
+msgstr ""
+"노드를 선택하고 이동하세요.\n"
+"우클릭: 클릭한 위치에 새 노드를 만듭니다.\n"
+"Shift+좌클릭+드래그: 선택한 노드를 다른 노드와 연결합니다. 노드가 아닌 영역"
+"을 선택했을 경우 새 노드를 만듭니다."
+
msgid "Create new nodes."
msgstr "새 노드를 만듭니다."
@@ -4963,12 +6422,21 @@ msgstr "선택한 노드나 전환을 제거합니다."
msgid "Transition:"
msgstr "전환:"
+msgid "New Transitions Should Auto Advance"
+msgstr "새 전환을 자동으로 진행"
+
msgid "Play Mode:"
msgstr "실행 모드:"
msgid "Delete Selected"
msgstr "선택 항목 삭제"
+msgid "Delete All"
+msgstr "모두 삭제"
+
+msgid "Root"
+msgstr "루트"
+
msgid "AnimationTree"
msgstr "애니메이션 트리"
@@ -5041,6 +6509,9 @@ msgstr "SHA-256 해시 확인 실패"
msgid "Asset Download Error:"
msgstr "애셋 다운로드 오류:"
+msgid "Ready to install!"
+msgstr "설치 준비 완료!"
+
msgid "Downloading (%s / %s)..."
msgstr "다운로드 중 (%s / %s)..."
@@ -5111,6 +6582,23 @@ msgstr "마지막"
msgid "All"
msgstr "모두"
+msgid "No results for \"%s\" for support level(s): %s."
+msgstr "\"%s\"에 대한 결과가 서포트 레벨 %s에 없습니다."
+
+msgid ""
+"No results compatible with %s %s for support level(s): %s.\n"
+"Check the enabled support levels using the 'Support' button in the top-right "
+"corner."
+msgstr ""
+"%s %s와 호환되는 결과가 지원 레벨 %s에 없습니다.\n"
+"우측 상단의 '지원' 버튼을 눌러 활성화된 지원 레벨을 확인하세요."
+
+msgid "Search Templates, Projects, and Demos"
+msgstr "템플릿, 프로젝트, 데모 검색"
+
+msgid "Search Assets (Excluding Templates, Projects, and Demos)"
+msgstr "애셋 검색 (템플릿, 프로젝트, 데모 제외)"
+
msgid "Import..."
msgstr "가져오기..."
@@ -5138,6 +6626,12 @@ msgstr "애셋 ZIP 파일"
msgid "Audio Preview Play/Pause"
msgstr "오디오 미리보기 재생/일시 정지"
+msgid "Bone Picker:"
+msgstr "본 선택기:"
+
+msgid "Clear mappings in current group."
+msgstr "현재 그룹에서 모든 맵핑을 제거합니다."
+
msgid "Preview"
msgstr "미리보기"
@@ -5165,6 +6659,9 @@ msgstr "회전 단계:"
msgid "Scale Step:"
msgstr "스케일 단계:"
+msgid "Move Node(s) to Position"
+msgstr "노드를 위치로 이동"
+
msgid "Move Vertical Guide"
msgstr "수직 가이드 이동"
@@ -5225,6 +6722,27 @@ msgstr "그룹됨"
msgid "Add Node Here"
msgstr "여기에 노드 추가"
+msgid "Instantiate Scene Here"
+msgstr "여기에 씬 인스턴스화"
+
+msgid "Paste Node(s) Here"
+msgstr "여기에 노드 붙여넣기"
+
+msgid "Move Node(s) Here"
+msgstr "여기로 노드 이동"
+
+msgid "px"
+msgstr "px"
+
+msgid "units"
+msgstr "units"
+
+msgid "Moving:"
+msgstr "이동:"
+
+msgid "Rotating:"
+msgstr "회전:"
+
msgid "Scaling:"
msgstr "스케일링:"
@@ -5262,6 +6780,9 @@ msgstr "포즈 붙여 넣기"
msgid "Clear Guides"
msgstr "가이드 지우기"
+msgid "Create Custom Bone2D(s) from Node(s)"
+msgstr "노드에서 커스텀 Bone2D 만들기"
+
msgid "Zoom to 3.125%"
msgstr "3.125%로 줌"
@@ -5292,8 +6813,11 @@ msgstr "800%로 줌"
msgid "Zoom to 1600%"
msgstr "1600%로 줌"
+msgid "Center View"
+msgstr "중앙 보기"
+
msgid "Select Mode"
-msgstr "모드 선택"
+msgstr "선택 모드"
msgid "Drag: Rotate selected node around pivot."
msgstr "드래그: 피벗 주위에 선택된 노드를 회전합니다."
@@ -5326,12 +6850,21 @@ msgstr "스케일 모드"
msgid "Shift: Scale proportionally."
msgstr "Shift: 비례적으로 조정합니다."
+msgid "Show list of selectable nodes at position clicked."
+msgstr "클릭한 위치의 선택할 수 있는 노드 목록을 보여줍니다."
+
msgid "Click to change object's rotation pivot."
msgstr "클릭으로 오브젝트의 회전 피벗을 바꿉니다."
msgid "Pan Mode"
msgstr "팬 모드"
+msgid ""
+"You can also use Pan View shortcut (Space by default) to pan in any mode."
+msgstr ""
+"팬 보기 단축키 (기본값은 스페이스)를 이용하여 아무 모드에서나 팬을 할 수도 있"
+"습니다."
+
msgid "Ruler Mode"
msgstr "자 모드"
@@ -5386,15 +6919,27 @@ msgstr "다른 노드에 스냅"
msgid "Snap to Guides"
msgstr "가이드에 스냅"
+msgid "Lock selected node, preventing selection and movement."
+msgstr "선택된 노드를 잠그어 선택하거나 이동하지 못하게 합니다."
+
msgid "Lock Selected Node(s)"
msgstr "선택한 노드 잠금"
+msgid "Unlock selected node, allowing selection and movement."
+msgstr "선택된 노드를 잠금 해제하여 선택하거나 이동할 수 있게 합니다."
+
msgid "Unlock Selected Node(s)"
msgstr "선택한 노드 잠금 해제"
+msgid "Make selected node's children not selectable."
+msgstr "선택된 노드의 자식을 선택하지 못하게 합니다."
+
msgid "Group Selected Node(s)"
msgstr "선택한 노드 그룹화"
+msgid "Make selected node's children selectable."
+msgstr "선택된 노드의 자식을 선택할 수 있게 합니다."
+
msgid "Ungroup Selected Node(s)"
msgstr "선택한 노드 그룹 해제"
@@ -5404,6 +6949,9 @@ msgstr "스켈레톤 설정"
msgid "Show Bones"
msgstr "본 보이기"
+msgid "Make Bone2D Node(s) from Node(s)"
+msgstr "노드에서 Bone2D 노드 만들기"
+
msgid "View"
msgstr "보기"
@@ -5440,6 +6988,9 @@ msgstr "뷰포트 보이기"
msgid "Show Group And Lock Icons"
msgstr "그룹과 잠금 아이콘 보이기"
+msgid "Show Transformation Gizmos"
+msgstr "변형 기즈모 표시"
+
msgid "Center Selection"
msgstr "선택 항목 중앙으로"
@@ -5496,18 +7047,84 @@ msgstr "격자 단계를 반으로 감소"
msgid "Adding %s..."
msgstr "%s 추가하는 중..."
+msgid "Drag and drop to add as child of current scene's root node."
+msgstr "드래그 & 드롭하면 현재 씬의 루트 노드의 자식으로서 노드를 추가합니다."
+
+msgid "Hold Ctrl when dropping to add as child of selected node."
+msgstr ""
+"Ctrl을 누른 채 드롭하면 현재 선택된 노드의 자식으로서 노드를 추가합니다."
+
+msgid "Hold Shift when dropping to add as sibling of selected node."
+msgstr "Shift를 누른 채 드롭하면 선택된 노드의 형제로서 노드를 추가합니다."
+
+msgid "Hold Alt when dropping to add as a different node type."
+msgstr "Alt를 누른 채 드롭하면 다른 타입의 노드로 추가합니다."
+
msgid "Cannot instantiate multiple nodes without root."
-msgstr "루트 노드 없이는 여러 노드를 인스턴스할 수 없습니다."
+msgstr "루트 노드 없이 여러 노드를 인스턴스할 수 없습니다."
msgid "Create Node"
msgstr "노드 만들기"
+msgid "Error instantiating scene from %s"
+msgstr "%s에서 씬 인스턴스화 오류"
+
msgid "Change Default Type"
msgstr "디폴트 타입 바꾸기"
+msgid "Set Target Position"
+msgstr "목표 위치 설정"
+
msgid "Set Handle"
msgstr "핸들 설정"
+msgid "This node doesn't have a control parent."
+msgstr "이 노드에는 Control 부모가 없습니다."
+
+msgid ""
+"Use the appropriate layout properties depending on where you are going to "
+"put it."
+msgstr "어디에 놓을 것인지에 따라 적절한 레이아웃 속성을 사용하세요."
+
+msgid "This node is a child of a container."
+msgstr "이 노드는 Container의 자식입니다."
+
+msgid "Use container properties for positioning."
+msgstr "위치를 잡는 데 컨테이너의 속성을 사용하세요."
+
+msgid "This node is a child of a regular control."
+msgstr "이 노드는 일반적인 Control의 자식입니다."
+
+msgid "Use anchors and the rectangle for positioning."
+msgstr "위치를 잡는 데 앵커와 크기를 사용하세요."
+
+msgid "Collapse positioning hint."
+msgstr "위치 힌트를 접습니다."
+
+msgid "Expand positioning hint."
+msgstr "위치 힌트를 펼칩니다."
+
+msgid "Container Default"
+msgstr "컨테이너 기본값"
+
+msgid "Fill"
+msgstr "채우기"
+
+msgid "Shrink Begin"
+msgstr "시작점에서 수축"
+
+msgid "Shrink Center"
+msgstr "중앙에서 수축"
+
+msgid "Shrink End"
+msgstr "끝점에서 수축"
+
+msgid "Custom"
+msgstr "커스텀"
+
+msgid "Expand"
+msgstr "확장"
+
msgid "Top Left"
msgstr "왼쪽 위"
@@ -5530,7 +7147,7 @@ msgid "Center Right"
msgstr "오른쪽 중앙"
msgid "HCenter Wide"
-msgstr "수평선 중앙 넓게"
+msgstr "가로 중앙 넓게"
msgid "Bottom Left"
msgstr "왼쪽 아래"
@@ -5548,17 +7165,72 @@ msgid "Left Wide"
msgstr "왼쪽 넓게"
msgid "VCenter Wide"
-msgstr "수직선 중앙 넓게"
+msgstr "세로 중앙 넓게"
msgid "Right Wide"
msgstr "오른쪽 넓게"
msgid "Full Rect"
-msgstr "사각형 전체"
+msgstr "공간 전체"
+
+msgid ""
+"Enable to also set the Expand flag.\n"
+"Disable to only set Shrink/Fill flags."
+msgstr ""
+"확장 플래그를 같이 설정합니다.\n"
+"비활성화할 경우 수축/채우기 플래그만 설정합니다."
+
+msgid "Some parents of the selected nodes do not support the Expand flag."
+msgstr "선택된 노드의 부모들 중 일부가 확장 플래그를 지원하지 않습니다."
+
+msgid "Align with Expand"
+msgstr "확장과 정렬"
+
+msgid "Change Anchors, Offsets, Grow Direction"
+msgstr "앵커, 오프셋, 확장 방향 변경"
+
+msgid "Change Anchors, Offsets (Keep Ratio)"
+msgstr "앵커, 오프셋 변경 (비율 유지)"
+
+msgid "Change Vertical Size Flags"
+msgstr "세로 방향 크기 플래그 변경"
+
+msgid "Change Horizontal Size Flags"
+msgstr "가로 방향 크기 플래그 변경"
+
+msgid "Presets for the anchor and offset values of a Control node."
+msgstr "Control 노드의 앵커와 오프셋 값의 프리셋입니다."
+
+msgid "Anchor preset"
+msgstr "앵커 프리셋"
+
+msgid "Set to Current Ratio"
+msgstr "현재 비율로 설정"
+
+msgid "Adjust anchors and offsets to match the current rect size."
+msgstr "현재 크기에 맞게 앵커와 오프셋을 조정합니다."
+
+msgid ""
+"When active, moving Control nodes changes their anchors instead of their "
+"offsets."
+msgstr ""
+"이 설정을 켜면, Control 노드를 움직일 때 오프셋이 아닌 앵커를 바꿉니다."
+
+msgid "Sizing settings for children of a Container node."
+msgstr "Container 노드의 자식 크기 설정입니다."
+
+msgid "Horizontal alignment"
+msgstr "가로 방향 정렬"
+
+msgid "Vertical alignment"
+msgstr "세로 방향 정렬"
msgid "Load Emission Mask"
msgstr "방출 마스크 불러오기"
+msgid "CPUParticles2D"
+msgstr "CPUParticles2D"
+
msgid "Generated Point Count:"
msgstr "생성한 점 개수:"
@@ -5580,20 +7252,38 @@ msgstr "픽셀에서 캡처"
msgid "Emission Colors"
msgstr "방출 색상"
+msgid "CPUParticles3D"
+msgstr "CPUParticles3D"
+
msgid "Create Emission Points From Node"
msgstr "노드에서 방출 점 만들기"
msgid "Load Curve Preset"
msgstr "곡선 프리셋 불러오기"
+msgid "Add Curve Point"
+msgstr "곡선 점 생성"
+
msgid "Remove Curve Point"
msgstr "곡선 점 제거"
msgid "Modify Curve Point"
msgstr "곡선 점 수정"
+msgid "Modify Curve Point's Tangents"
+msgstr "곡선 점의 접선 수정"
+
+msgid "Modify Curve Point's Left Tangent"
+msgstr "곡선 점의 왼쪽 접선 수정"
+
+msgid "Modify Curve Point's Right Tangent"
+msgstr "곡선 점의 오른쪽 접선 수정"
+
+msgid "Toggle Linear Curve Point's Tangent"
+msgstr "곡선 점의 선형 접선 토글"
+
msgid "Hold Shift to edit tangents individually"
-msgstr "Shift키를 눌러서 탄젠트를 개별적으로 편집"
+msgstr "Shift키를 눌러서 접선을 개별적으로 편집"
msgid "Ease In"
msgstr "감속"
@@ -5622,13 +7312,13 @@ msgid ""
"You don't need to enable it to use the GDScript debugger locally."
msgstr ""
"이 옵션이 활성화된 경우 원 클릭 배포를 사용하면 실행중인 프로젝트를 디버깅 "
-"할 수 있도록이 컴퓨터의 IP에 연결을 시도합니다.\n"
+"할 수 있도록 이 컴퓨터의 IP에 연결을 시도합니다.\n"
"이 옵션은 원격 디버깅 (일반적으로 모바일 기기 사용)에 사용하기 위한 것입니"
"다.\n"
"GDScript 디버거를 로컬에서 사용하기 위해 활성화할 필요는 없습니다."
msgid "Small Deploy with Network Filesystem"
-msgstr "네트워크 파일시스템을 사용하여 작게 배포"
+msgstr "네트워크 파일시스템을 사용한 경량 배포"
msgid ""
"When this option is enabled, using one-click deploy for Android will only "
@@ -5642,7 +7332,7 @@ msgstr ""
"실행 파일만 내 보냅니다.\n"
"파일시스템은 네트워크를 통해 에디터에 의해 프로젝트에서 제공됩니다.\n"
"Android의 경우, 배포시 더 빠른 속도를 위해 USB 케이블을 사용합니다. 이 옵션"
-"은 애셋의 용량이 큰 프로젝트의 테스트 속도를 높입니다."
+"은 에셋의 용량이 큰 프로젝트의 테스트 속도를 높입니다."
msgid "Visible Collision Shapes"
msgstr "콜리전 모양 보이기"
@@ -5654,8 +7344,18 @@ msgstr ""
"이 설정을 활성화하면 프로젝트를 실행하는 동안 (2D와 3D용) 콜리전 모양과 "
"Raycast 노드가 보이게 됩니다."
+msgid "Visible Paths"
+msgstr "패스 보이기"
+
+msgid ""
+"When this option is enabled, curve resources used by path nodes will be "
+"visible in the running project."
+msgstr ""
+"이 설정이 활성화되면, 프로젝트를 실행하는 동안 Path 노드에서 사용하는 Curve "
+"리소스가 보이게 됩니다."
+
msgid "Visible Navigation"
-msgstr "내비게이션 보이기"
+msgstr "네비게이션 보이기"
msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
@@ -5664,6 +7364,16 @@ msgstr ""
"이 설정이 활성화되면, 프로젝트를 실행하는 동안 네비게이션 메시와 폴리곤이 보"
"이게 됩니다."
+msgid "Visible Avoidance"
+msgstr "어보이던스 보이기"
+
+msgid ""
+"When this option is enabled, avoidance objects shapes, radius and velocities "
+"will be visible in the running project."
+msgstr ""
+"이 설정이 활성화되면, 프로젝트를 실행하는 동안 어보이던스 오브젝트의 모양, 직"
+"경과 속도가 보이게 됩니다."
+
msgid "Synchronize Scene Changes"
msgstr "씬 변경사항 동기화"
@@ -5675,8 +7385,8 @@ msgid ""
msgstr ""
"이 설정이 활성화되면, 에디터에서 씬을 수정하면 실행 중인 프로젝트에 반영됩니"
"다.\n"
-"기기에서 원격으로 사용 중인 경우 네트워크 파일시스템 기능을 활성화하면 더욱 "
-"효율적입니다."
+"기기에서 원격으로 사용 중인 경우, 네트워크 파일시스템 옵션이 활성화되어 있다"
+"면 더욱 효율적입니다."
msgid "Synchronize Script Changes"
msgstr "스크립트 변경사항 동기화"
@@ -5687,18 +7397,62 @@ msgid ""
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
-"이 옵션이 활성화되면, 어떤 스크립트든지 저장되면 실행 중인 프로젝트를 다시 불"
+"이 설정이 활성화되면, 어떤 스크립트든지 저장되면 실행 중인 프로젝트를 다시 불"
"러오게 됩니다.\n"
-"기기에서 원격으로 사용 중이면, 네트워크 파일시스템 옵션이 활성화되어 있다면 "
-"더욱 효율적입니다."
+"기기에서 원격으로 사용 중인 경우, 네트워크 파일시스템 옵션이 활성화되어 있다"
+"면 더욱 효율적입니다."
+
+msgid "Keep Debug Server Open"
+msgstr "디버그 서버 열어놓기"
+
+msgid ""
+"When this option is enabled, the editor debug server will stay open and "
+"listen for new sessions started outside of the editor itself."
+msgstr ""
+"이 설정이 활성화되면, 에디터의 디버그 서버가 에디터 바깥에서 시작된 새로운 세"
+"션을 지원하기 위해 열려 있을 것입니다."
+
+msgid "Run Multiple Instances"
+msgstr "여러 인스턴스 실행"
msgid "Run %d Instance"
msgid_plural "Run %d Instances"
-msgstr[0] "%d 인스턴스 실행"
+msgstr[0] "%d개 인스턴스 실행"
+
+msgid "Size: %s"
+msgstr "크기: %s"
+
+msgid "Type: %s"
+msgstr "타입: %s"
+
+msgid "Overrides (%d)"
+msgstr "오버라이드 (%d)"
+
+msgctxt "Locale"
+msgid "Add Script"
+msgstr "스크립트 추가"
+
+msgid "Add Locale"
+msgstr "로케일 추가"
+
+msgid "Variation Coordinates (%d)"
+msgstr "바리에이션 좌표 (%d)"
+
+msgid "No supported features"
+msgstr "지원되는 기능 없음"
+
+msgid "Features (%d of %d set)"
+msgstr "기능 (%d개, %d개 중)"
+
+msgid "Add Feature"
+msgstr "기능 추가"
msgid " - Variation"
msgstr " - 바리에이션"
+msgid "Unable to preview font"
+msgstr "폰트를 미리보기할 수 없음"
+
msgid "Change AudioStreamPlayer3D Emission Angle"
msgstr "AudioStreamPlayer3D 방출 각도 바꾸기"
@@ -5711,6 +7465,9 @@ msgstr "카메라 크기 바꾸기"
msgid "Change Sphere Shape Radius"
msgstr "구체 모양 반경 바꾸기"
+msgid "Change Box Shape Size"
+msgstr "박스 모양 크기 바꾸기"
+
msgid "Change Capsule Shape Radius"
msgstr "캡슐 모양 반경 바꾸기"
@@ -5723,24 +7480,61 @@ msgstr "캡슐 모양 반지름 바꾸기"
msgid "Change Cylinder Shape Height"
msgstr "캡슐 모양 높이 바꾸기"
+msgid "Change Separation Ray Shape Length"
+msgstr "구분 광선 모양 길이 바꾸기"
+
+msgid "Change Decal Size"
+msgstr "데칼 크기 바꾸기"
+
+msgid "Change Fog Volume Size"
+msgstr "포그 볼륨 크기 바꾸기"
+
msgid "Change Particles AABB"
msgstr "파티클 AABB 바꾸기"
+msgid "Change Radius"
+msgstr "반경 바꾸기"
+
msgid "Change Light Radius"
msgstr "라이트 반경 바꾸기"
+msgid "Start Location"
+msgstr "시작 위치"
+
+msgid "End Location"
+msgstr "끝 위치"
+
+msgid "Change Start Position"
+msgstr "시작 위치 바꾸기"
+
+msgid "Change End Position"
+msgstr "끝 위치 바꾸기"
+
+msgid "Change Probe Size"
+msgstr "프로브 크기 바꾸기"
+
msgid "Change Notifier AABB"
msgstr "알림 AABB 바꾸기"
msgid "Convert to CPUParticles2D"
msgstr "CPUParticles2D로 변환"
+msgid "Generating Visibility Rect (Waiting for Particle Simulation)"
+msgstr "가시성 직사각형 생성 중 (파티클 시뮬레이션을 기다리는 중)"
+
msgid "Generate Visibility Rect"
-msgstr "가시성 직사각형을 만듭니다"
+msgstr "가시성 직사각형 생성"
+
+msgid "Can only set point into a ParticleProcessMaterial process material"
+msgstr ""
+"ParticleProcessMaterial 프로세스 머티리얼 안에만 점을 설정할 수 있습니다"
msgid "Clear Emission Mask"
msgstr "에미션 마스크 정리"
+msgid "GPUParticles2D"
+msgstr "GPUParticles2D"
+
msgid "Generation Time (sec):"
msgstr "생성 시간 (초):"
@@ -5750,6 +7544,9 @@ msgstr "지오메트리의 면에 영역이 포함되지 않습니다."
msgid "The geometry doesn't contain any faces."
msgstr "지오메트리에 면이 포함되지 않습니다."
+msgid "\"%s\" doesn't inherit from Node3D."
+msgstr "\"%s\"은(는) Node3D를 상속받지 않습니다."
+
msgid "\"%s\" doesn't contain geometry."
msgstr "\"%s\"에 지오메트리가 포함되지 않습니다."
@@ -5774,18 +7571,75 @@ msgstr "볼륨"
msgid "Emission Source:"
msgstr "방출 소스:"
+msgid "A processor material of type 'ParticleProcessMaterial' is required."
+msgstr "'ParticlesProcessMaterial' 타입의 프로세서 머티리얼이 필요합니다."
+
+msgid "Convert to CPUParticles3D"
+msgstr "CPUParticles3D로 변환"
+
+msgid "Generating Visibility AABB (Waiting for Particle Simulation)"
+msgstr "가시성 AABB 생성 중 (파티클 시뮬레이션을 기다리는 중)"
+
msgid "Generate Visibility AABB"
-msgstr "가시성 AABB 만들기"
+msgstr "가시성 AABB 생성"
+
+msgid "GPUParticles3D"
+msgstr "GPUParticles3D"
+
+msgid "Generate AABB"
+msgstr "AABB 생성"
+
+msgid "Low"
+msgstr "낮음"
+
+msgid "Moderate"
+msgstr "중간"
+
+msgid "High"
+msgstr "높음"
+
+msgid "Subdivisions: %s"
+msgstr "서브디비전: %s"
+
+msgid "Cell size: %s"
+msgstr "셀 크기: %s"
+
+msgid "Video RAM size: %s MB (%s)"
+msgstr "VRAM 크기: %s MB (%s)"
+
+msgid "Bake SDF"
+msgstr "SDF 굽기"
+
+msgid ""
+"No faces detected during GPUParticlesCollisionSDF3D bake.\n"
+"Check whether there are visible meshes matching the bake mask within its "
+"extents."
+msgstr ""
+"GPUParticlesCollisionSDF3D를 굽는 중 아무 면도 찾지 못했습니다.\n"
+"이 범위 내에 일치하는 베이크 마스크를 지닌 숨겨지지 않은 메시가 있는지 확인"
+"해 주세요."
+
+msgid "Select path for SDF Texture"
+msgstr "SDF 텍스처의 경로를 선택하세요"
msgid "Gradient Edited"
-msgstr "기울기 편집됨"
+msgstr "그라디언트 편집됨"
+
+msgid "Reverse/mirror gradient."
+msgstr "그라디언트를 뒤집거나 반전합니다."
+
+msgid "Move GradientTexture2D Fill Point"
+msgstr "GradientTexture2D 채우기 포인트 교체"
msgid "Swap GradientTexture2D Fill Points"
-msgstr "그라디언트텍스처2D 채우기 포인트 교체"
+msgstr "GradientTexture2D 채우기 포인트 교체"
msgid "Swap Gradient Fill Points"
msgstr "그라디언트 채우기 포인트 교체"
+msgid "Configure"
+msgstr "구성"
+
msgid "Create Occluder Polygon"
msgstr "Occluder 폴리곤 만들기"
@@ -5794,11 +7648,24 @@ msgid ""
"Save your scene and try again."
msgstr ""
"라이트맵 이미지를 위한 저장 경로를 결정할 수 없습니다.\n"
-"당신의 씬을 저장하고 다시 시도하세요."
+"씬을 저장하고 다시 시도하세요."
+
+msgid ""
+"No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake "
+"Light' flag is on."
+msgstr ""
+"구울 메시가 없습니다. UV2 채널을 포함하고 있고 'Bake Light' 플래그가 켜져 있"
+"는지 확인해주세요."
msgid "Failed creating lightmap images, make sure path is writable."
msgstr "라이트맵 이미지 생성 실패. 작성 가능한 경로인지 확인해주세요."
+msgid "No editor scene root found."
+msgstr "에디터 씬의 루트를 찾을 수 없습니다."
+
+msgid "Lightmap data is not local to the scene."
+msgstr "라이트맵 데이터가 씬에 로컬이 아닙니다."
+
msgid "Bake Lightmaps"
msgstr "라이트맵 굽기"
@@ -5847,12 +7714,39 @@ msgstr "다중 컨벡스 모양 만들기"
msgid "Create Navigation Mesh"
msgstr "내비게이션 메시 만들기"
+msgid "Create Debug Tangents"
+msgstr "디버그 접선 생성"
+
msgid "Contained Mesh is not of type ArrayMesh."
msgstr "포함된 메시가 ArrayMesh 타입이 아닙니다."
+msgid ""
+"Mesh cannot unwrap UVs because it does not belong to the edited scene. Make "
+"it unique first."
+msgstr ""
+"이 메시는 편집 중인 씬에 속한 것이 아니어서 UV 펼치기를 할 수 없습니다. 먼저 "
+"리소스를 유일하게 만드세요."
+
+msgid ""
+"Mesh cannot unwrap UVs because it belongs to another resource which was "
+"imported from another file type. Make it unique first."
+msgstr ""
+"이 메시는 다른 파일 타입에서 가져온 다른 리소스에 속하는 것이어서 UV 펼치기"
+"를 할 수 없습니다. 먼저 리소스를 유일하게 만드세요."
+
+msgid ""
+"Mesh cannot unwrap UVs because it was imported from another file type. Make "
+"it unique first."
+msgstr ""
+"이 메시는 다른 파일 타입에서 가져온 것이어서 UV 펼치기를 할 수 없습니다. 먼"
+"저 리소스를 유일하게 만드세요."
+
msgid "UV Unwrap failed, mesh may not be manifold?"
msgstr "UV 펼치기를 실패했습니다. 메시가 다양한 것 같은데요?"
+msgid "Unwrap UV2"
+msgstr "UV2 펼치기"
+
msgid "No mesh to debug."
msgstr "디버그할 메시가 없습니다."
@@ -5880,6 +7774,15 @@ msgstr "메시"
msgid "Create Trimesh Static Body"
msgstr "Trimesh Static Body 만들기"
+msgid ""
+"Creates a StaticBody3D and assigns a polygon-based collision shape to it "
+"automatically.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+"StaticBody3D를 만들고 거기에 폴리곤 기반 콜리전 모양을 자동으로 만들어 붙입니"
+"다.\n"
+"이 방법은 가장 정확한 (하지만 가장 느린) 콜리전 탐지 방법입니다."
+
msgid "Create Trimesh Collision Sibling"
msgstr "Trimesh 콜리전 동기 만들기"
@@ -5927,6 +7830,16 @@ msgstr ""
msgid "Create Outline Mesh..."
msgstr "윤곽선 메시 만들기..."
+msgid ""
+"Creates a static outline mesh. The outline mesh will have its normals "
+"flipped automatically.\n"
+"This can be used instead of the StandardMaterial Grow property when using "
+"that property isn't possible."
+msgstr ""
+"스태틱 윤곽선 메시를 만듭니다. 윤곽선 메시의 법선 벡터는 자동으로 반전됩니"
+"다.\n"
+"StandardMaterial의 Grow 속성을 사용할 수 없을 때 대신 사용할 수 있습니다."
+
msgid "View UV1"
msgstr "UV1 보기"
@@ -5990,6 +7903,9 @@ msgstr "메시 소스를 지정하지 않았습니다 (그리고 MultiMesh에
msgid "Mesh source is invalid (invalid path)."
msgstr "메시 소스가 잘못되었습니다 (잘못된 경로)."
+msgid "Mesh source is invalid (not a MeshInstance3D)."
+msgstr "메시 소스가 잘못되었습니다 (MeshInstance3D가 아님)."
+
msgid "Mesh source is invalid (contains no Mesh resource)."
msgstr "메시 소스가 잘못되었습니다 (Mesh 리소스가 없음)."
@@ -6050,6 +7966,18 @@ msgstr "양:"
msgid "Populate"
msgstr "만들기"
+msgid "Set start_position"
+msgstr "start_position 설정"
+
+msgid "Set end_position"
+msgstr "end_position 설정"
+
+msgid "Set NavigationObstacle3D Vertices"
+msgstr "NavigationObstacle3D 꼭지점 설정"
+
+msgid "Edit Vertices"
+msgstr "꼭지점 편집"
+
msgid "Edit Poly"
msgstr "폴리곤 편집"
@@ -6063,7 +7991,7 @@ msgid "Unnamed Gizmo"
msgstr "이름 없는 기즈모"
msgid "Transform Aborted."
-msgstr "변형 중단됨."
+msgstr "변형이 중단되었습니다."
msgid "Orthogonal"
msgstr "직교"
@@ -6111,26 +8039,62 @@ msgid " [auto]"
msgstr " [자동]"
msgid "X-Axis Transform."
-msgstr "X축 변형."
+msgstr "X축 변형입니다."
msgid "Y-Axis Transform."
-msgstr "Y축 변형."
+msgstr "Y축 변형입니다."
msgid "Z-Axis Transform."
-msgstr "Z축 변형."
+msgstr "Z축 변형입니다."
msgid "View Plane Transform."
-msgstr "뷰 평면 변형."
+msgstr "뷰 평면 변형입니다."
+
+msgid "YZ-Plane Transform."
+msgstr "YZ 평면 변형입니다."
+
+msgid "XZ-Plane Transform."
+msgstr "XZ 평면 변형."
+
+msgid "XY-Plane Transform."
+msgstr "XY 평면 변형입니다."
msgid "Keying is disabled (no key inserted)."
-msgstr "키가 비활성화되어 있습니다 (키가 삽입되지 않습니다)."
+msgstr "키잉이 비활성화되어 있습니다 (키가 삽입되지 않습니다)."
msgid "Animation Key Inserted."
msgstr "애니메이션 키를 삽입했습니다."
+msgid "X: %s\n"
+msgstr "X: %s\n"
+
+msgid "Y: %s\n"
+msgstr "Y: %s\n"
+
+msgid "Z: %s\n"
+msgstr "Z: %s\n"
+
+msgid "Size: %s (%.1fMP)\n"
+msgstr "크기: %s (%.1fMP)\n"
+
msgid "Objects: %d\n"
msgstr "오브젝트: %d\n"
+msgid "Primitives: %d\n"
+msgstr "프리미티브: %d\n"
+
+msgid "Draw Calls: %d"
+msgstr "드로우 콜: %d"
+
+msgid "CPU Time: %s ms"
+msgstr "CPU 시간: %s ms"
+
+msgid "GPU Time: %s ms"
+msgstr "GPU 시간: %s ms"
+
+msgid "FPS: %d"
+msgstr "FPS: %d"
+
msgid "Top View."
msgstr "상단면 보기."
@@ -6155,6 +8119,15 @@ msgstr "변형을 뷰에 정렬"
msgid "Align Rotation with View"
msgstr "회전을 뷰에 정렬"
+msgid "Set Surface %d Override Material"
+msgstr "표면 %d 오버라이드 머티리얼 설정"
+
+msgid "Set Material Override"
+msgstr "머티리얼 오버라이드 설정"
+
+msgid "Cannot drag and drop into multiple selected nodes."
+msgstr "선택된 여러 노드에 드래그 드롭할 수 없습니다."
+
msgid "None"
msgstr "없음"
@@ -6177,7 +8150,7 @@ msgid "Lock View Rotation"
msgstr "뷰 회전 잠금"
msgid "Display Normal"
-msgstr "노멀 표시"
+msgstr "일반 표시"
msgid "Display Wireframe"
msgstr "와이어프레임 표시"
@@ -6185,11 +8158,77 @@ msgstr "와이어프레임 표시"
msgid "Display Overdraw"
msgstr "오버드로 표시"
+msgid "Display Lighting"
+msgstr "명암 표시"
+
msgid "Display Unshaded"
-msgstr "셰이더 없음 표시"
+msgstr "셰이더 없이 표시"
+
+msgid "Directional Shadow Splits"
+msgstr "디렉셔널 섀도 스플릿"
msgid "Normal Buffer"
-msgstr "방출 소스:"
+msgstr "노멀 버퍼"
+
+msgid "Shadow Atlas"
+msgstr "그림자 아틀라스"
+
+msgid "Directional Shadow Map"
+msgstr "디렉셔널 섀도 맵"
+
+msgid "Decal Atlas"
+msgstr "데칼 아틀라스"
+
+msgid "VoxelGI Lighting"
+msgstr "VoxelGI 명암"
+
+msgid "VoxelGI Albedo"
+msgstr "VoxelGI 알베도"
+
+msgid "VoxelGI Emission"
+msgstr "VoxelGI 에미션"
+
+msgid "SDFGI Cascades"
+msgstr "SDFGI 캐스케이드"
+
+msgid "SDFGI Probes"
+msgstr "SDFGI 프로브"
+
+msgid "Scene Luminance"
+msgstr "씬 광도"
+
+msgid "SSAO"
+msgstr "SSAO"
+
+msgid "SSIL"
+msgstr "SSIL"
+
+msgid "VoxelGI/SDFGI Buffer"
+msgstr "VoxelGI/SDFGI 버퍼"
+
+msgid "Disable Mesh LOD"
+msgstr "메시 LOD 비활성화"
+
+msgid "OmniLight3D Cluster"
+msgstr "OmniLight3D 클러스터"
+
+msgid "SpotLight3D Cluster"
+msgstr "SpotLight3D 클러스터"
+
+msgid "Decal Cluster"
+msgstr "데칼 클러스터"
+
+msgid "ReflectionProbe Cluster"
+msgstr "ReflectionProbe 클러스터"
+
+msgid "Occlusion Culling Buffer"
+msgstr "오클루전 컬링 버퍼"
+
+msgid "Motion Vectors"
+msgstr "모션 벡터"
+
+msgid "Display Advanced..."
+msgstr "자세히 표시..."
msgid "View Environment"
msgstr "환경 보기"
@@ -6200,6 +8239,9 @@ msgstr "기즈모 보기"
msgid "View Information"
msgstr "정보 보기"
+msgid "View Frame Time"
+msgstr "프레임 시간 보기"
+
msgid "Half Resolution"
msgstr "절반 해상도"
@@ -6207,11 +8249,14 @@ msgid "Audio Listener"
msgstr "오디오 리스너"
msgid "Enable Doppler"
-msgstr "파동 왜곡 활성화"
+msgstr "도플러 효과 활성화"
msgid "Cinematic Preview"
msgstr "시네마틱 미리보기"
+msgid "Not available when using the OpenGL renderer."
+msgstr "OpenGL 렌더러에서는 사용할 수 없습니다."
+
msgid "Freelook Left"
msgstr "자유 시점 왼쪽으로"
@@ -6231,10 +8276,40 @@ msgid "Freelook Down"
msgstr "자유 시점 아래로"
msgid "Freelook Speed Modifier"
-msgstr "자유 시점 속도 수정자"
+msgstr "자유 시점 가속 수정자"
msgid "Freelook Slow Modifier"
-msgstr "자유 시점 느린 수정자"
+msgstr "자유 시점 감속 수정자"
+
+msgid "Lock Transformation to X axis"
+msgstr "변형을 X축으로 잠금"
+
+msgid "Lock Transformation to Y axis"
+msgstr "변형을 Y축으로 잠금"
+
+msgid "Lock Transformation to Z axis"
+msgstr "변형을 Z축으로 잠금"
+
+msgid "Lock Transformation to YZ plane"
+msgstr "변형을 YZ 평면으로 잠금"
+
+msgid "Lock Transformation to XZ plane"
+msgstr "변형을 XZ 평면으로 잠금"
+
+msgid "Lock Transformation to XY plane"
+msgstr "변형을 XY 평면으로 잠금"
+
+msgid "Cancel Transformation"
+msgstr "변형 취소"
+
+msgid "Begin Translate Transformation"
+msgstr "이동 변형 시작"
+
+msgid "Begin Rotate Transformation"
+msgstr "회전 변형 시작"
+
+msgid "Begin Scale Transformation"
+msgstr "크기 변형 시작"
msgid "Toggle Camera Preview"
msgstr "카메라 미리보기 토글"
@@ -6246,6 +8321,16 @@ msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr "더욱 확대하려면, 카메라의 클리핑 평면을 바꾸세요 (보기 -> 설정...)"
+msgid "Overriding material..."
+msgstr "머티리얼 오버라이드..."
+
+msgid ""
+"Drag and drop to override the material of any geometry node.\n"
+"Hold Ctrl when dropping to override a specific surface."
+msgstr ""
+"드래그 & 드롭으로 아무 지오메트리 노드의 머티리얼을 오버라이드합니다.\n"
+"Ctrl을 누르며 드롭하면 특정한 면을 오버라이드합니다."
+
msgid "XForm Dialog"
msgstr "XForm 대화 상자"
@@ -6268,12 +8353,58 @@ msgstr "노드를 바닥에 스냅"
msgid "Couldn't find a solid floor to snap the selection to."
msgstr "선택 항목을 스냅할 바닥을 찾을 수 없습니다."
+msgid "Add Preview Sun to Scene"
+msgstr "미리보기 태양을 씬에 추가"
+
+msgid "Add Preview Environment to Scene"
+msgstr "미리보기 환경을 씬에 추가"
+
+msgid ""
+"Scene contains\n"
+"DirectionalLight3D.\n"
+"Preview disabled."
+msgstr ""
+"씬에 DirectionalLight3D가\n"
+"존재합니다.\n"
+"미리보기가 비활성화됩니다."
+
+msgid "Preview disabled."
+msgstr "미리보기가 비활성화되었습니다."
+
+msgid ""
+"Scene contains\n"
+"WorldEnvironment.\n"
+"Preview disabled."
+msgstr ""
+"씬에 WorldEnvironment가\n"
+"존재합니다.\n"
+"미리보기가 비활성화됩니다."
+
msgid "Use Local Space"
msgstr "로컬 공간 사용"
msgid "Use Snap"
msgstr "스냅 사용"
+msgid ""
+"Toggle preview sunlight.\n"
+"If a DirectionalLight3D node is added to the scene, preview sunlight is "
+"disabled."
+msgstr ""
+"태양 미리보기를 토글합니다.\n"
+"씬에 DirectionalLight3D 노드가 있다면, 태양 미리보기를 사용할 수 없습니다."
+
+msgid ""
+"Toggle preview environment.\n"
+"If a WorldEnvironment node is added to the scene, preview environment is "
+"disabled."
+msgstr ""
+"환경 미리보기를 토글합니다.\n"
+"씬에 WorldEnvironment 노드가 있다면, 환경 미리보기를 사용할 수 없습니다."
+
+msgid "Edit Sun and Environment settings."
+msgstr "태양과 환경을 설정합니다."
+
msgid "Bottom View"
msgstr "하단 뷰"
@@ -6415,6 +8546,102 @@ msgstr "전"
msgid "Post"
msgstr "후"
+msgid "Preview Sun"
+msgstr "태양 미리보기"
+
+msgid "Sun Direction"
+msgstr "태양 방향"
+
+msgid "Angular Altitude"
+msgstr "고도각"
+
+msgid "Azimuth"
+msgstr "방위각"
+
+msgid "Sun Color"
+msgstr "태양 색상"
+
+msgid "Sun Energy"
+msgstr "햇살 강도"
+
+msgid "Shadow Max Distance"
+msgstr "그림자 최대 길이"
+
+msgid "Add Sun to Scene"
+msgstr "씬에 태양 추가"
+
+msgid ""
+"Adds a DirectionalLight3D node matching the preview sun settings to the "
+"current scene.\n"
+"Hold Shift while clicking to also add the preview environment to the current "
+"scene."
+msgstr ""
+"현재 태양 미리보기 설정과 같은 설정의 DirectionalLight3D 노드를 추가합니다.\n"
+"Shift를 누르며 클릭하면 미리보기 환경 또한 같이 추가합니다."
+
+msgid "Preview Environment"
+msgstr "환경 미리보기"
+
+msgid "Sky Color"
+msgstr "하늘 색상"
+
+msgid "Ground Color"
+msgstr "땅 색상"
+
+msgid "Sky Energy"
+msgstr "하늘빛 강도"
+
+msgid "AO"
+msgstr "AO"
+
+msgid "Glow"
+msgstr "빛번짐"
+
+msgid "Tonemap"
+msgstr "톤맵"
+
+msgid "GI"
+msgstr "GI"
+
+msgid "Post Process"
+msgstr "후처리"
+
+msgid "Add Environment to Scene"
+msgstr "씬에 환경 추가"
+
+msgid ""
+"Adds a WorldEnvironment node matching the preview environment settings to "
+"the current scene.\n"
+"Hold Shift while clicking to also add the preview sun to the current scene."
+msgstr ""
+"현재 환경 미리보기 설정과 같은 설정의 WorldEnvironment 노드를 추가합니다.\n"
+"Shift를 누르며 클릭하면 미리보기 태양 또한 같이 추가합니다."
+
+msgid ""
+"Can't determine a save path for the occluder.\n"
+"Save your scene and try again."
+msgstr ""
+"오클루더 저장 경로를 결정할 수 없습니다.\n"
+"씬을 저장한 뒤 다시 시도하세요."
+
+msgid ""
+"No meshes to bake.\n"
+"Make sure there is at least one MeshInstance3D node in the scene whose "
+"visual layers are part of the OccluderInstance3D's Bake Mask property."
+msgstr ""
+"구울 메시가 없습니다.\n"
+"씬에 비주얼 레이어가 OccluderInstance3D의 베이크 마스크 속성의 일부인 "
+"MeshInstance3D 노드가 하나 이상 있는지 확인하세요."
+
+msgid "Could not save the new occluder at the specified path:"
+msgstr "새 오클루더를 지정된 경로에 저장할 수 없습니다:"
+
+msgid "Bake Occluders"
+msgstr "오클루더 굽기"
+
+msgid "Select occluder bake file:"
+msgstr "오클루더를 구울 파일 선택:"
+
msgid "Remove Point from Curve"
msgstr "곡선에서 점 제거"
@@ -6718,8 +8945,14 @@ msgstr "파일을 찾을 수 없음:"
msgid "Save File As..."
msgstr "다른 이름으로 저장..."
+msgid "Can't obtain the script for reloading."
+msgstr "재시작할 스크립트를 받아올 수 없습니다."
+
+msgid "Reload only takes effect on tool scripts."
+msgstr "재시작은 툴 스크립트에만 영향을 줍니다."
+
msgid "Can't obtain the script for running."
-msgstr "실행하기 위한 스크립트를 가질 수 없습니다."
+msgstr "실행할 스크립트를 받아올 수 없습니다."
msgid "Script is not in tool mode, will not be able to run."
msgstr "스크립트가 Tool 모드가 아닙니다. 실행할 수 없을 것입니다."
@@ -6745,6 +8978,9 @@ msgstr "저장 중 오류"
msgid "Save Theme As..."
msgstr "테마를 다른 이름으로 저장..."
+msgid "Unsaved file."
+msgstr "저장되지 않은 파일입니다."
+
msgid "%s Class Reference"
msgstr "%s 클래스 참조"
@@ -6754,6 +8990,9 @@ msgstr "다음 찾기"
msgid "Find Previous"
msgstr "이전 찾기"
+msgid "Filter Scripts"
+msgstr "스크립트 필터"
+
msgid "Toggle alphabetical sorting of the method list."
msgstr "메서드 목록의 사전 식 정렬을 토글합니다."
@@ -6778,6 +9017,9 @@ msgstr "닫은 스크립트 다시 열기"
msgid "Save All"
msgstr "모두 저장"
+msgid "Soft Reload Tool Script"
+msgstr "툴 스크립트 새로고침"
+
msgid "Copy Script Path"
msgstr "스크립트 경로 복사"
@@ -6826,6 +9068,9 @@ msgstr "이전에 편집한 문서로 이동합니다."
msgid "Go to next edited document."
msgstr "다음에 편집한 문서로 이동합니다."
+msgid "Make the script editor floating."
+msgstr "스크립트 에디터를 창으로 띄웁니다."
+
msgid "Discard"
msgstr "버리기"
@@ -6845,6 +9090,12 @@ msgstr "최근 스크립트 지우기"
msgid "Standard"
msgstr "표준"
+msgid "Plain Text"
+msgstr "일반 텍스트"
+
+msgid "JSON"
+msgstr "JSON"
+
msgid "Connections to method:"
msgstr "메서드에 연결:"
@@ -6852,13 +9103,16 @@ msgid "Source"
msgstr "소스"
msgid "Target"
-msgstr "Target(대상)"
+msgstr "대상"
+
+msgid "Error at (%d, %d):"
+msgstr "(%d, %d)에 오류 있음:"
msgid ""
"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
msgstr ""
-"메서드 '%s'이(가) 시그널 '%s'을 노드 '%s'에서 노드 '%s'으로 연결되지 않았습니"
-"다."
+"연결 메서드 '%s'이(가) 없어서 시그널 '%s'을 통한 노드 '%s'에서 노드 '%s'로의 "
+"연결이 불가합니다."
msgid "[Ignore]"
msgstr "[무시]"
@@ -6872,6 +9126,9 @@ msgstr "함수로 이동"
msgid "Only resources from filesystem can be dropped."
msgstr "파일시스템의 리소스만 드롭할 수 있습니다."
+msgid "Can't drop nodes without an open scene."
+msgstr "루트 노드를 같은 씬 안으로 붙여넣을 수 없습니다."
+
msgid "Can't drop nodes because script '%s' is not used in this scene."
msgstr ""
"스크립트 '%s'이(가) 이 씬에서 사용되지 않고 있어서 노드를 드롭할 수 없습니다."
@@ -6882,6 +9139,12 @@ msgstr "룩업 기호"
msgid "Pick Color"
msgstr "색상 선택"
+msgid "Folding"
+msgstr "접기"
+
+msgid "Indentation"
+msgstr "들여쓰기"
+
msgid "Uppercase"
msgstr "대문자로"
@@ -6906,6 +9169,9 @@ msgstr "이동"
msgid "Delete Line"
msgstr "행 삭제"
+msgid "Unindent"
+msgstr "들여쓰기 해제"
+
msgid "Toggle Comment"
msgstr "주석 토글"
@@ -6921,6 +9187,9 @@ msgstr "모든 행 펼치기"
msgid "Evaluate Selection"
msgstr "선택 항목 평가"
+msgid "Toggle Word Wrap"
+msgstr "자동 줄 바꿈 토글"
+
msgid "Trim Trailing Whitespace"
msgstr "후행 공백 문자 제거"
@@ -6972,17 +9241,60 @@ msgstr "다음 중단점으로 이동"
msgid "Go to Previous Breakpoint"
msgstr "이전 중단점으로 이동"
+msgid "Shader Editor"
+msgstr "셰이더 에디터"
+
+msgid "New Shader Include"
+msgstr "셰이더 인클루드 만들기"
+
+msgid "Load Shader File"
+msgstr "셰이더 파일 불러오기"
+
+msgid "Load Shader Include File"
+msgstr "셰이더 인클루드 파일 불러오기"
+
+msgid "Save File"
+msgstr "파일 저장"
+
+msgid "Save File As"
+msgstr "파일을 다른 이름으로 저장"
+
+msgid "Open File in Inspector"
+msgstr "파일을 인스펙터에서 열기"
+
+msgid "Close File"
+msgstr "파일 닫기"
+
+msgid "Make the shader editor floating."
+msgstr "셰이더 에디터를 창으로 띄웁니다."
+
+msgid "No valid shader stages found."
+msgstr "올바른 셰이더 스테이지가 없습니다."
+
+msgid "Shader stage compiled without errors."
+msgstr "셰이더 스테이지를 문제없이 컴파일하였습니다."
+
+msgid ""
+"File structure for '%s' contains unrecoverable errors:\n"
+"\n"
+msgstr ""
+"'%s'의 파일 구조에 복구 불가능한 오류가 존재합니다:\n"
+"\n"
+
+msgid "ShaderFile"
+msgstr "ShaderFile"
+
msgid "This skeleton has no bones, create some children Bone2D nodes."
-msgstr "이 스켈레톤에는 본이 없습니다. Bone2D노드를 자식으로 만드세요."
+msgstr "이 스켈레톤에는 본이 없습니다. 자식 Bone2D 노드를 만드세요."
msgid "Set Rest Pose to Bones"
-msgstr "본에게 대기 자세 설정"
+msgstr "본에 대기 자세 설정"
msgid "Create Rest Pose from Bones"
-msgstr "본의 대기 자세 만들기"
+msgstr "본으로부터 대기 자세 만들기"
msgid "Skeleton2D"
-msgstr "스켈레톤2D"
+msgstr "Skeleton2D"
msgid "Reset to Rest Pose"
msgstr "대기 자세로 재설정"
@@ -6990,12 +9302,76 @@ msgstr "대기 자세로 재설정"
msgid "Overwrite Rest Pose"
msgstr "대기 자세 덮어 쓰기"
+msgid "Set Bone Transform"
+msgstr "본 변형 설정"
+
+msgid "Set Bone Rest"
+msgstr "본 대기 자세 설정"
+
+msgid "Cannot create a physical skeleton for a Skeleton3D node with no bones."
+msgstr "본이 없는 Skeleton3D 노드에 물리적 스켈레톤을 만들 수 없습니다."
+
msgid "Create physical bones"
msgstr "물리적 본 만들기"
+msgid "Cannot export a SkeletonProfile for a Skeleton3D node with no bones."
+msgstr "본이 없는 Skeleton3D 노드의 SkeletonProfile을 내보낼 수 없습니다."
+
+msgid "Export Skeleton Profile As..."
+msgstr "스켈레톤 프로필을 다른 이름으로 내보내기..."
+
+msgid "Set Bone Parentage"
+msgstr "본 부모 설정"
+
+msgid "Skeleton3D"
+msgstr "Skeleton3D"
+
+msgid "Reset All Bone Poses"
+msgstr "모든 본 포즈 재설정"
+
+msgid "Reset Selected Poses"
+msgstr "선택된 포즈 재설정"
+
+msgid "Apply All Poses to Rests"
+msgstr "모든 포즈를 대기 자세에 적용"
+
+msgid "Apply Selected Poses to Rests"
+msgstr "선택된 포즈를 대기 자세에 적용"
+
+msgid "Create Physical Skeleton"
+msgstr "물리적 스켈레톤 생성"
+
+msgid "Export Skeleton Profile"
+msgstr "스켈레톤 프로필 내보내기"
+
+msgid ""
+"Edit Mode\n"
+"Show buttons on joints."
+msgstr ""
+"편집 모드\n"
+"관절 위에 버튼을 보입니다."
+
+msgid "Insert key of bone poses already exist track."
+msgstr "이미 존재하는 트랙의 본 포즈에 키를 삽입합니다."
+
+msgid "Insert key of all bone poses."
+msgstr "모든 본 포즈의 키를 삽입합니다."
+
+msgid "Insert Key (All Bones)"
+msgstr "키 삽입 (모든 본에)"
+
+msgid "Bone Transform"
+msgstr "본 변형"
+
msgid "Play IK"
msgstr "IK 실행"
+msgid "Create MeshInstance2D"
+msgstr "MeshInstance2D 생성"
+
+msgid "MeshInstance2D Preview"
+msgstr "MeshInstance2D 미리보기"
+
msgid "Create Polygon2D"
msgstr "Polygon2D 만들기"
@@ -7017,6 +9393,9 @@ msgstr "LightOccluder2D 미리보기"
msgid "Can't convert a Sprite2D from a foreign scene."
msgstr "다른 씬으로부터 Sprite2D를 변환할 수 없습니다."
+msgid "Sprite2D is empty!"
+msgstr "Sprite2D가 비어 있습니다!"
+
msgid "Can't convert a sprite using animation frames to mesh."
msgstr "애니메이션 프레임을 사용하는 스프라이트를 메시로 변환할 수 없습니다."
@@ -7044,6 +9423,9 @@ msgstr "잘못된 지오메트리. 조명 어클루더를 만들 수 없습니
msgid "Create LightOccluder2D Sibling"
msgstr "LightOccluder2D 동기 만들기"
+msgid "Sprite2D"
+msgstr "Sprite2D"
+
msgid "Simplification:"
msgstr "단순화:"
@@ -7092,30 +9474,145 @@ msgstr "애니메이션을 삭제할까요?"
msgid "Change Animation FPS"
msgstr "애니메이션 FPS 바꾸기"
+msgid "Set Frame Duration"
+msgstr "프레임 길이 설정"
+
msgid "(empty)"
msgstr "(비었음)"
msgid "Animations:"
msgstr "애니메이션:"
+msgid "Animation Speed"
+msgstr "애니메이션 속도"
+
+msgid "Filter Animations"
+msgstr "애니메이션 필터"
+
+msgid "Delete Animation"
+msgstr "애니메이션 삭제"
+
+msgid "This resource does not have any animations."
+msgstr "이 리소스에는 애니메이션이 없습니다."
+
msgid "Animation Frames:"
msgstr "애니메이션 프레임:"
+msgid "Frame Duration:"
+msgstr "프레임 길이:"
+
msgid "Zoom Reset"
msgstr "줌 재설정"
+msgid "Add frame from file"
+msgstr "파일에서 프레임 추가"
+
+msgid "Add frames from sprite sheet"
+msgstr "스프라이트 시트에서 프레임 추가"
+
+msgid "Delete Frame"
+msgstr "프레임 삭제"
+
+msgid "Copy Frame"
+msgstr "프레임 복사"
+
+msgid "Insert Empty (Before Selected)"
+msgstr "빈 프레임 삽입 (앞에)"
+
+msgid "Insert Empty (After Selected)"
+msgstr "빈 프레임 삽입 (뒤에)"
+
+msgid "Move Frame Left"
+msgstr "프레임을 왼쪽으로 이동"
+
+msgid "Move Frame Right"
+msgstr "프레임을 오른쪽으로 이동"
+
msgid "Select Frames"
msgstr "프레임 선택"
+msgid "Frame Order"
+msgstr "프레임 순서"
+
+msgid "As Selected"
+msgstr "선택한 대로"
+
+msgid "By Row"
+msgstr "행을 기준으로"
+
+msgid "Left to Right, Top to Bottom"
+msgstr "좌에서 우로, 상에서 하로"
+
+msgid "Left to Right, Bottom to Top"
+msgstr "좌에서 우로, 하에서 상으로"
+
+msgid "Right to Left, Top to Bottom"
+msgstr "우에서 좌로, 상에서 하로"
+
+msgid "Right to Left, Bottom to Top"
+msgstr "우에서 좌로, 하에서 상으로"
+
+msgid "By Column"
+msgstr "열을 기준으로"
+
+msgid "Top to Bottom, Left to Right"
+msgstr "상에서 하로, 좌에서 우로"
+
+msgid "Top to Bottom, Right to Left"
+msgstr "상에서 하로, 우에서 좌로"
+
+msgid "Bottom to Top, Left to Right"
+msgstr "하에서 상으로, 좌에서 우로"
+
+msgid "Bottom to Top, Right to Left"
+msgstr "하에서 상으로, 우에서 좌로"
+
+msgid "Select None"
+msgstr "선택 해제"
+
+msgid "Toggle Settings Panel"
+msgstr "설정 패널 토글"
+
+msgid "Horizontal"
+msgstr "수평"
+
+msgid "Vertical"
+msgstr "수직"
+
msgid "Size"
msgstr "크기"
+msgid "Separation"
+msgstr "간격"
+
+msgid "Offset"
+msgstr "오프셋"
+
msgid "Create Frames from Sprite Sheet"
msgstr "스프라이트 시트에서 프레임 만들기"
msgid "SpriteFrames"
msgstr "스프라이트 프레임"
+msgid "Warnings should be fixed to prevent errors."
+msgstr "오류를 방지하기 위해 경고를 수정하는 것이 좋습니다."
+
+msgid ""
+"This shader has been modified on disk.\n"
+"What action should be taken?"
+msgstr ""
+"이 셰이더는 디스크에서 수정했습니다.\n"
+"어떻게 하시겠습니까?"
+
+msgid "%s Mipmaps"
+msgstr "%s 밉맵"
+
+msgid "Memory: %s"
+msgstr "메모리: %s"
+
+msgid "No Mipmaps"
+msgstr "밉맵 없음"
+
msgid "Set Region Rect"
msgstr "사각 영역 설정"
@@ -7140,6 +9637,12 @@ msgstr "단계:"
msgid "Separation:"
msgstr "간격:"
+msgid "Region Editor"
+msgstr "구역 에디터"
+
+msgid "Edit Region"
+msgstr "구역 편집"
+
msgid "Styleboxes"
msgstr "스타일박스"
@@ -7168,6 +9671,9 @@ msgid "1 font size"
msgid_plural "{num} font sizes"
msgstr[0] "{num} 폰트 크기"
+msgid "No font sizes found."
+msgstr "글꼴 크기를 찾을 수 없습니다."
+
msgid "1 icon"
msgid_plural "{num} icons"
msgstr[0] "{num} 아이콘"
@@ -7201,6 +9707,12 @@ msgstr "에디터를 업데이트 중"
msgid "Finalizing"
msgstr "마무리 중"
+msgid "Import Theme Items"
+msgstr "테마 항목 가져오기"
+
+msgid "Filter Items"
+msgstr "개체 필터"
+
msgid "With Data"
msgstr "데이터와 함께"
@@ -7234,6 +9746,18 @@ msgstr "보이는 모든 글꼴 항목과 그 데이터를 선택합니다."
msgid "Deselect all visible font items."
msgstr "보이는 모든 글꼴 항목을 선택 해제합니다."
+msgid "Font sizes"
+msgstr "폰트 크기"
+
+msgid "Select all visible font size items."
+msgstr "보이는 모든 글꼴 크기 항목을 선택합니다."
+
+msgid "Select all visible font size items and their data."
+msgstr "보이는 모든 글꼴 크기 항목과 그 데이터를 선택합니다."
+
+msgid "Deselect all visible font size items."
+msgstr "보이는 모든 글꼴 크기 항목을 선택 해제합니다."
+
msgid "Select all visible icon items."
msgstr "보이는 모든 아이콘 항목을 선택합니다."
@@ -7313,6 +9837,9 @@ msgstr "모든 상수 항목 제거"
msgid "Remove All Font Items"
msgstr "모든 글꼴 항목 제거"
+msgid "Remove All Font Size Items"
+msgstr "모든 글꼴 크기 항목 제거"
+
msgid "Remove All Icon Items"
msgstr "모든 아이콘 항목 제거"
@@ -7326,12 +9853,30 @@ msgstr ""
"이 테마 타입은 비어 있습니다.\n"
"직접 또는 다른 테마에서 가져와서 테마에 더 많은 항목을 추가하세요."
+msgid "Remove Theme Item"
+msgstr "테마 항목 제거"
+
msgid "Add Theme Type"
msgstr "테마 유형 추가"
+msgid "Create Theme Item"
+msgstr "테마 항목 생성"
+
msgid "Remove Theme Type"
msgstr "테마 유형 제거"
+msgid "Remove Data Type Items From Theme"
+msgstr "테마에서 데이터 타입 항목 제거"
+
+msgid "Remove Class Items From Theme"
+msgstr "테마에서 클래스 항목 제거"
+
+msgid "Remove Custom Items From Theme"
+msgstr "테마에서 커스텀 항목 제거"
+
+msgid "Remove All Items From Theme"
+msgstr "테마에서 모든 항목 제거"
+
msgid "Add Color Item"
msgstr "색상 항목 추가"
@@ -7341,6 +9886,9 @@ msgstr "상수 항목 추가"
msgid "Add Font Item"
msgstr "글꼴 항목 추가"
+msgid "Add Font Size Item"
+msgstr "글꼴 크기 항목 추가"
+
msgid "Add Icon Item"
msgstr "아이콘 항목 추가"
@@ -7356,12 +9904,18 @@ msgstr "상수 항목 이름 바꾸기"
msgid "Rename Font Item"
msgstr "글꼴 항목 이름 바꾸기"
+msgid "Rename Font Size Item"
+msgstr "글꼴 크기 항목 이름 바꾸기"
+
msgid "Rename Icon Item"
msgstr "아이콘 항목 이름 바꾸기"
msgid "Rename Stylebox Item"
msgstr "스타일박스 항목 이름 바꾸기"
+msgid "Rename Theme Item"
+msgstr "테마 항목 이름 바꾸기"
+
msgid "Invalid file, not a Theme resource."
msgstr "잘못된 파일, 테마 리소스가 아닙니다."
@@ -7459,12 +10013,48 @@ msgstr "항목 타입 추가"
msgid "Add Type"
msgstr "타입 추가"
+msgid "Override All Default Theme Items"
+msgstr "모든 기본 테마 항목 오버라이드"
+
+msgid "Override Theme Item"
+msgstr "테마 항목 오버라이드"
+
+msgid "Set Color Item in Theme"
+msgstr "테마의 색상 항목 설정"
+
+msgid "Set Constant Item in Theme"
+msgstr "테마의 상수 항목 설정"
+
+msgid "Set Font Size Item in Theme"
+msgstr "테마의 폰트 크기 항목 설정"
+
+msgid "Set Font Item in Theme"
+msgstr "테마의 폰트 항목 설정"
+
+msgid "Set Icon Item in Theme"
+msgstr "테마의 아이콘 항목 설정"
+
+msgid "Set Stylebox Item in Theme"
+msgstr "테마의 스타일박스 항목 설정"
+
+msgid "Pin Stylebox"
+msgstr "스타일박스 고정"
+
+msgid "Unpin Stylebox"
+msgstr "스타일박스 고정 해제"
+
+msgid "Set Theme Type Variation"
+msgstr "테마 타입 바리에이션 설정"
+
msgid "Set Variation Base Type"
-msgstr "변형 기본 유형 설정"
+msgstr "바리에이션 기본 유형 설정"
msgid "Set Base Type"
msgstr "기본 유형 설정"
+msgid "Add a type from a list of available types or create a new one."
+msgstr "사용 가능한 타입 목록에서 타입을 추가하거나 새로운 타입을 만드세요."
+
msgid "Show Default"
msgstr "디폴트 보이기"
@@ -7588,6 +10178,87 @@ msgstr "잘못된 파일, PackedScene 리소스가 아닙니다."
msgid "Reload the scene to reflect its most actual state."
msgstr "씬을 새로 고쳐 가장 실제 상태를 반영합니다."
+msgid "Merge TileSetAtlasSource"
+msgstr "TileSetAtlasSource 병합"
+
+msgid "%s (ID: %d)"
+msgstr "%s (ID: %d)"
+
+msgid "Atlas Merging"
+msgstr "아틀라스 병합"
+
+msgid "Merge (Keep original Atlases)"
+msgstr "병합 (원본 아틀라스 유지)"
+
+msgid "Merge"
+msgstr "병합"
+
+msgid "Next Line After Column"
+msgstr "열 뒤의 다음 줄"
+
+msgid "Please select two atlases or more."
+msgstr "두 개 이상의 아틀라스를 선택해 주세요."
+
+msgid ""
+"Source: %d\n"
+"Atlas coordinates: %s\n"
+"Alternative: 0"
+msgstr ""
+"소스: %d\n"
+"아틀라스 좌표: %s\n"
+"대체: 0"
+
+msgid ""
+"Source: %d\n"
+"Atlas coordinates: %s\n"
+"Alternative: %d"
+msgstr ""
+"소스: %d\n"
+"아틀라스 좌표: %s\n"
+"대체: %d"
+
+msgid "No atlas source with a valid texture selected."
+msgstr "올바른 텍스쳐가 선택된 아틀라스 소스가 없습니다."
+
+msgid "Base Tiles"
+msgstr "기본 타일"
+
+msgid "Alternative Tiles"
+msgstr "대체 타일"
+
+msgid "Reset Polygons"
+msgstr "폴리곤 재설정"
+
+msgid "Clear Polygons"
+msgstr "폴리곤 모두 삭제"
+
+msgid "Rotate Polygons Right"
+msgstr "폴리곤 오른쪽으로 회전"
+
+msgid "Rotate Polygons Left"
+msgstr "폴리곤 왼쪽으로 회전"
+
+msgid "Flip Polygons Horizontally"
+msgstr "폴리곤 수평으로 뒤집기"
+
+msgid "Flip Polygons Vertically"
+msgstr "폴리곤 수직으로 뒤집기"
+
+msgid "Edit Polygons"
+msgstr "폴리곤 편집"
+
+msgid "Add polygon tool"
+msgstr "폴리곤 생성 툴"
+
+msgid "Edit points tool"
+msgstr "점 편집 툴"
+
+msgid "Delete points tool"
+msgstr "점 삭제 툴"
+
+msgid "Reset to default tile shape"
+msgstr "기본 타일 모양으로 재설정"
+
msgid "Rotate Right"
msgstr "오른쪽으로 회전"
@@ -7600,15 +10271,346 @@ msgstr "수평으로 뒤집기"
msgid "Flip Vertically"
msgstr "수직으로 뒤집기"
+msgid "Disable Snap"
+msgstr "스냅 끄기"
+
+msgid "Half-Pixel Snap"
+msgstr "절반-픽셀 스냅"
+
+msgid "Painting Tiles Property"
+msgstr "칠하는 타일 속성"
+
+msgid "Painting:"
+msgstr "칠하는 중:"
+
+msgid "Picker"
+msgstr "선택기"
+
+msgid "No terrains"
+msgstr "지형 없음"
+
+msgid "No terrain"
+msgstr "지형 없음"
+
+msgid "Painting Terrain Set"
+msgstr "지형 세트 칠하는 중"
+
+msgid "Painting Terrain"
+msgstr "지형 칠하는 중"
+
+msgid "No Texture Atlas Source (ID: %d)"
+msgstr "텍스쳐 아틀라스 소스 없음 (ID: %d)"
+
+msgid "Scene Collection Source (ID: %d)"
+msgstr "씬 컬렉션 소스 (ID: %d)"
+
+msgid "Unknown Type Source (ID: %d)"
+msgstr "알 수 없는 타입 소스 (ID: %d)"
+
+msgid "Add TileSet pattern"
+msgstr "타일셋 패턴 추가"
+
+msgid "Remove TileSet patterns"
+msgstr "타일셋 패턴 제거"
+
+msgid "Index: %d"
+msgstr "인덱스: %d"
+
+msgid "Tile with Invalid Scene"
+msgstr "잘못된 씬의 타일"
+
+msgid "Delete tiles"
+msgstr "타일 삭제"
+
+msgid "Drawing Rect:"
+msgstr "사각형 그리는 중:"
+
+msgid "Change selection"
+msgstr "선택 수정"
+
+msgid "Move tiles"
+msgstr "타일 이동"
+
+msgid "Paint tiles"
+msgstr "타일 칠하기"
+
+msgid "Paste tiles"
+msgstr "타일 붙여넣기"
+
+msgid "Selection"
+msgstr "선택"
+
+msgid "Paint"
+msgstr "칠하기"
+
+msgid "Shift: Draw line."
+msgstr "Shift: 직선을 그립니다."
+
+msgid "Shift+Ctrl: Draw rectangle."
+msgstr "Shift+Ctrl: 사각형을 그립니다."
+
+msgctxt "Tool"
+msgid "Line"
+msgstr "직선"
+
+msgid "Rect"
+msgstr "직사각형"
+
+msgid "Bucket"
+msgstr "페인트통"
+
+msgid "Alternatively hold Ctrl with other tools to pick tile."
+msgstr "다른 툴에서도 Ctrl을 홀드하면서 타일을 선택할 수 있습니다."
+
+msgid "Eraser"
+msgstr "지우개"
+
+msgid "Alternatively use RMB to erase tiles."
+msgstr "우클릭으로도 타일을 지울 수 있습니다."
+
+msgid "Contiguous"
+msgstr "인접"
+
+msgid "Place Random Tile"
+msgstr "랜덤 타일 놓기"
+
+msgid ""
+"Modifies the chance of painting nothing instead of a randomly selected tile."
+msgstr "선택된 타일을 칠하는 대신 아무것도 칠하지 않을 확률을 지정합니다."
+
+msgid "Scattering:"
+msgstr "흩뿌리기:"
+
msgid "Tiles"
msgstr "타일"
+msgid ""
+"This TileMap's TileSet has no source configured. Go to the TileSet bottom "
+"tab to add one."
+msgstr ""
+"이 타일맵의 타일셋에 지정된 소스가 없습니다. TileSet의 아래 탭에서 소스를 하"
+"나 추가하세요."
+
+msgid "Sort sources"
+msgstr "소스 정렬"
+
+msgid "Sort by ID (Ascending)"
+msgstr "ID순 정렬 (오름차순)"
+
+msgid "Sort by ID (Descending)"
+msgstr "ID순 정렬 (내림차순)"
+
+msgid "Invalid source selected."
+msgstr "잘못된 소스가 선택되었습니다."
+
+msgid "Patterns"
+msgstr "패턴"
+
+msgid "Drag and drop or paste a TileMap selection here to store a pattern."
+msgstr ""
+"타일맵 선택을 여기에 드래그 & 드롭하거나 붙여넣어서 패턴으로 저장합니다."
+
+msgid "Paint terrain"
+msgstr "지형 칠하기"
+
+msgid "Matches Corners and Sides"
+msgstr "변과 꼭지점 매치"
+
+msgid "Matches Corners Only"
+msgstr "꼭지점만 매치"
+
+msgid "Matches Sides Only"
+msgstr "변만 매치"
+
+msgid "Terrain Set %d (%s)"
+msgstr "지형 세트 %d (%s)"
+
+msgid ""
+"Connect mode: paints a terrain, then connects it with the surrounding tiles "
+"with the same terrain."
+msgstr "연결 모드: 지형을 칠하면, 둘러싸는 타일들을 같은 지형으로 연결합니다."
+
+msgid ""
+"Path mode: paints a terrain, thens connects it to the previous tile painted "
+"within the same stroke."
+msgstr "경로 모드: 지형을 칠하면, 같은 획에서 칠한 이전 타일과 연결합니다."
+
+msgid "Terrains"
+msgstr "지형"
+
+msgid "Replace Tiles with Proxies"
+msgstr "타일을 프록시로 바꾸기"
+
+msgid "No Layers"
+msgstr "레이어 없음"
+
+msgid "Select Next Tile Map Layer"
+msgstr "다음 타일맵 레이어 선택"
+
+msgid "Select Previous Tile Map Layer"
+msgstr "이전 타일맵 레이어 선택"
+
+msgid "TileMap Layers"
+msgstr "타일맵 레이어"
+
+msgid "Highlight Selected TileMap Layer"
+msgstr "선택된 타일맵 레이어 강조"
+
+msgid "Toggle grid visibility."
+msgstr "그리드 가시성을 토글합니다."
+
+msgid "Automatically Replace Tiles with Proxies"
+msgstr "자동으로 타일을 프록시로 바꾸기"
+
+msgid ""
+"The edited TileMap node has no TileSet resource.\n"
+"Create or load a TileSet resource in the Tile Set property in the inspector."
+msgstr ""
+"변경된 타일맵 노드에 타일셋 리소스가 없습니다.\n"
+"인스펙터의 타일 셋 속성에서 타일셋 리소스를 생성하거나 불러오세요."
+
+msgid "Remove Tile Proxies"
+msgstr "타일 프록시 제거"
+
+msgid "Delete All Tile Proxies"
+msgstr "모든 타일 프록시 삭제"
+
+msgid "From Coords"
+msgstr "좌표로부터"
+
+msgid "Global actions:"
+msgstr "전역 액션:"
+
+msgid "Atlas"
+msgstr "아틀라스"
+
+msgid "Base Tile"
+msgstr "기본 타일"
+
+msgid "Alternative Tile"
+msgstr "다른 타일"
+
+msgid "Occlusion Layer %d"
+msgstr "오클루전 레이어 %d"
+
+msgid "Probability"
+msgstr "확률"
+
+msgid "Physics"
+msgstr "물리"
+
+msgid "Physics Layer %d"
+msgstr "물리 레이어 %d"
+
+msgid "Navigation Layer %d"
+msgstr "네비게이션 레이어 %d"
+
+msgid "Custom Data"
+msgstr "커스텀 데이터"
+
+msgid "Custom Data %d"
+msgstr "커스텀 데이터 %d"
+
+msgid "Select a property editor"
+msgstr "속성 편집기 선택"
+
+msgid "Create tiles"
+msgstr "타일 만들기"
+
+msgid "Create a tile"
+msgstr "타일 만들기"
+
+msgid "Remove tiles"
+msgstr "타일 제거"
+
+msgid "Move a tile"
+msgstr "타일 이동"
+
+msgid "Select tiles"
+msgstr "타일 선택"
+
+msgid "Resize a tile"
+msgstr "타일 크기 조정"
+
+msgid "Remove tile"
+msgstr "타일 제거"
+
+msgid "Select tiles."
+msgstr "타일을 선택하세요."
+
+msgid "No tiles selected."
+msgstr "선택한 타일이 없습니다."
+
+msgid "Paint Properties:"
+msgstr "칠하기 속성:"
+
+msgid "Create a Tile"
+msgstr "타일 만들기"
+
msgid "Yes"
msgstr "예"
+msgid "No"
+msgstr "아니요"
+
+msgid "Add a new atlas source"
+msgstr "새로운 아틀라스 소스 추가"
+
+msgid "Remove source"
+msgstr "소스 제거"
+
+msgid "Add atlas source"
+msgstr "아틀라스 소스 추가"
+
+msgid "Sort Sources"
+msgstr "소스 정렬"
+
+msgid "Scenes Collection"
+msgstr "씬 컬렉션"
+
+msgid "Open Atlas Merging Tool"
+msgstr "아틀라스 병합 도구 열기"
+
+msgid "Manage Tile Proxies"
+msgstr "타일 프록시 관리"
+
+msgid ""
+"No TileSet source selected. Select or create a TileSet source.\n"
+"You can create a new source by using the Add button on the left or by "
+"dropping a tileset texture onto the source list."
+msgstr ""
+"TileSet 소스가 선택되지 않았습니다. TileSet 소스를 선택하거나 만드세요.\n"
+"왼쪽에 있는 추가 버튼을 누르거나 소스 목록에 타일셋 텍스쳐를 드롭하여 새로운 "
+"소스를 만들 수 있습니다."
+
+msgid "Add new patterns in the TileMap editing mode."
+msgstr "타일맵 편집 모드에 새로운 패턴을 추가합니다."
+
+msgid "Add a Scene Tile"
+msgstr "씬 타일 추가"
+
+msgid "Remove a Scene Tile"
+msgstr "씬 타일 제거"
+
+msgid "Scenes collection properties:"
+msgstr "씬 컬렉션 속성:"
+
+msgid "Tile properties:"
+msgstr "타일 속성:"
+
msgid "TileSet"
msgstr "타일셋"
+msgid "TileMap"
+msgstr "타일맵"
+
+msgid ""
+"No VCS plugins are available in the project. Install a VCS plugin to use VCS "
+"integration features."
+msgstr ""
+"이 프로젝트에는 VCS 플러그인이 없습니다. VCS 통합 기능을 사용하려면 VCS 플러"
+"그인을 설치하세요."
+
msgid "Error"
msgstr "오류"
@@ -7621,11 +10623,17 @@ msgstr ""
msgid "Commit"
msgstr "커밋"
+msgid "Open in editor"
+msgstr "에디터에서 열기"
+
+msgid "Discard changes"
+msgstr "모든 변경사항 버리기"
+
msgid "Staged Changes"
-msgstr "단계적 변경"
+msgstr "스테이지된 변경 사항"
msgid "Unstaged Changes"
-msgstr "비단계적 변경"
+msgstr "스테이지되지 않은 변경 사항"
msgid "Commit:"
msgstr "커밋:"
@@ -7642,9 +10650,24 @@ msgstr "%s 분기를 제거하시겠습니까?"
msgid "Do you want to remove the %s remote?"
msgstr "%s 리모트를 제거하시겠습니까?"
+msgid "Create VCS metadata files for:"
+msgstr "VCS 메타데이터 생성:"
+
+msgid "Existing VCS metadata files will be overwritten."
+msgstr "존재하는 VCS 메타데이터 파일은 덮어씌워질 것입니다."
+
+msgid "Local Settings"
+msgstr "로컬 설정"
+
msgid "Apply"
msgstr "적용"
+msgid "VCS Provider"
+msgstr "VCS 제공자"
+
+msgid "Connect to VCS"
+msgstr "VCS에 연결"
+
msgid "Remote Login"
msgstr "원격 로그인"
@@ -7675,6 +10698,14 @@ msgstr "새 변경사항 감지"
msgid "Discard all changes"
msgstr "모든 변경사항 버리기"
+msgid "This operation is IRREVERSIBLE. Your changes will be deleted FOREVER."
+msgstr ""
+"이 행동은 절대로 되돌릴 수 없습니다. 당신의 변경 사항이 영구적으로 완전히 삭"
+"제될 것입니다."
+
+msgid "Permanentally delete my changes"
+msgstr "내 변경 사항 영구적으로 삭제"
+
msgid "Stage all changes"
msgstr "모든 변경사항 스테이징"
@@ -7747,6 +10778,9 @@ msgstr "타입체인지"
msgid "Unmerged"
msgstr "미병합"
+msgid "View file diffs before committing them to the latest version"
+msgstr "최신 버전으로 커밋하기 전 파일 차이점 보기"
+
msgid "View:"
msgstr "보기:"
@@ -7754,7 +10788,7 @@ msgid "Split"
msgstr "분할"
msgid "Unified"
-msgstr "통합됨"
+msgstr "통합"
msgid "E constant (2.718282). Represents the base of the natural logarithm."
msgstr "E 상수 (2.718282). 자연 로그의 밑을 나타냄."
@@ -7786,36 +10820,163 @@ msgstr "입력 추가"
msgid "Add Output"
msgstr "출력 추가"
+msgid "Float"
+msgstr "Float"
+
+msgid "Int"
+msgstr "Int"
+
+msgid "UInt"
+msgstr "UInt"
+
+msgid "Vector2"
+msgstr "Vector2"
+
+msgid "Vector3"
+msgstr "Vector3"
+
+msgid "Vector4"
+msgstr "Vector4"
+
msgid "Boolean"
-msgstr "불리언"
+msgstr "Boolean"
msgid "Sampler"
msgstr "샘플러"
+msgid "[default]"
+msgstr "[기본]"
+
+msgid ""
+"The 2D preview cannot correctly show the result retrieved from instance "
+"parameter."
+msgstr ""
+"2D 프리뷰는 인스턴스 파라미터로부터 받아온 결과값을 정확하게 보여주지 못합니"
+"다."
+
msgid "Add Input Port"
msgstr "입력 포트 추가하기"
msgid "Add Output Port"
msgstr "출력 포트 추가하기"
+msgid "Change Input Port Type"
+msgstr "입력 포트 타입 바꾸기"
+
+msgid "Change Output Port Type"
+msgstr "출력 포트 타입 바꾸기"
+
+msgid "Change Input Port Name"
+msgstr "입력 포트 이름 바꾸기"
+
+msgid "Change Output Port Name"
+msgstr "출력 포트 이름 바꾸기"
+
+msgid "Expand Output Port"
+msgstr "출력 포트 확장하기"
+
+msgid "Shrink Output Port"
+msgstr "출력 포트 줄이기"
+
msgid "Remove Input Port"
msgstr "입력 포트 제거"
msgid "Remove Output Port"
msgstr "출력 포트 제거"
+msgid "Set VisualShader Expression"
+msgstr "VisualShader 표현식 설정"
+
+msgid "Resize VisualShader Node"
+msgstr "VisualShader 노드 크기 조정"
+
+msgid "Hide Port Preview"
+msgstr "포트 미리보기 숨기기"
+
+msgid "Show Port Preview"
+msgstr "포트 미리보기 보이기"
+
+msgid "Set Comment Node Title"
+msgstr "주석 노드 제목 설정"
+
+msgid "Set Comment Node Description"
+msgstr "주석 노드 설명 설정"
+
+msgid "Set Parameter Name"
+msgstr "매개변수 이름 설정"
+
msgid "Set Input Default Port"
msgstr "입력 디폴트 포트 설정"
msgid "Add Node to Visual Shader"
msgstr "노드를 비주얼 셰이더에 추가"
+msgid "Add Varying to Visual Shader: %s"
+msgstr "비주얼셰이더에 Varying 추가: %s"
+
+msgid "Remove Varying from Visual Shader: %s"
+msgstr "비주얼셰이더에서 Varying 제거: %s"
+
msgid "Node(s) Moved"
msgstr "노드 이동됨"
+msgid "Convert Constant Node(s) To Parameter(s)"
+msgstr "상수 노드를 매개 변수로 변환"
+
+msgid "Convert Parameter Node(s) To Constant(s)"
+msgstr "매개 변수 노드를 상수로 변환"
+
+msgid "Delete VisualShader Node"
+msgstr "비주얼셰이더 노드 제거"
+
+msgid "Delete VisualShader Node(s)"
+msgstr "비주얼셰이더 노드 제거"
+
+msgid "Float Constants"
+msgstr "실수형 상수"
+
+msgid "Convert Constant(s) to Parameter(s)"
+msgstr "상수를 매개 변수로 변환"
+
+msgid "Convert Parameter(s) to Constant(s)"
+msgstr "매개 변수를 상수로 변환"
+
+msgid "Set Comment Title"
+msgstr "주석 제목 설정"
+
+msgid "Set Comment Description"
+msgstr "주석 설명 설정"
+
+msgid "Duplicate VisualShader Node(s)"
+msgstr "비주얼 셰이더 노드 복제"
+
+msgid "Paste VisualShader Node(s)"
+msgstr "비주얼 셰이더 노드 붙여넣기"
+
+msgid "Cut VisualShader Node(s)"
+msgstr "비주얼 셰이더 노드 잘라내기"
+
msgid "Visual Shader Input Type Changed"
msgstr "비주얼 셰이더 입력 타입 변경됨"
+msgid "ParameterRef Name Changed"
+msgstr "ParameterRef 이름 변경됨"
+
+msgid "Varying Name Changed"
+msgstr "Varying 이름 변경됨"
+
+msgid "Set Constant: %s"
+msgstr "상수 설정: %s"
+
+msgid "Invalid name for varying."
+msgstr "올바르지 않은 varying 이름입니다."
+
+msgid "Varying with that name is already exist."
+msgstr "이 이름으로 된 varying이 이미 있습니다."
+
+msgid "Add Node(s) to Visual Shader"
+msgstr "노드를 비주얼 셰이더에 추가"
+
msgid "Vertex"
msgstr "꼭짓점"
@@ -7828,20 +10989,56 @@ msgstr "라이트"
msgid "Process"
msgstr "프로세스"
+msgid "Collide"
+msgstr "콜라이드"
+
+msgid "Sky"
+msgstr "스카이"
+
+msgid "Fog"
+msgstr "포그"
+
+msgid "Manage Varyings"
+msgstr "Varying 관리"
+
+msgid "Add Varying"
+msgstr "Varying 추가"
+
+msgid "Remove Varying"
+msgstr "Varying 제거"
+
+msgid "Show generated shader code."
+msgstr "생성된 셰이더 코드를 보여줍니다."
+
+msgid "Generated Shader Code"
+msgstr "생성된 셰이더 코드"
+
msgid "Add Node"
msgstr "노드 추가"
+msgid "Clear Copy Buffer"
+msgstr "카피 버퍼 비우기"
+
+msgid "High-end node"
+msgstr "하이-엔드 노드"
+
msgid "Create Shader Node"
msgstr "셰이더 노드 만들기"
+msgid "Create Shader Varying"
+msgstr "셰이더 Varying 만들기"
+
+msgid "Delete Shader Varying"
+msgstr "셰이더 Varying 제거"
+
msgid "Color function."
-msgstr "색상 함수."
+msgstr "색상 함수입니다."
msgid "Color operator."
-msgstr "색상 연산자."
+msgstr "색상 연산자입니다."
msgid "Grayscale function."
-msgstr "회색조 함수."
+msgstr "회색조 함수입니다."
msgid "Converts HSV vector to RGB equivalent."
msgstr "HSV 벡터를 RGB로 변환합니다."
@@ -7850,37 +11047,43 @@ msgid "Converts RGB vector to HSV equivalent."
msgstr "RGB 벡터를 HSV로 변환합니다."
msgid "Sepia function."
-msgstr "세피아 함수."
+msgstr "세피아 함수입니다."
msgid "Burn operator."
-msgstr "번 연산자."
+msgstr "번 (Burn) 연산자입니다."
msgid "Darken operator."
-msgstr "어두움 연산자."
+msgstr "어둡게 하기 (Darken) 연산자입니다."
msgid "Difference operator."
-msgstr "차이 연산자."
+msgstr "차이 (Difference) 연산자입니다."
msgid "Dodge operator."
-msgstr "닷지 연산자."
+msgstr "닷지 (Dodge) 연산자입니다."
msgid "HardLight operator."
-msgstr "하드 라이트 연산자."
+msgstr "하드 라이트 (HardLight) 연산자입니다."
msgid "Lighten operator."
-msgstr "Lighten 연산자."
+msgstr "밝게 하기 (Lighten) 연산자입니다."
msgid "Overlay operator."
-msgstr "오버레이 연산자."
+msgstr "오버레이 (Overlay) 연산자입니다."
msgid "Screen operator."
-msgstr "화면 연산자."
+msgstr "스크린 (Screen) 연산자입니다."
msgid "SoftLight operator."
-msgstr "소프트 라이트 연산자."
+msgstr "소프트 라이트 (SoftLight) 연산자입니다."
msgid "Color constant."
-msgstr "색상 상수."
+msgstr "색상 상수입니다."
+
+msgid "Color parameter."
+msgstr "색상 매개 변수입니다."
+
+msgid "(Fragment/Light mode only) Derivative function."
+msgstr "(프래그먼트/라이트 모드만 가능) 미분 함수입니다."
msgid "Returns the boolean result of the %s comparison between two parameters."
msgstr "두 매개변수 사이 %s 비교의 불리언 결과 값을 반환합니다."
@@ -7919,6 +11122,41 @@ msgstr "보다 작거나 같다 (<=)"
msgid "Not Equal (!=)"
msgstr "같지 않다 (!=)"
+msgid ""
+"Returns an associated 3D vector if the provided boolean value is true or "
+"false."
+msgstr "불리언 값이 참이거나 거짓이면 관련 3D 벡터를 반환합니다."
+
+msgid ""
+"Returns an associated 2D vector if the provided boolean value is true or "
+"false."
+msgstr "불리언 값이 참이거나 거짓이면 2D 관련 벡터를 반환합니다."
+
+msgid ""
+"Returns an associated boolean if the provided boolean value is true or false."
+msgstr "불리언 값이 참이거나 거짓이면 관련 불리언을 반환합니다."
+
+msgid ""
+"Returns an associated floating-point scalar if the provided boolean value is "
+"true or false."
+msgstr "불리언 값이 참이거나 거짓이면 관련 실수형 스칼라를 반환합니다."
+
+msgid ""
+"Returns an associated integer scalar if the provided boolean value is true "
+"or false."
+msgstr "불리언 값이 참이거나 거짓이면 관련 정수형 스칼라를 반환합니다."
+
+msgid ""
+"Returns an associated transform if the provided boolean value is true or "
+"false."
+msgstr "불리언 값이 참이거나 거짓이면 관련 트랜스폼을 반환합니다."
+
+msgid ""
+"Returns an associated unsigned integer scalar if the provided boolean value "
+"is true or false."
+msgstr ""
+"불리언 값이 참이거나 거짓이면 관련 부호 없는 정수형 스칼라를 반환합니다."
+
msgid "Returns the boolean result of the comparison between two parameters."
msgstr "두 매개변수 사이 비교의 불리언 결과 값을 반환합니다."
@@ -7932,26 +11170,50 @@ msgstr ""
msgid "Boolean constant."
msgstr "불리언 상수."
+msgid "Boolean parameter."
+msgstr "불리언 매개변수."
+
+msgid "Translated to '%s' in Godot Shading Language."
+msgstr "Godot Shading Language에서 '%s'로 번역됩니다."
+
msgid "'%s' input parameter for all shader modes."
-msgstr "모든 셰이더 모드에 대한 '%s' 입력 매개변수."
+msgstr "모든 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
msgid "Input parameter."
-msgstr "입력 매개변수."
+msgstr "입력 매개변수입니다."
msgid "'%s' input parameter for vertex and fragment shader modes."
-msgstr "꼭짓점과 프래그먼트 셰이더 모드에 대한 '%s' 입력 매개변수."
+msgstr "꼭짓점과 프래그먼트 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
msgid "'%s' input parameter for fragment and light shader modes."
-msgstr "프래그먼트와 라이트 셰이더 모드에 대한 '%s' 입력 매개변수."
+msgstr "프래그먼트와 라이트 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
msgid "'%s' input parameter for fragment shader mode."
-msgstr "프래그먼트 셰이더 모드에 대한 '%s' 입력 매개변수."
+msgstr "프래그먼트 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
+
+msgid "'%s' input parameter for sky shader mode."
+msgstr "모든 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
+
+msgid "'%s' input parameter for fog shader mode."
+msgstr "포그 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
msgid "'%s' input parameter for light shader mode."
-msgstr "조명 셰이더 모드에 대한 '%s' 입력 매개변수."
+msgstr "라이트 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
msgid "'%s' input parameter for vertex shader mode."
-msgstr "꼭짓점 셰이더 모드에 대한 '%s' 입력 매개변수."
+msgstr "꼭짓점 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
+
+msgid "'%s' input parameter for start shader mode."
+msgstr "스타트 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
+
+msgid "'%s' input parameter for process shader mode."
+msgstr "프로세스 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
+
+msgid "'%s' input parameter for start and process shader modes."
+msgstr "스타트와 프로세스 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
+
+msgid "'%s' input parameter for process and collide shader modes."
+msgstr "프로세스와 콜라이드 셰이더 모드에 대한 '%s' 입력 매개변수입니다."
msgid "Returns the absolute value of the parameter."
msgstr "매개변수의 절대값을 반환합니다."
@@ -7977,6 +11239,9 @@ msgstr "매개변수들의 아크탄젠트 값을 반환합니다."
msgid "Returns the inverse hyperbolic tangent of the parameter."
msgstr "매개변수의 역쌍곡탄젠트 값을 반환합니다."
+msgid "Returns the result of bitwise NOT (~a) operation on the integer."
+msgstr "정수의 비트 단위 NOT (~a) 연산값을 반환합니다."
+
msgid ""
"Finds the nearest integer that is greater than or equal to the parameter."
msgstr "매개변수보다 크거나 같은 가장 가까운 정수를 찾습니다."
@@ -8108,6 +11373,15 @@ msgstr "매개변수의 쌍곡탄젠트 값을 반환합니다."
msgid "Finds the truncated value of the parameter."
msgstr "매개변수의 절사된 값을 찾습니다."
+msgid "Returns the result of bitwise AND (a & b) operation for two integers."
+msgstr "두 정수 사이 비트 단위 AND (a & b) 연산의 결과값을 반환합니다."
+
+msgid "Returns the result of bitwise OR (a | b) operation for two integers."
+msgstr "두 정수 사이 비트 단위 OR (a | b) 연산의 계산값을 반환합니다."
+
+msgid "Converts screen UV to a SDF."
+msgstr "스크린 UV를 SDF로 변환합니다."
+
msgid "Perform the cubic texture lookup."
msgstr "세제곱 텍스처 룩업을 수행합니다."
@@ -8145,6 +11419,12 @@ msgstr "변형의 역함수를 계산합니다."
msgid "Calculates the transpose of a transform."
msgstr "변형의 전치를 계산합니다."
+msgid "Sums two transforms."
+msgstr "두 개의 Transform을 더합니다."
+
+msgid "Subtracts two transforms."
+msgstr "두 Transform을 뺍니다."
+
msgid "Multiplies vector by transform."
msgstr "변형에 벡터를 곱합니다."
@@ -8271,13 +11551,27 @@ msgid ""
msgstr "(프래그먼트/라이트 모드만 가능) (벡터) 'x'와 'y'의 절대 미분 값의 합."
msgid ""
+"A rectangular area with a description string for better graph organization."
+msgstr ""
+"설명이 달린 사각형 영역입니다. 그래프를 보기 좋게 정리하는 데 사용합니다."
+
+msgid ""
"Custom Godot Shader Language expression, with custom amount of input and "
"output ports. This is a direct injection of code into the vertex/fragment/"
"light function, do not use it to write the function declarations inside."
msgstr ""
-"커스텀 입력 및 출력 포트로 이루어진, 커스텀 Godot 셰이더 언어 표현식. 꼭짓점/"
-"프래그먼트/라이트 함수에 직접 코드를 넣는 것이므로 코드 안에 함수 선언을 작성"
-"하는 용도로 쓰지 마세요."
+"커스텀 입력 및 출력 포트로 이루어진, 커스텀 Godot Shader Language 표현식입니"
+"다. 꼭짓점/프래그먼트/라이트 함수에 직접 코드를 넣는 것이므로 코드 안에 함수 "
+"선언을 작성하는 용도로 쓸 수 없습니다."
+
+msgid "A reference to an existing parameter."
+msgstr "기존 매개 변수에 대한 참조입니다."
+
+msgid "Get varying parameter."
+msgstr "varying 매개 변수를 받아옵니다."
+
+msgid "Set varying parameter."
+msgstr "varying 매개 변수를 설정합니다."
msgid "Edit Visual Property:"
msgstr "비주얼 속성 편집:"
@@ -8285,6 +11579,21 @@ msgstr "비주얼 속성 편집:"
msgid "Visual Shader Mode Changed"
msgstr "비주얼 셰이더 모드 변경됨"
+msgid "Voxel GI data is not local to the scene."
+msgstr "Voxel GI 데이터가 씬에 로컬이 아닙니다."
+
+msgid "Voxel GI data is part of an imported resource."
+msgstr "Voxel GI 데이터는 가져오기한 리소스의 일부입니다."
+
+msgid "Voxel GI data is an imported resource."
+msgstr "Voxel GI 데이터는 가져오기한 리소스입니다."
+
+msgid "Bake VoxelGI"
+msgstr "VoxelGI 굽기"
+
+msgid "Select path for VoxelGI Data File"
+msgstr "VoxelGI 데이터 파일 경로 선택"
+
msgid "The path specified doesn't exist."
msgstr "지정한 경로가 없습니다."
@@ -8306,6 +11615,20 @@ msgstr "\"project.godot\" 파일 또는 \".zip\" 파일을 선택해주세요."
msgid "This directory already contains a Godot project."
msgstr "디렉토리에 Godot 프로젝트가 이미 존재합니다."
+msgid ""
+"You cannot save a project in the selected path. Please make a new folder or "
+"choose a new path."
+msgstr ""
+"해당 경로에 프로젝트를 저장할 수 없습니다. 새 폴더를 만들거나 다른 경로를 골"
+"라주세요."
+
+msgid ""
+"The selected path is not empty. Choosing an empty folder is highly "
+"recommended."
+msgstr ""
+"선택된 경로는 비어있지 않습니다. 비어 있는 폴더를 선택하는 것을 매우 권장합니"
+"다."
+
msgid "New Game Project"
msgstr "새 게임 프로젝트"
@@ -8319,25 +11642,84 @@ msgid "Couldn't create folder."
msgstr "폴더를 만들 수 없습니다."
msgid "There is already a folder in this path with the specified name."
-msgstr "이미 이 경로에 이 이름과 같은 폴더가 있습니다."
+msgstr "이 경로에는 이 이름으로 된 폴더가 이미 있습니다."
msgid "It would be a good idea to name your project."
msgstr "프로젝트 이름을 정하는 게 좋을 것입니다."
+msgid "Supports desktop platforms only."
+msgstr "데스크톱 플랫폼만을 지원합니다."
+
+msgid "Advanced 3D graphics available."
+msgstr "고급 3D 그래픽을 사용할 수 있습니다."
+
+msgid "Can scale to large complex scenes."
+msgstr "크고 복잡한 씬도 충분히 그려낼 수 있습니다."
+
+msgid "Uses RenderingDevice backend."
+msgstr "RenderingDevice 백엔드를 사용합니다."
+
+msgid "Slower rendering of simple scenes."
+msgstr "단순한 씬을 렌더링할 때의 성능은 떨어집니다."
+
+msgid "Supports desktop + mobile platforms."
+msgstr "데스크톱과 모바일 플랫폼을 지원합니다."
+
+msgid "Less advanced 3D graphics."
+msgstr "조금 덜 고급인 3D 그래픽을 사용할 수 있습니다."
+
+msgid "Less scalable for complex scenes."
+msgstr "크고 복잡한 씬을 그려내기에는 좋지 않습니다."
+
+msgid "Fast rendering of simple scenes."
+msgstr "단순한 씬을 빠르게 그려낼 수 있습니다."
+
+msgid "Supports desktop, mobile + web platforms."
+msgstr "데스크톱, 모바일, 웹 플랫폼을 지원합니다."
+
+msgid "Least advanced 3D graphics (currently work-in-progress)."
+msgstr "고급 3D 그래픽 사용 능력이 가장 떨어집니다 (아직 작업 중입니다)."
+
+msgid "Intended for low-end/older devices."
+msgstr "저성능 또는 오래된 디바이스에서 사용하는 용도입니다."
+
+msgid "Uses OpenGL 3 backend (OpenGL 3.3/ES 3.0/WebGL2)."
+msgstr "OpenGL 3 백엔드 (OpenGL 3.3/ES 3.0/WebGL2)를 사용합니다."
+
+msgid "Fastest rendering of simple scenes."
+msgstr "단순한 씬을 가장 빠르게 그려낼 수 있습니다."
+
msgid "Invalid project path (changed anything?)."
-msgstr "잘못된 프로젝트 경로 (무언가를 변경하셨습니까?)."
+msgstr "잘못된 프로젝트 경로 (무언가를 변경하셨나요?)."
msgid ""
"Couldn't load project at '%s' (error %d). It may be missing or corrupted."
msgstr ""
-"프로젝트 경로에서 프로젝트를 불러올 수 없습니다 (오류 %d). 누락되거나 손상된 "
-"것 같습니다."
+"'%s'에서 프로젝트를 불러올 수 없습니다 (오류 %d). 프로젝트가 누락되거나 손상"
+"된 것 같습니다."
msgid "Couldn't save project at '%s' (error %d)."
-msgstr "'%s'에서 프로젝트를 저장 할 수 없었습니다."
+msgstr "'%s'에 프로젝트를 저장 할 수 없습니다 (오류 %d)."
+
+msgid "Warning: This folder is not empty"
+msgstr "경고: 빈 폴더가 아닙니다"
+
+msgid ""
+"You are about to create a Godot project in a non-empty folder.\n"
+"The entire contents of this folder will be imported as project resources!\n"
+"\n"
+"Are you sure you wish to continue?"
+msgstr ""
+"비어있지 않은 폴더에 Godot 프로젝트를 만들고 있습니다.\n"
+"그러면, 폴더 내의 모든 내용물들을 프로젝트 리소스로서 가져올 것입니다!\n"
+"\n"
+"정말로 진행하시겠습니까?"
msgid "Couldn't create project.godot in project path."
-msgstr "프로젝트 경로에서 project.godot 파일을 만들 수 없습니다."
+msgstr "프로젝트 경로에 project.godot 파일을 만들 수 없습니다."
+
+msgid "Couldn't create icon.svg in project path."
+msgstr "프로젝트 경로에 icon.svg 파일을 만들 수 없습니다."
msgid "Error opening package file, not in ZIP format."
msgstr "패키지 파일을 여는 중 오류. ZIP 형식이 아닙니다."
@@ -8381,6 +11763,18 @@ msgstr "프로젝트 설치 경로:"
msgid "Renderer:"
msgstr "렌더러:"
+msgid "The renderer can be changed later, but scenes may need to be adjusted."
+msgstr "렌더러는 나중에 바꿀 수 있지만, 씬을 조정해야 할 수도 있습니다."
+
+msgid "Version Control Metadata:"
+msgstr "버전 컨트롤 메타데이터:"
+
+msgid "Git"
+msgstr "Git"
+
+msgid "The project uses features unsupported by the current build:"
+msgstr "이 프로젝트는 현재 빌드에서는 지원하지 않는 기능을 사용합니다:"
+
msgid "Error: Project is missing on the filesystem."
msgstr "오류: 프로젝트가 파일시스템에서 누락되었습니다."
@@ -8400,13 +11794,161 @@ msgid "Can't open project at '%s'."
msgstr "'%s'에서 프로젝트를 열 수 없습니다."
msgid ""
+"You requested to open %d projects in parallel. Do you confirm?\n"
+"Note that usual checks for engine version compatibility will be bypassed."
+msgstr ""
+"프로젝트 %d개를 동시에 열려고 합니다. 확실합니까?\n"
+"엔진 버전 호환성에 대한 일반적인 체크를 건너뛸 것이니 주의하세요."
+
+msgid ""
+"The selected project \"%s\" does not specify its supported Godot version in "
+"its configuration file (\"project.godot\").\n"
+"\n"
+"Project path: %s\n"
+"\n"
+"If you proceed with opening it, it will be converted to Godot's current "
+"configuration file format.\n"
+"\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+"선택된 프로젝트 \"%s\"가 지원되는 Godot 버전 정보를 그 설정 파일(\"project."
+"godot\") 내에 명시하지 않았습니다.\n"
+"\n"
+"프로젝트 경로: %s\n"
+"\n"
+"파일 열기를 계속한다면, 현재 Godot의 구성 파일 형식으로 변환될 것입니다.\n"
+"\n"
+"경고: 더 이상 이 프로젝트를 이전 버전의 엔진에서 열 수 없을 것입니다."
+
+msgid ""
+"The selected project \"%s\" was generated by Godot 3.x, and needs to be "
+"converted for Godot 4.x.\n"
+"\n"
+"Project path: %s\n"
+"\n"
+"You have three options:\n"
+"- Convert only the configuration file (\"project.godot\"). Use this to open "
+"the project without attempting to convert its scenes, resources and "
+"scripts.\n"
+"- Convert the entire project including its scenes, resources and scripts "
+"(recommended if you are upgrading).\n"
+"- Do nothing and go back.\n"
+"\n"
+"Warning: If you select a conversion option, you won't be able to open the "
+"project with previous versions of the engine anymore."
+msgstr ""
+"선택된 프로젝트 \"%s\"는 Godot 3.x 버전에서 만들어졌으며, Godot 4.x에 맞게 변"
+"환되어야 합니다.\n"
+"\n"
+"프로젝트 경로: %s\n"
+"\n"
+"세 가지 선택지가 있습니다:\n"
+"- 설정 파일(\"project.godot\") 만을 변환합니다. 씬이나 리소스, 스크립트 등은 "
+"변환하려 하지 않고서 프로젝트를 엽니다.\n"
+"- 씬, 리소스, 스크립트를 포함한 프로젝트 전체를 변환합니다. 프로젝트를 업그레"
+"이드하려 할 경우엔 이 선택지를 권장합니다.\n"
+"- 취소하고 뒤로 돌아갑니다.\n"
+"\n"
+"경고: 프로젝트를 변환할 경우, 더 이상 이 프로젝트를 이전 버전의 엔진에서 열 "
+"수 없을 것입니다."
+
+msgid "Convert project.godot Only"
+msgstr "project.godot만 변환"
+
+msgid ""
+"The selected project \"%s\" was generated by an older engine version, and "
+"needs to be converted for this version.\n"
+"\n"
+"Project path: %s\n"
+"\n"
+"Do you want to convert it?\n"
+"\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+"다음 프로젝트 \"%s\"는 이전 버전에서 만든 것으로, 현재 버전에 맞게 변환해야 "
+"합니다:\n"
+"\n"
+"프로젝트 경로: %s\n"
+"\n"
+"변환할까요?\n"
+"\n"
+"경고: 더 이상 이 프로젝트를 이전 버전의 엔진에서 열 수 없을 것입니다."
+
+msgid "Convert project.godot"
+msgstr "project.godot 변환"
+
+msgid ""
+"Can't open project \"%s\" at the following path:\n"
+"\n"
+"%s\n"
+"\n"
+"The project settings were created by a newer engine version, whose settings "
+"are not compatible with this version."
+msgstr ""
+"다음 경로의 프로젝트 \"%s\"를 열 수 없습니다:\n"
+"\n"
+"%s\n"
+"\n"
+"프로젝트 설정이 이후 버전에 맞게 만들어졌습니다. 이 버전에서는 호환하지 않습"
+"니다."
+
+msgid ""
+"Warning: This project uses double precision floats, but this version of\n"
+"Godot uses single precision floats. Opening this project may cause data "
+"loss.\n"
+"\n"
+msgstr ""
+"경고: 이 프로젝트는 배정밀도 부동소수점(double precision float)을 사용하지"
+"만,\n"
+"이 버전의 Godot은 단정밀도 부동소수점(single precision float)을 사용합니다.\n"
+"프로젝트를 열면 데이터 손실이 발생할 수도 있습니다.\n"
+"\n"
+
+msgid ""
+"Warning: This project uses C#, but this build of Godot does not have\n"
+"the Mono module. If you proceed you will not be able to use any C# scripts.\n"
+"\n"
+msgstr ""
+"경고: 이 프로젝트는 C#을 사용하지만, 이 빌드의 Godot은 Mono 모듈을\n"
+"지원하지 않습니다. 계속 진행할 경우 C# 스크립트를 사용할 수 없습니다.\n"
+"\n"
+
+msgid ""
+"Warning: This project was built in Godot %s.\n"
+"Opening will upgrade or downgrade the project to Godot %s.\n"
+"\n"
+msgstr ""
+"경고: 이 프로젝트는 Godot %s에서 만들어졌습니다.\n"
+"프로젝트를 열면 이 프로젝트를 Godot %s로 업그레이드/다운그레이드할 것입니"
+"다.\n"
+"\n"
+
+msgid ""
+"Warning: This project uses the following features not supported by this "
+"build of Godot:\n"
+"\n"
+"%s\n"
+"\n"
+msgstr ""
+"경고: 이 프로젝트는 이 빌드의 Godot에서 지원하지 않는 다음과 같은 기능들을 사"
+"용합니다:\n"
+"\n"
+"%s\n"
+"\n"
+
+msgid "Open anyway? Project will be modified."
+msgstr "무시하고 열까요? 프로젝트가 수정될 것입니다."
+
+msgid ""
"Can't run project: no main scene defined.\n"
"Please edit the project and set the main scene in the Project Settings under "
"the \"Application\" category."
msgstr ""
"프로젝트를 실행할 수 없음: 메인 씬을 정의하지 않았습니다.\n"
-"프로젝트를 편집하고 프로젝트 설정의 \"Application\" 카테고리에서 메인 씬을 설"
-"정해주세요."
+"프로젝트를 편집하고 프로젝트 설정의 \"어플리케이션\" 카테고리에서 메인 씬을 "
+"설정해주세요."
msgid ""
"Can't run project: Assets need to be imported.\n"
@@ -8416,7 +11958,19 @@ msgstr ""
"프로젝트를 편집해서 최초 가져오기가 실행되도록 하세요."
msgid "Are you sure to run %d projects at once?"
-msgstr "한 번에 %d개의 프로젝트를 실행할 건가요?"
+msgstr "%d개의 프로젝트를 동시에 실행할까요?"
+
+msgid "Tag name can't be empty."
+msgstr "태그 이름은 비워둘 수 없습니다."
+
+msgid "Tag name can't contain spaces."
+msgstr "태그 이름은 공백을 포함할 수 없습니다."
+
+msgid "These characters are not allowed in tags: %s."
+msgstr "다음 문자들을 태그에 넣을 수 없습니다: %s."
+
+msgid "Tag name must be lowercase."
+msgstr "태그 이름은 소문자여야 합니다."
msgid "Remove %d projects from the list?"
msgstr "목록에서 프로젝트 %d개를 제거하시겠습니까?"
@@ -8449,6 +12003,9 @@ msgctxt "Application"
msgid "Project Manager"
msgstr "프로젝트 매니저"
+msgid "Filter Projects"
+msgstr "프로젝트 필터"
+
msgid ""
"This field filters projects by name and last path component.\n"
"To filter projects by name and full path, the query must contain at least "
@@ -8461,6 +12018,12 @@ msgstr ""
msgid "Loading, please wait..."
msgstr "로드 중, 기다려 주세요..."
+msgid "Last Edited"
+msgstr "마지막으로 수정됨"
+
+msgid "Tags"
+msgstr "태그"
+
msgid "New Project"
msgstr "새 프로젝트"
@@ -8476,6 +12039,9 @@ msgstr "프로젝트 스캔"
msgid "Edit Project"
msgstr "프로젝트 편집"
+msgid "Manage Tags"
+msgstr "태그 설정"
+
msgid "Remove Project"
msgstr "프로젝트 제거"
@@ -8497,6 +12063,30 @@ msgstr "모두 제거"
msgid "Also delete project contents (no undo!)"
msgstr "프로젝트 콘텐츠도 삭제 (되돌릴 수 없습니다!)"
+msgid "Convert Full Project"
+msgstr "프로젝트 전체 변환"
+
+msgid ""
+"This option will perform full project conversion, updating scenes, resources "
+"and scripts from Godot 3.x to work in Godot 4.0.\n"
+"\n"
+"Note that this is a best-effort conversion, i.e. it makes upgrading the "
+"project easier, but it will not open out-of-the-box and will still require "
+"manual adjustments.\n"
+"\n"
+"IMPORTANT: Make sure to backup your project before converting, as this "
+"operation makes it impossible to open it in older versions of Godot."
+msgstr ""
+"이것은 씬이나 리소스, 스크립트를 포함한 프로젝트 전체를 Godot 3.x에서 Godot "
+"4.0에 맞게 변환합니다.\n"
+"\n"
+"이것은 가장 힘이 덜 드는 선택지이지만, 그렇다고 해도 프로젝트가 아무 문제 없"
+"이 작동하지는 않을 것이며 여전히 여러 것들을 수동으로 조정해주어야 할 것입니"
+"다.\n"
+"\n"
+"중요: 반드시 변환하기 전에 프로젝트를 어딘가에 백업해 두세요. 변환을 수행하"
+"면 이전 버전의 Godot에서 프로젝트를 열지 못하게 됩니다."
+
msgid "Can't run project"
msgstr "프로젝트를 실행할 수 없습니다"
@@ -8505,26 +12095,68 @@ msgid ""
"Would you like to explore official example projects in the Asset Library?"
msgstr ""
"현재 프로젝트가 하나도 없습니다.\n"
-"애셋 라이브러리에서 공식 예제 프로젝트를 찾아볼까요?"
+"애셋 라이브러리에서 공식 예제 프로젝트를 찾아보는 게 어떤가요?"
+
+msgid "Manage Project Tags"
+msgstr "프로젝트 태그 설정"
+
+msgid "Project Tags"
+msgstr "프로젝트 태그"
+
+msgid "Click tag to remove it from the project."
+msgstr "태그를 클릭하면 프로젝트에서 제거합니다."
+
+msgid "All Tags"
+msgstr "모든 태그"
+
+msgid "Click tag to add it to the project."
+msgstr "태그를 클릭하면 프로젝트에 추가합니다."
+
+msgid "Create New Tag"
+msgstr "새 태그 만들기"
+
+msgid "Tags are capitalized automatically when displayed."
+msgstr "태그 대소문자는 보여질 때 자동으로 붙여집니다."
+
+msgid "Add Project Setting"
+msgstr "프로젝트 설정 추가"
msgid "Delete Item"
msgstr "항목 삭제"
+msgid "(All)"
+msgstr "(모두)"
+
msgid "Add Input Action"
msgstr "입력 액션 추가"
msgid "Change Action deadzone"
msgstr "액션 데드존 바꾸기"
+msgid "Change Input Action Event(s)"
+msgstr "입력 액션 이벤트 바꾸기"
+
msgid "Erase Input Action"
msgstr "입력 액션 지우기"
+msgid "Rename Input Action"
+msgstr "입력 액션 이름 바꾸기"
+
+msgid "Update Input Action Order"
+msgstr "입력 액션 순서 변경"
+
msgid "Project Settings (project.godot)"
msgstr "프로젝트 설정 (project.godot)"
+msgid "Advanced Settings"
+msgstr "고급 설정"
+
msgid "Select a Setting or Type its Name"
msgstr "설정을 선택하거나 그 이름을 입력해주세요"
+msgid "Changed settings will be applied to the editor after restarting."
+msgstr "변경 사항은 재시작 후에 에디터에 적용됩니다."
+
msgid "Input Map"
msgstr "입력 맵"
@@ -8534,6 +12166,9 @@ msgstr "현지화"
msgid "Autoload"
msgstr "자동 로드"
+msgid "Shader Globals"
+msgstr "셰이더 글로벌"
+
msgid "Plugins"
msgstr "플러그인(Plugin)"
@@ -8564,6 +12199,21 @@ msgstr "고급 옵션"
msgid "Substitute"
msgstr "대체"
+msgid "Node name."
+msgstr "노드 이름입니다."
+
+msgid "Node's parent name, if available."
+msgstr "사용 가능한 경우, 노드의 부모 이름입니다."
+
+msgid "Node type."
+msgstr "노드의 타입입니다."
+
+msgid "Current scene name."
+msgstr "현재 씬의 이름입니다."
+
+msgid "Root node name."
+msgstr "루트 노드의 이름입니다."
+
msgid ""
"Sequential integer counter.\n"
"Compare counter options."
@@ -8577,9 +12227,15 @@ msgstr "단계별 카운터"
msgid "If set, the counter restarts for each group of child nodes."
msgstr "설정하면 각 그룹의 자식 노드의 카운터를 다시 시작합니다."
+msgid "Initial value for the counter."
+msgstr "카운터의 초기 값입니다."
+
msgid "Step"
msgstr "단계"
+msgid "Amount by which counter is incremented for each node."
+msgstr "각 노드에 대해 카운터가 증가하는 양입니다."
+
msgid "Padding"
msgstr "패딩"
@@ -8623,12 +12279,42 @@ msgstr "(문자 %s 위치)"
msgid "Reparent Node"
msgstr "부모 노드 다시 지정"
+msgid "Select new parent:"
+msgstr "새 부모를 선택하세요:"
+
msgid "Keep Global Transform"
msgstr "전역 변형 유지"
msgid "Reparent"
msgstr "부모 다시 지정"
+msgid "Pick Root Node Type"
+msgstr "루트 노드 타입 선택"
+
+msgid "Pick"
+msgstr "선택"
+
+msgid "Scene name is valid."
+msgstr "씬 이름이 올바릅니다."
+
+msgid "Scene name is empty."
+msgstr "씬 이름이 비었습니다."
+
+msgid "File name invalid."
+msgstr "파일 이름이 잘못되었습니다."
+
+msgid "File already exists."
+msgstr "파일이 이미 존재합니다."
+
+msgid "Root node valid."
+msgstr "루트 노드가 올바릅니다."
+
+msgid "Invalid root node name."
+msgstr "잘못된 루트 노드 이름입니다."
+
+msgid "Root Type:"
+msgstr "루트 유형:"
+
msgid "2D Scene"
msgstr "2D 씬"
@@ -8638,12 +12324,42 @@ msgstr "3D 씬"
msgid "User Interface"
msgstr "유저 인터페이스"
+msgid "Scene Name:"
+msgstr "씬 이름:"
+
+msgid "Root Name:"
+msgstr "루트 이름:"
+
+msgid "Leave empty to use scene name"
+msgstr "공란일 경우 씬 이름을 사용합니다"
+
+msgid "Create New Scene"
+msgstr "씬 만들기"
+
+msgid "No parent to instantiate a child at."
+msgstr "자식을 인스턴스화할 부모가 없습니다."
+
+msgid "No parent to instantiate the scenes at."
+msgstr "씬을 인스턴스할 수 있는 부모가 없습니다."
+
msgid "Error loading scene from %s"
msgstr "%s에서 씬 불러오는 중 오류"
+msgid ""
+"Cannot instantiate the scene '%s' because the current scene exists within "
+"one of its nodes."
+msgstr ""
+"노드들 중 하나에 현재 씬이 있기 때문에, '%s' 씬을 인스턴스할 수 없습니다."
+
+msgid "Instantiate Scene(s)"
+msgstr "씬 인스턴스화"
+
msgid "Replace with Branch Scene"
msgstr "가지 씬으로 교체"
+msgid "Instantiate Child Scene"
+msgstr "자식 씬 인스턴스화"
+
msgid "Detach Script"
msgstr "스크립트 떼기"
@@ -8688,6 +12404,9 @@ msgstr "노드 \"%s\"와(과) 자식을 삭제할까요?"
msgid "Delete node \"%s\"?"
msgstr "노드 \"%s\"을(를) 삭제할까요?"
+msgid "Some nodes are referenced by animation tracks."
+msgstr "노드 몇 개가 애니메이션 트랙에서 참조되고 있습니다."
+
msgid ""
"Saving the branch as a scene requires having a scene open in the editor."
msgstr "가지를 씬으로 저장하려면 에디터에서 씬을 열어야 합니다."
@@ -8700,6 +12419,26 @@ msgstr ""
"있습니다."
msgid ""
+"Can't save the root node branch as an instantiated scene.\n"
+"To create an editable copy of the current scene, duplicate it using the "
+"FileSystem dock context menu\n"
+"or create an inherited scene using Scene > New Inherited Scene... instead."
+msgstr ""
+"루트 노드 가지를 인스턴스된 씬으로 저장할 수 없습니다.\n"
+"현재 씬의 편집 가능한 복사본을 만드려면, 파일시스템 독 컨텍스트 메뉴를 사용하"
+"여 복제하거나\n"
+"상속 씬을 씬 > 새 상속 씬...을 대신 사용하여 만드세요."
+
+msgid ""
+"Can't save the branch of an already instantiated scene.\n"
+"To create a variation of a scene, you can make an inherited scene based on "
+"the instantiated scene using Scene > New Inherited Scene... instead."
+msgstr ""
+"이미 인스턴스된 씬의 가지를 저장할 수 없습니다.\n"
+"씬의 바리에이션을 만드려면, 인스턴스된 씬을 바탕으로 상속 씬을 씬 > 새 상속 "
+"씬...을 대신 사용하여 만들 수 있습니다."
+
+msgid ""
"Can't save a branch which is a child of an already instantiated scene.\n"
"To save this branch into its own scene, open the original scene, right click "
"on this branch, and select \"Save Branch as Scene\"."
@@ -8751,18 +12490,30 @@ msgstr "새 씬 루트"
msgid "Create Root Node:"
msgstr "루트 노드 만들기:"
+msgid "Switch to Favorite Nodes"
+msgstr "즐겨찾기 노드로 전환"
+
msgid "Other Node"
msgstr "다른 노드"
+msgid "Paste From Clipboard"
+msgstr "클립보드에서 붙여넣기"
+
msgid "Can't operate on nodes from a foreign scene!"
msgstr "다른 씬에서 수행할 수 없는 작업입니다!"
msgid "Can't operate on nodes the current scene inherits from!"
msgstr "상속 씬 내에서 수행할 수 없는 작업입니다!"
+msgid "This operation can't be done on instantiated scenes."
+msgstr "이 작업은 인스턴스된 씬에서 할 수 없습니다."
+
msgid "Attach Script"
msgstr "스크립트 붙이기"
+msgid "Set Shader"
+msgstr "셰이더 설정"
+
msgid "Cut Node(s)"
msgstr "노드 잘라내기"
@@ -8787,9 +12538,18 @@ msgstr "씬 저장 중 오류."
msgid "Error duplicating scene to save it."
msgstr "저장하기 위해 씬 복제 중 오류."
+msgid "Instantiate Script"
+msgstr "스크립트 인스턴스화"
+
msgid "Sub-Resources"
msgstr "하위 리소스"
+msgid "Revoke Unique Name"
+msgstr "고유 이름 제거"
+
+msgid "Access as Unique Name"
+msgstr "고유 이름으로 액세스"
+
msgid "Clear Inheritance"
msgstr "상속 지우기"
@@ -8799,9 +12559,31 @@ msgstr "편집할 수 있는 자식"
msgid "Load As Placeholder"
msgstr "자리 표시자로 불러오기"
+msgid "Auto Expand to Selected"
+msgstr "선택으로 자동 확장"
+
+msgid "All Scene Sub-Resources"
+msgstr "모든 씬 하위 리소스"
+
msgid "Filters"
msgstr "필터"
+msgid "Filter by Type"
+msgstr "타입으로 필터"
+
+msgid "Filter by Group"
+msgstr "그룹으로 필터"
+
+msgid "Selects all Nodes of the given type."
+msgstr "주어진 타입의 노드를 모두 선택합니다."
+
+msgid ""
+"Selects all Nodes belonging to the given group.\n"
+"If empty, selects any Node belonging to any group."
+msgstr ""
+"주어진 그룹에 속하는 모든 노드를 선택합니다.\n"
+"비어 있다면, 아무 그룹에 속하는 아무 노드를 선택합니다."
+
msgid ""
"Cannot attach a script: there are no languages registered.\n"
"This is probably because this editor was built with all language modules "
@@ -8816,9 +12598,18 @@ msgstr "루트 노드를 같은 씬 안으로 붙여넣을 수 없습니다."
msgid "Paste Node(s)"
msgstr "노드 붙여넣기"
+msgid "<Unnamed> at %s"
+msgstr "%s의 <이름 없음>"
+
+msgid "(used %d times)"
+msgstr "(%d회 사용됨)"
+
msgid "Add Child Node"
msgstr "자식 노드 추가"
+msgid "Expand/Collapse Branch"
+msgstr "하위 항목 펼치기/접기"
+
msgid "Change Type"
msgstr "타입 바꾸기"
@@ -8828,18 +12619,30 @@ msgstr "새 노드에 부모 노드 다시 지정"
msgid "Make Scene Root"
msgstr "씬 루트 만들기"
+msgid "Toggle Access as Unique Name"
+msgstr "고유 이름으로 액세스 토글"
+
msgid "Delete (No Confirm)"
msgstr "삭제 (확인 없음)"
msgid "Add/Create a New Node."
msgstr "새 노드를 추가하거나 만듭니다."
+msgid ""
+"Instantiate a scene file as a Node. Creates an inherited scene if no root "
+"node exists."
+msgstr ""
+"씬 파일을 노드로 인스턴스화합니다. 루트 노드가 없으면 상속된 씬을 만듭니다."
+
msgid "Attach a new or existing script to the selected node."
msgstr "선택한 노드에 새 스크립트나 기존 스크립트를 붙입니다."
msgid "Detach the script from the selected node."
msgstr "선택한 노드에서 스크립트를 뗍니다."
+msgid "Extra scene options."
+msgstr "별도의 씬 옵션입니다."
+
msgid "Remote"
msgstr "원격"
@@ -8852,6 +12655,9 @@ msgstr ""
"는 원인이 됩니다.\n"
"성능을 향상시키려면 로컬 씬 트리 독으로 다시 전환하세요."
+msgid "Delete Related Animation Tracks"
+msgstr "관련 애니메이션 트랙 삭제"
+
msgid "Clear Inheritance? (No Undo!)"
msgstr "상속을 지울까요? (되돌릴 수 없습니다!)"
@@ -8861,9 +12667,15 @@ msgstr "경로가 비었습니다."
msgid "Filename is empty."
msgstr "파일 이름이 비었습니다."
+msgid "Filename is invalid."
+msgstr "파일 이름이 잘못되었습니다."
+
msgid "Path is not local."
msgstr "경로가 로컬이 아닙니다."
+msgid "Base path is invalid."
+msgstr "베이스 경로가 잘못되었습니다."
+
msgid "A directory with the same name exists."
msgstr "같은 이름의 디렉토리가 있습니다."
@@ -8873,6 +12685,9 @@ msgstr "파일이 존재하지 않습니다."
msgid "Invalid extension."
msgstr "잘못된 확장자."
+msgid "Extension doesn't match chosen language."
+msgstr "확장명이 선택된 언어와 맞지 않습니다."
+
msgid "Template:"
msgstr "템플릿:"
@@ -8888,6 +12703,12 @@ msgstr "스크립트 열기 / 위치 선택"
msgid "Open Script"
msgstr "스크립트 열기"
+msgid "Inherit %s"
+msgstr "%s 상속"
+
+msgid "Inherit"
+msgstr "상속"
+
msgid "File exists, it will be reused."
msgstr "파일이 있습니다. 재사용될 것입니다."
@@ -8915,12 +12736,21 @@ msgstr "내장 스크립트 (씬 파일 안)."
msgid "Will create a new script file."
msgstr "새 스크립트 파일을 만듭니다."
+msgid "Using existing script file."
+msgstr "기존 스크립트 파일을 사용합니다."
+
msgid "Will load an existing script file."
msgstr "기존 스크립트 파일을 불러옵니다."
msgid "Script file already exists."
msgstr "스크립트 파일이 이미 있습니다."
+msgid "No suitable template."
+msgstr "적당한 템플릿이 없습니다."
+
+msgid "Empty"
+msgstr "비어 있음"
+
msgid ""
"Note: Built-in scripts have some limitations and can't be edited using an "
"external editor."
@@ -8944,15 +12774,79 @@ msgstr "내장 스크립트:"
msgid "Attach Node Script"
msgstr "노드 스크립트 붙이기"
+msgid "Error - Could not create shader include in filesystem."
+msgstr "오류 - 파일시스템에 셰이더 인클루드를 만들 수 없습니다."
+
+msgid "Error - Could not create shader in filesystem."
+msgstr "오류 - 파일시스템에 셰이더를 만들 수 없습니다."
+
+msgid "Error loading shader from %s"
+msgstr "%s에서 셰이더 불러오는 중 오류"
+
+msgid "Open Shader / Choose Location"
+msgstr "셰이더 열기 / 위치 선택"
+
msgid "Invalid base path."
msgstr "잘못된 기본 경로."
msgid "Wrong extension chosen."
msgstr "잘못된 확장자 선택."
+msgid "Shader path/name is valid."
+msgstr "셰이더의 경로/이름이 올바릅니다."
+
+msgid "Built-in shader (into scene file)."
+msgstr "내장 셰이더 (씬 파일 안)."
+
+msgid "Will create a new shader file."
+msgstr "새 셰이더 파일을 만듭니다."
+
+msgid "Will load an existing shader file."
+msgstr "기존 셰이더 파일을 불러옵니다."
+
+msgid "Shader file already exists."
+msgstr "셰이더 파일이 이미 있습니다."
+
+msgid "Note: Built-in shaders can't be edited using an external editor."
+msgstr "참고: 내장 셰이더는 외부 에디터를 사용하여 편집할 수 없습니다."
+
+msgid "Mode:"
+msgstr "모드:"
+
+msgid "Built-in Shader:"
+msgstr "내장 셰이더:"
+
+msgid "Create Shader"
+msgstr "셰이더 만들기"
+
+msgid "Set Shader Global Variable"
+msgstr "셰이더 전역 변수 설정"
+
+msgid "Please specify a valid shader uniform identifier name."
+msgstr "올바른 셰이더 유니폼 식별자 이름을 지정해 주세요."
+
msgid "Global shader parameter '%s' already exists'"
msgstr "글로벌 셰이더 매개변수 '%s'이(가) 이미 있습니다"
+msgid "Name '%s' is a reserved shader language keyword."
+msgstr "'%s'는 셰이더 언어의 예약된 키워드입니다."
+
+msgid "Add Shader Global Parameter"
+msgstr "셰이더 전역 파라미터 추가"
+
+msgid "Make this panel floating in the screen %d."
+msgstr "이 패널을 화면 %d 위에 창으로 띄웁니다."
+
+msgid ""
+"Make this panel floating.\n"
+"Right click to open the screen selector."
+msgstr ""
+"이 패널을 창으로 띄웁니다.\n"
+"우클릭으로 화면 선택기를 엽니다."
+
+msgid "Select Screen"
+msgstr "화면 선택"
+
msgid "Change Cylinder Radius"
msgstr "원기둥 반지름 바꾸기"
@@ -8993,6 +12887,84 @@ msgstr "잘못된 인스턴스 딕셔너리 형식 (잘못된 @path의 스크립
msgid "Invalid instance dictionary (invalid subclasses)"
msgstr "잘못된 인스턴스 딕셔너리 (잘못된 하위 클래스)"
+msgid "Value of type '%s' can't provide a length."
+msgstr "'%s' 타입의 값은 길이를 제공하지 못합니다."
+
+msgid ""
+"Invalid type argument for is_instance_of(), use TYPE_* constants for built-"
+"in types."
+msgstr ""
+"is_instance_of() 메서드의 인수 타입이 올바르지 않습니다. 내장 타입에 대해서"
+"는 TYPE_* 상수를 사용하세요."
+
+msgid "Type argument is a previously freed instance."
+msgstr "타입 매개 변수가 이전에 할당 해제한 인스턴스입니다."
+
+msgid ""
+"Invalid type argument for is_instance_of(), should be a TYPE_* constant, a "
+"class or a script."
+msgstr ""
+"is_instance_of() 메서드의 인수 타입이 올바르지 않습니다. TYPE_* 상수, 클래"
+"스, 스크립트 중 하나여야 합니다."
+
+msgid "Value argument is a previously freed instance."
+msgstr "값 매개 변수가 이전에 할당 해제한 인스턴스입니다."
+
+msgid "Export Scene to glTF 2.0 File"
+msgstr "씬을 glTF 2.0 파일으로 내보내기"
+
+msgid "glTF 2.0 Scene..."
+msgstr "glTF 2.0 씬..."
+
+msgid "Path does not contain a Blender installation."
+msgstr "경로에서 Blender 파일을 찾을 수 없습니다."
+
+msgid "Can't execute Blender binary."
+msgstr "Blender 파일을 실행할 수 없습니다."
+
+msgid "Unexpected --version output from Blender binary at: %s"
+msgstr "Blender 실행 파일의 --version에서 예측하지 못한 값을 얻음: %s"
+
+msgid "Path supplied lacks a Blender binary."
+msgstr "제공된 경로에 Blender 실행 파일이 없습니다."
+
+msgid "This Blender installation is too old for this importer (not 3.0+)."
+msgstr ""
+"이 임포터에 사용하기에는 Blender의 버전이 너무 오래되었습니다 (3.0 미만)."
+
+msgid "This Blender installation is too new for this importer (not 3.x)."
+msgstr ""
+"이 임포터에 사용하기에는 Blender의 버전이 너무 최신입니다 (3.x가 아님)."
+
+msgid "Path to Blender installation is valid (Autodetected)."
+msgstr "Blender 실행 파일의 경로가 올바릅니다 (자동 감지됨)."
+
+msgid "Path to Blender installation is valid."
+msgstr "Blender 실행 파일의 경로가 올바릅니다."
+
+msgid "Configure Blender Importer"
+msgstr "Blender 임포터 설정"
+
+msgid ""
+"Blender 3.0+ is required to import '.blend' files.\n"
+"Please provide a valid path to a Blender installation:"
+msgstr ""
+"'.blend' 파일을 가져오기 위해서는 3.0버전 이상의 Blender가 필요합니다.\n"
+"Blender 실행 파일이 있는 경로를 제공해 주세요:"
+
+msgid "Disable '.blend' Import"
+msgstr "'.blend' 가져오기 비활성화"
+
+msgid ""
+"Disables Blender '.blend' files import for this project. Can be re-enabled "
+"in Project Settings."
+msgstr ""
+"이 프로젝트에서 Bleder '.blend' 파일 가져오기를 비활성화합니다. 프로젝트 설정"
+"에서 다시 활성화할 수 있습니다."
+
+msgid "Disabling '.blend' file import requires restarting the editor."
+msgstr "'.blend' 파일 가져오기를 비활성화하려면 에디터를 다시 시작해야 합니다."
+
msgid "Next Plane"
msgstr "다음 평면"
@@ -9077,14 +13049,59 @@ msgstr "그리드맵 설정"
msgid "Pick Distance:"
msgstr "거리 선택:"
+msgid "Filter Meshes"
+msgstr "메시 필터"
+
msgid "Give a MeshLibrary resource to this GridMap to use its meshes."
msgstr "메시를 사용하려면 이 GridMap에 MeshLibrary 리소스를 주세요."
+msgid "Determining optimal atlas size"
+msgstr "최적의 아틀라스 크기 찾는 중"
+
+msgid "Blitting albedo and emission"
+msgstr "알베도와 에미션을 블리팅하는 중"
+
+msgid "Plotting mesh into acceleration structure %d/%d"
+msgstr "메시를 가속 구조에 그리는 중 %d/%d"
+
+msgid "Optimizing acceleration structure"
+msgstr "가속 구조를 최적화하는 중"
+
msgid "Begin Bake"
msgstr "굽기 시작"
+msgid "Preparing shaders"
+msgstr "셰이더 준비 중"
+
+msgid "Un-occluding geometry"
+msgstr "지오메트리 오클루전 해제 중"
+
+msgid "Plot direct lighting"
+msgstr "직접 조명 그리기"
+
+msgid "Integrate indirect lighting"
+msgstr "간접 조명 통합"
+
+msgid "Bounce %d/%d: Integrate indirect lighting %d%%"
+msgstr "바운스 %d/%d: 간접 조명 통합 %d%%"
+
+msgid "Baking lightprobes"
+msgstr "라이트 프로브 굽는 중"
+
+msgid "Integrating light probes %d%%"
+msgstr "라이트 프로브 통합 중 %d%%"
+
+msgid "Denoising"
+msgstr "노이즈 제거 중"
+
+msgid "Retrieving textures"
+msgstr "텍스쳐 받아오는 중"
+
msgid "Class name can't be a reserved keyword"
-msgstr "클래스 이름은 키워드가 될 수 없습니다"
+msgstr "클래스 이름은 키워드가 될 수 없음"
+
+msgid "Class name must be a valid identifier"
+msgstr "클래스 이름은 올바른 식별자여야 함"
msgid "Build Solution"
msgstr "솔루션 빌드"
@@ -9092,15 +13109,59 @@ msgstr "솔루션 빌드"
msgid "Not enough bytes for decoding bytes, or invalid format."
msgstr "디코딩할 바이트가 모자라거나 잘못된 형식입니다."
+msgid ""
+"Unable to load .NET runtime, no compatible version was found.\n"
+"Attempting to create/edit a project will lead to a crash.\n"
+"\n"
+"Please install the .NET SDK 6.0 or later from https://dotnet.microsoft.com/"
+"en-us/download and restart Godot."
+msgstr ""
+".NET 런타임을 불러오지 못했습니다. 호환되는 버전을 찾지 못했습니다.\n"
+"프로젝트를 생성하거나 편집하려는 시도는 크래시로 이어질 것입니다.\n"
+"\n"
+".NET SDK 6.0 또는 이후 버전을 https://dotnet.microsoft.com/en-us/download 에"
+"서 받은 뒤 Godot을 재시작해 주세요."
+
+msgid "Failed to load .NET runtime"
+msgstr ".NET 런타임을 불러오지 못함"
+
+msgid ""
+"Unable to load .NET runtime, specifically hostfxr.\n"
+"Attempting to create/edit a project will lead to a crash.\n"
+"\n"
+"Please install the .NET SDK 6.0 or later from https://dotnet.microsoft.com/"
+"en-us/download and restart Godot."
+msgstr ""
+".NET 런타임을 불러오지 못했습니다. 특히, 그 중에서 hostfxr을 불러오지 못했습"
+"니다.\n"
+"프로젝트를 생성하거나 편집하려는 시도는 크래시로 이어질 것입니다.\n"
+"\n"
+".NET SDK 6.0 또는 이후 버전을 https://dotnet.microsoft.com/en-us/download 에"
+"서 받은 뒤 Godot을 재시작해 주세요."
+
+msgid "%d (%s)"
+msgstr "%d (%s)"
+
msgid "%s/s"
msgstr "%s/s"
+msgctxt "Network"
+msgid "Down"
+msgstr "다운"
+
+msgctxt "Network"
+msgid "Up"
+msgstr "업"
+
msgid "Incoming RPC"
msgstr "수신 RPC"
msgid "Outgoing RPC"
msgstr "발신 RPC"
+msgid "Synchronizer"
+msgstr "동기화"
+
msgid "Config"
msgstr "구성"
@@ -9110,6 +13171,39 @@ msgstr "양"
msgid "Network Profiler"
msgstr "네트워크 프로파일러"
+msgid "Replication"
+msgstr "리플리케이션"
+
+msgid "Select a replicator node in order to pick a property to add to it."
+msgstr "리플리케이터 노드를 선택하고 추가할 속성을 고르세요."
+
+msgid "Not possible to add a new property to synchronize without a root."
+msgstr "루트 없이는 동기화할 속성을 추가할 수 없습니다."
+
+msgid "Property is already being synchronized."
+msgstr "속성이 이미 동기화되어 있습니다."
+
+msgid "Add property to synchronizer"
+msgstr "싱크로나이저에 속성 추가"
+
+msgid "Pick a node to synchronize:"
+msgstr "동기화할 노드를 고르세요:"
+
+msgid "Add property to sync..."
+msgstr "동기화할 속성 추가..."
+
+msgid "Add from path"
+msgstr "경로에서 추가"
+
+msgid "Spawn"
+msgstr "소환"
+
+msgid "Watch"
+msgstr "감시"
+
+msgid "Delete Property?"
+msgstr "속성을 삭제할까요?"
+
msgid "A NavigationMesh resource must be set or created for this node to work."
msgstr ""
"이 노드가 작동하려면 NavigationMesh 리소스를 설정하거나 만들어야 합니다."
@@ -9120,9 +13214,27 @@ msgstr "NavMesh 굽기"
msgid "Clear the navigation mesh."
msgstr "내비게이션 메시를 지웁니다."
+msgid "Error saving file %s: %s"
+msgstr "파일 %s 저장 중 오류: %s"
+
+msgid "Error loading %s: %s."
+msgstr "%s 불러오는 중 오류: %s"
+
+msgid "Add an action set."
+msgstr "액션 세트를 추가합니다."
+
msgid "Pose"
msgstr "자세"
+msgid "Haptic"
+msgstr "햅틱"
+
+msgid "Unknown"
+msgstr "알 수 없음"
+
+msgid "Select an action"
+msgstr "액션을 선택하세요"
+
msgid "Package name is missing."
msgstr "패키지 이름이 누락되어 있습니다."
@@ -9219,6 +13331,9 @@ msgstr "'build-tools' 디렉토리가 누락되어 있습니다!"
msgid "Unable to find Android SDK build-tools' apksigner command."
msgstr "Android SDK build-tools의 apksigner 명령을 찾을 수 없습니다."
+msgid "Code Signing"
+msgstr "코드 서명"
+
msgid ""
"'apksigner' could not be found. Please check that the command is available "
"in the Android SDK build-tools directory. The resulting %s is unsigned."
@@ -9241,6 +13356,13 @@ msgstr "apksigner 실행 파일을 시작할 수 없습니다."
msgid "'apksigner' returned with error #%d"
msgstr "'apksigner'가 오류 #%d로 반환되었습니다"
+msgid ""
+"output: \n"
+"%s"
+msgstr ""
+"출력:\n"
+"%s"
+
msgid "Verifying %s..."
msgstr "%s 검증 중..."
@@ -9309,6 +13431,15 @@ msgstr "APK를 만드는 중..."
msgid "Could not find template APK to export: \"%s\"."
msgstr "내보낼 템플릿 APK를 찾을 수 없음: \"%s\"."
+msgid ""
+"Missing libraries in the export template for the selected architectures: %s. "
+"Please build a template with all required libraries, or uncheck the missing "
+"architectures in the export preset."
+msgstr ""
+"선택된 아키텍처를 위한 내보내기 템플릿에 라이브러리가 누락되어 있습니다: %s. "
+"모든 필수 라이브러리를 가지고 템플릿을 빌드하거나, 내보내기 프리셋에서 누락"
+"된 아키텍처를 선택 취소하세요."
+
msgid "Adding files..."
msgstr "파일을 추가하는 중..."
@@ -9324,15 +13455,78 @@ msgstr "임시 정렬되지 않은 APK의 압축을 풀 수 없었습니다."
msgid "Invalid Identifier:"
msgstr "잘못된 식별자:"
+msgid "Xcode Build"
+msgstr "Xcode 빌드"
+
msgid "Identifier is missing."
msgstr "식별자가 누락되어 있습니다."
msgid "The character '%s' is not allowed in Identifier."
msgstr "문자 '%s'은(는) 식별자에 쓸 수 없습니다."
+msgid "Debug Script Export"
+msgstr "디버그 스크립트 내보내기"
+
+msgid "Could not open file \"%s\"."
+msgstr "파일 \"%s\"를 열 수 없습니다."
+
+msgid "Debug Console Export"
+msgstr "디버그 콘솔 내보내기"
+
+msgid "Could not create console wrapper."
+msgstr "콘솔 래퍼(console wrapper)를 만들 수 없습니다."
+
+msgid "Failed to open executable file \"%s\"."
+msgstr "파일 \"%s\"를 실행할 수 없습니다."
+
+msgid "Executable file header corrupted."
+msgstr "실행 파일 헤더가 손상되었습니다."
+
+msgid "32-bit executables cannot have embedded data >= 4 GiB."
+msgstr "32비트 실행 파일은 4GiB 이상의 데이터를 포함하지 못합니다."
+
+msgid "Executable \"pck\" section not found."
+msgstr "실행 파일의 \"pck\" 섹션을 찾을 수 없습니다."
+
msgid "Stop and uninstall"
msgstr "멈춤 및 설치 제거"
+msgid "Run on remote Linux/BSD system"
+msgstr "원격 Linux/BSD 시스템에서 실행"
+
+msgid "Stop and uninstall running project from the remote system"
+msgstr "원격 시스템에서 실행 중인 프로젝트를 정지하고 설치 제거"
+
+msgid "Run exported project on remote Linux/BSD system"
+msgstr "내보낸 프로젝트를 원격 Linux/BSD 시스템에서 실행"
+
+msgid "Running..."
+msgstr "실행 중..."
+
+msgid "Could not create temp directory:"
+msgstr "임시 디렉터리를 만들 수 없음:"
+
+msgid "Exporting project..."
+msgstr "프로젝트 내보내는 중..."
+
+msgid "Creating temporary directory..."
+msgstr "임시 디렉터리 만드는 중..."
+
+msgid "Uploading archive..."
+msgstr "압축 파일 업로드하는 중..."
+
+msgid "Uploading scripts..."
+msgstr "스크립트 업로드하는 중..."
+
+msgid "Starting project..."
+msgstr "프로젝트 시작 중..."
+
+msgid "Can't get filesystem access."
+msgstr "파일시스템 접근 권한을 얻지 못했습니다."
+
+msgid "Failed to create \"%s\" subfolder."
+msgstr "서브폴더 \"%s\"을(를) 만들 수 없습니다."
+
msgid "Invalid bundle identifier:"
msgstr "잘못된 bundle 식별자:"
@@ -9348,6 +13542,15 @@ msgstr "파일 %s를 서명할 수 없습니다."
msgid "Could not start hdiutil executable."
msgstr "hdiutil 실행 파일을 시작할 수 없었습니다."
+msgid "Could not find template app to export: \"%s\"."
+msgstr "내보낼 템플릿 앱을 찾을 수 없음: \"%s\"."
+
+msgid "Invalid export format."
+msgstr "잘못된 내보내기 템플릿입니다."
+
+msgid "Could not created symlink \"%s\" -> \"%s\"."
+msgstr "바로가기 파일 \"%s\" -> \"%s\"를 만들 수 없습니다."
+
msgid "Invalid package short name."
msgstr "잘못된 패키지 단축 이름."
@@ -9399,6 +13602,16 @@ msgstr "파일에 쓸 수 없음: \"%s\"."
msgid "Could not read file: \"%s\"."
msgstr "파일을 읽을 수 없음: \"%s\"."
+msgid "PWA"
+msgstr "PWA"
+
+msgid ""
+"Exporting to Web is currently not supported in Godot 4 when using C#/.NET. "
+"Use Godot 3 to target Web with C#/Mono instead."
+msgstr ""
+"C#/.NET을 사용하는 Godot 4에서는 아직 웹으로 내보내기를 지원하지 않습니다. 필"
+"요하다면 대신 C#/Mono를 사용하는 Godot 3을 사용하세요."
+
msgid "Could not read HTML shell: \"%s\"."
msgstr "HTML shell을 읽을 수 없음: \"%s\"."
@@ -9420,16 +13633,112 @@ msgstr "내보낸 HTML을 시스템의 기본 브라우저를 사용하여 실
msgid "Resources Modification"
msgstr "리소스 변경"
+msgid "Icon size \"%d\" is missing."
+msgstr "아이콘 크기 \"%d\"가 없습니다."
+
msgid "Failed to rename temporary file \"%s\"."
msgstr "임시 파일 \"%s\"의 이름을 바꾸지 못했습니다."
+msgid "Invalid icon path."
+msgstr "잘못된 아이콘 경로입니다."
+
+msgid "Invalid file version."
+msgstr "잘못된 파일 버전입니다."
+
+msgid "Invalid product version."
+msgstr "잘못된 제품 버전입니다."
+
+msgid "Could not find rcedit executable at \"%s\"."
+msgstr "\"%s\"에서 rcedit 실행 파일을 찾지 못했습니다."
+
+msgid "Could not find wine executable at \"%s\"."
+msgstr "\"%s\"에서 wine 실행 파일을 찾지 못했습니다."
+
+msgid "Invalid icon file \"%s\"."
+msgstr "아이콘 파일 \"%s\"은 올바르지 않습니다."
+
+msgid ""
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
+msgstr ""
+"rcedit을 실행하지 못했습니다. 에디터 설정 (내보내기 > Windows > rcedit)에서 "
+"rcedit의 경로를 지정하거나, 내보내기 프리셋에서 \"어플리케이션 > 리소스 수정"
+"\"을 비활성화하세요."
+
+msgid "rcedit failed to modify executable: %s."
+msgstr "rcedit으로 실행 파일을 수정하지 못했습니다: %s."
+
+msgid "Could not find signtool executable at \"%s\"."
+msgstr "\"%s\"에서 signtool 실행 파일을 찾지 못했습니다."
+
+msgid "Could not find osslsigncode executable at \"%s\"."
+msgstr "\"%s\"에서 osslsigncode 실행 파일을 찾지 못했습니다."
+
+msgid "No identity found."
+msgstr "아이덴티티를 찾을 수 없습니다."
+
msgid "Invalid identity type."
-msgstr "잘못된 식별자 타입입니다."
+msgstr "잘못된 아이덴티티 타입입니다."
+
+msgid "Invalid timestamp server."
+msgstr "잘못된 타임스탬프 서버입니다."
+
+msgid ""
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > signtool), or disable \"Codesign\" in the "
+"export preset."
+msgstr ""
+"signtool을 실행하지 못했습니다. 에디터 설정 (내보내기 > Windows > signtool)에"
+"서 signtool의 경로를 지정하거나, 내보내기 프리셋에서 \"코드 서명\"을 비활성화"
+"하세요."
+
+msgid ""
+"Could not start osslsigncode executable. Configure signtool path in the "
+"Editor Settings (Export > Windows > osslsigncode), or disable \"Codesign\" "
+"in the export preset."
+msgstr ""
+"osslsigncode을 실행하지 못했습니다. 에디터 설정 (내보내기 > Windows > "
+"osslsigncode)에서 osslsigncode의 경로를 지정하거나, 내보내기 프리셋에서 \"코"
+"드 서명\"을 비활성화하세요."
+
+msgid "Signtool failed to sign executable: %s."
+msgstr "signtool으로 실행 파일을 서명하지 못했습니다: %s."
msgid "Failed to remove temporary file \"%s\"."
msgstr "임시 파일 \"%s\"를 제거하지 못했습니다."
msgid ""
+"The rcedit tool must be configured in the Editor Settings (Export > Windows "
+"> rcedit) to change the icon or app information data."
+msgstr ""
+"앱 아이콘이나 정보를 바꾸기 위해선 에디터 설정 (내보내기 > Windows > rcedit)"
+"에서 rcedit 도구를 설정해야 합니다."
+
+msgid "Windows executables cannot be >= 4 GiB."
+msgstr "Windows 실행 파일은 4GiB보다 클 수 없습니다."
+
+msgid "Run on remote Windows system"
+msgstr "원격 Windows 시스템에서 실행"
+
+msgid "Run exported project on remote Windows system"
+msgstr "내보낸 프로젝트를 원격 Windows 시스템에서 실행"
+
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite2D to display frames."
+msgstr ""
+"AnimatedSprite2D가 프레임을 보여주기 위해서는 \"Frames\" 속성에서 "
+"SpriteFrames 리소스를 만들거나 설정해야 합니다."
+
+msgid ""
+"Only one visible CanvasModulate is allowed per scene (or set of instantiated "
+"scenes). The first created one will work, while the rest will be ignored."
+msgstr ""
+"CanvasModulate는 씬 (또는 인스턴트된 씬들) 당 단 하나만 보일 수 있습니다. 처"
+"음에 만든 것만 작동하고, 나머지는 무시됩니다."
+
+msgid ""
"This node has no shape, so it can't collide or interact with other objects.\n"
"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
"define its shape."
@@ -9438,6 +13747,15 @@ msgstr ""
"CollisionShape2D 또는 CollisionPolygon2D를 자식 노드로 추가하여 모양을 정의하"
"는 것을 고려하세요."
+msgid ""
+"CollisionPolygon2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."
+msgstr ""
+"CollisionPolygon2D는 CollisionObject2D 기반 노드에 콜리전 모양을 지정하는 용"
+"도로만 사용됩니다. 모양을 정의해야 하는 Area2D, StaticBody2D, RigidBody2D, "
+"CharacterBody2D 등의 자식으로만 사용해주세요."
+
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "빈 CollisionPolygon2D는 콜리전에 영향을 주지 않습니다."
@@ -9540,6 +13858,28 @@ msgstr ""
"이 본에 적절한 대기 자세가 없습니다. Skeleton2D 노드로 가서 대기 자세를 설정"
"하세요."
+msgid ""
+"CollisionPolygon3D only serves to provide a collision shape to a "
+"CollisionObject3D derived node.\n"
+"Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, "
+"CharacterBody3D, etc. to give them a shape."
+msgstr ""
+"CollisionPolygon3D는 CollisionObject3D 기반 노드에 콜리전 모양을 지정하는 용"
+"도로만 사용됩니다.\n"
+"모양을 정의해야 하는 Area3D, StaticBody3D, RigidBody23D, CharacterBody3D 등"
+"의 자식으로만 사용해주세요."
+
+msgid ""
+"CollisionShape3D only serves to provide a collision shape to a "
+"CollisionObject3D derived node.\n"
+"Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, "
+"CharacterBody3D, etc. to give them a shape."
+msgstr ""
+"CollisionShape3D는 CollisionObject3D 기반 노드에 콜리전 모양을 지정하는 용도"
+"로만 사용됩니다.\n"
+"모양을 정의해야 하는 Area3D, StaticBody3D, RigidBody3D, CharacterBody3D 등의 "
+"자식으로만 사용해주세요."
+
msgid "Nothing is visible because no mesh has been assigned."
msgstr "지정한 메시가 없어서 아무 것도 보이지 않습니다."
@@ -9547,6 +13887,12 @@ msgid ""
"Nothing is visible because meshes have not been assigned to draw passes."
msgstr "메시가 패스를 그리도록 지정하지 않아서, 아무 것도 보이지 않습니다."
+msgid "Creating probes"
+msgstr "프로브 생성"
+
+msgid "Generating Probe Volumes"
+msgstr "프로브 볼륨 생성 중"
+
msgid "This body will be ignored until you set a mesh."
msgstr "이 바디는 메시를 설정할 때까지 무시됩니다."
@@ -9569,6 +13915,9 @@ msgstr "BlendTree 노드 '%s'에서, 애니메이션을 찾을 수 없음: '%s'"
msgid "Animation not found: '%s'"
msgstr "애니메이션을 찾을 수 없음: '%s'"
+msgid "Animation Apply Reset"
+msgstr "애니메이션 적용 재설정"
+
msgid "In node '%s', invalid animation: '%s'."
msgstr "노드 '%s'에서, 잘못된 애니메이션: '%s'."
@@ -9592,8 +13941,51 @@ msgstr ""
msgid "The AnimationPlayer root node is not a valid node."
msgstr "AnimationPlayer 루트 노드가 올바른 노드가 아닙니다."
+msgid ""
+"ButtonGroup is intended to be used only with buttons that have toggle_mode "
+"set to true."
+msgstr ""
+"ButtonGroup은 오직 toggle_mode가 참인 버튼들만 함께 사용하도록 되어 있습니다."
+
+msgid "Copy this constructor in a script."
+msgstr "이 생성자를 스크립트 안으로 복사합니다."
+
+msgid "Enter a hex code (\"#ff0000\") or named color (\"red\")."
+msgstr "헥스 코드(\"#ff0000\") 또는 영어 색상 이름(\"red\")을 넣어 주세요."
+
+msgid ""
+"Color: #%s\n"
+"LMB: Apply color\n"
+"RMB: Remove preset"
+msgstr ""
+"색상: #%s\n"
+"좌클릭: 색상 지정\n"
+"우클릭: 프리셋 제거"
+
+msgid ""
+"Color: #%s\n"
+"LMB: Apply color"
+msgstr ""
+"색상: #%s\n"
+"좌클릭: 색상 지정"
+
+msgid "Pick a color from the screen."
+msgstr "화면에서 색상을 고르세요."
+
+msgid "Pick a color from the application window."
+msgstr "프로그램 창에서 색상을 고르세요."
+
+msgid "Select a picker shape."
+msgstr "피커 모양을 고르세요."
+
+msgid "Select a picker mode."
+msgstr "피커 모드를 고르세요."
+
msgid "Switch between hexadecimal and code values."
-msgstr "16진수나 코드 값으로 전환합니다."
+msgstr "헥스 코드와 코드 값의 사이를 전환합니다."
+
+msgid "Hex code or named color"
+msgstr "헥스 코드 또는 색상 이름"
msgid "Add current color as a preset."
msgstr "현재 색상을 프리셋으로 추가합니다."
@@ -9604,7 +13996,7 @@ msgid ""
"If you don't intend to add a script, use a plain Control node instead."
msgstr ""
"Container 자체는 자식 배치 작업을 구성하는 스크립트 외에는 목적이 없습니다.\n"
-"스크립트를 추가하는 의도가 없으면, 순수한 Control 노드를 사용해주세요."
+"스크립트를 추가할 목적이 아니면, 일반적인 Control 노드를 사용해주세요."
msgid ""
"The Hint Tooltip won't be displayed as the control's Mouse Filter is set to "
@@ -9614,15 +14006,76 @@ msgstr ""
"보이지 않습니다. 해결하려면 Mouse Filter를 \"Stop\"이나 \"Pass\"로 설정하세"
"요."
+msgid ""
+"Changing the Z index of a control only affects the drawing order, not the "
+"input event handling order."
+msgstr ""
+"컨트롤의 Z 인덱스를 변경하는 것은 보여지는 순서에만 영향을 미치고, 입력 이벤"
+"트를 처리하는 순서에는 영향을 미치지 않습니다."
+
msgid "Alert!"
msgstr "경고!"
msgid "Please Confirm..."
msgstr "확인해주세요..."
+msgid "You don't have permission to access contents of this folder."
+msgstr "이 폴더에 접근할 권한이 없습니다."
+
+msgid "All Files"
+msgstr "모든 파일"
+
+msgid "Invalid extension, or empty filename."
+msgstr "잘못된 확장자이거나 파일명이 비어 있습니다."
+
+msgid ""
+"Please be aware that GraphEdit and GraphNode will undergo extensive "
+"refactoring in a future 4.x version involving compatibility-breaking API "
+"changes."
+msgstr ""
+"GraphEdit과 GraphNode는 이후의 4.x 버전에서 하위 호환성 없는 API 변경을 포함"
+"한 큰 리팩터링을 거칠 것임을 유의해 주세요."
+
msgid "Enable grid minimap."
msgstr "그리드 미니맵을 활성화합니다."
+msgid "Arrange nodes."
+msgstr "노드를 적절히 배치합니다."
+
+msgid ""
+"The current font does not support rendering one or more characters used in "
+"this Label's text."
+msgstr ""
+"이 레이블에는 현재 글꼴이 렌더링하지 못하는 글자가 하나 이상 포함되어 있습니"
+"다."
+
+msgid "Same as Layout Direction"
+msgstr "레이아웃 방향과 같음"
+
+msgid "Auto-Detect Direction"
+msgstr "방향 자동 감지"
+
+msgid "Left-to-Right"
+msgstr "좌-우 방향으로"
+
+msgid "Right-to-Left"
+msgstr "우-좌 방향으로"
+
+msgid "Left-to-Right Mark (LRM)"
+msgstr "좌-우 방향 표식 (LRM)"
+
+msgid "Right-to-Left Mark (RLM)"
+msgstr "우-좌 방향 표식 (RLM)"
+
+msgid "Text Writing Direction"
+msgstr "텍스트 쓰기 방향"
+
+msgid "Display Control Characters"
+msgstr "제어 문자 표시"
+
+msgid "Insert Control Character"
+msgstr "제어 문자 삽입"
+
msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
msgstr "\"Exp Edit\"을 활성화하면, \"Min Value\"는 반드시 0보다 커야 합니다."
@@ -9635,10 +14088,46 @@ msgstr ""
"(VBox, HBox 등) 컨테이너를 자식으로 사용하거나, Control을 사용하고 사용자 지"
"정 최소 수치를 수동으로 설정하세요."
+msgid ""
+"This node doesn't have a SubViewport as child, so it can't display its "
+"intended content.\n"
+"Consider adding a SubViewport as a child to provide something displayable."
+msgstr ""
+"이 노드에는 SubViewport 자식이 없어서, 의도된 내용물을 표시하지 못합니다.\n"
+"무언가를 표시할 수 있게 SubViewport 자식을 추가하는 것을 고려해 보세요."
+
msgid "(Other)"
msgstr "(기타)"
msgid ""
+"Setting node name '%s' to be unique within scene for '%s', but it's already "
+"claimed by '%s'.\n"
+"'%s' is no longer set as having a unique name."
+msgstr ""
+"노드 이름 '%s'을(를) 씬에서 '%s'에 대해 고유하게 만들었지만, 그것은 이미 "
+"'%s'가 소유하고 있습니다.\n"
+"'%s'는 더 이상 고유 이름을 가지지 않게 됩니다."
+
+msgid ""
+"This node is marked as deprecated and will be removed in future versions.\n"
+"Please check the Godot documentation for information about migration."
+msgstr ""
+"이 노드는 더 이상 사용되지 않으며 이후 버전에서는 제거될 것입니다.\n"
+"더 자세한 사항은 Godot 문서를 참조해 주세요."
+
+msgid ""
+"This node is marked as experimental and may be subject to removal or major "
+"changes in future versions."
+msgstr "이 노드는 실험적이며 이후 버전에서 삭제되거나 변경될 수도 있습니다."
+
+msgid ""
+"Default Environment as specified in the project setting \"rendering/"
+"environment/defaults/default_environment\" could not be loaded."
+msgstr ""
+"프로젝트 설정 \"rendering/environment/defaults/default_environment\"에 지정"
+"한 디폴트 환경을 불러올 수 없습니다."
+
+msgid ""
"Very low timer wait times (< 0.05 seconds) may behave in significantly "
"different ways depending on the rendered or physics frame rate.\n"
"Consider using a script's process loop instead of relying on a Timer for "
@@ -9659,10 +14148,17 @@ msgid "Unsupported BMFont texture format."
msgstr "지원되지 않는 BMFont 텍스처 형식입니다."
msgid ""
+"Shader keywords cannot be used as parameter names.\n"
+"Choose another name."
+msgstr ""
+"셰이더 키워드를 매개변수 이름으로 사용할 수 없습니다.\n"
+"다른 이름을 선택해 주세요."
+
+msgid ""
"The sampler port is connected but not used. Consider changing the source to "
"'SamplerPort'."
msgstr ""
-"샘플러 포트가 연결되어 있지만 사용되지 않습이다. 소스를 'SamplerPort'로 변경"
+"샘플러 포트가 연결되어 있지만 사용되지 않습니다. 소스를 'SamplerPort'로 변경"
"하는 것을 고려해주세요."
msgid "Invalid source for preview."
@@ -9671,6 +14167,9 @@ msgstr "미리보기에 잘못된 소스."
msgid "Invalid source for shader."
msgstr "셰이더에 잘못된 소스."
+msgid "Default Color"
+msgstr "기본 색"
+
msgid "Filter"
msgstr "필터"
@@ -9680,14 +14179,23 @@ msgstr "반복"
msgid "Invalid comparison function for that type."
msgstr "해당 타입에 잘못된 비교 함수."
+msgid "Invalid arguments for the built-in function: \"%s(%s)\"."
+msgstr "내장 함수에 잘못된 인수가 들어감: \"%s(%s)\"."
+
+msgid "Invalid assignment of '%s' to '%s'."
+msgstr "'%s'을(를) '%s'에 대입할 수 없습니다."
+
+msgid "Expected constant expression."
+msgstr "상수 표현식이 와야 합니다."
+
msgid "Varying may not be assigned in the '%s' function."
msgstr "Varying은 '%s' 함수에서 할당되지 않을 수 있습니다."
msgid "Assignment to function."
-msgstr "함수에 대입."
+msgstr "함수에 대입할 수 없습니다."
msgid "Assignment to uniform."
-msgstr "Uniform에 대입."
+msgstr "uniform에 대입할 수 없습니다."
msgid "Constants cannot be modified."
msgstr "상수는 수정할 수 없습니다."
@@ -9696,8 +14204,8 @@ msgid ""
"Sampler argument %d of function '%s' called more than once using different "
"built-ins. Only calling with the same built-in is supported."
msgstr ""
-"다른 내장 함수를 사용하여 '%s' 함수의 샘플러 인수 %d를 두 번 이상 호출했습니"
-"다. 동일한 내장 함수를 사용한 호출만 지원됩니다."
+"서로 다른 내장 함수를 사용하여 샘플러 인수 %d을(를) '%s' 함수에서 두 번 이상 "
+"호출했습니다. 이 경우 동일한 내장 함수를 사용하는 호출만 지원됩니다."
msgid "Array size is already defined."
msgstr "배열 크기가 이미 정의되어 있습니다."
@@ -9709,38 +14217,82 @@ msgid "Array size expressions are not supported."
msgstr "배열 크기 표현식은 지원되지 않습니다."
msgid "Expected a positive integer constant."
-msgstr "양의 정수 상수를 기대합니다."
+msgstr "양의 정수형 상수가 와야 합니다."
+
+msgid "Invalid data type for the array."
+msgstr "잘못된 배열 데이터 타입입니다."
msgid "Array size mismatch."
-msgstr "배열 크기 불일치."
+msgstr "배열 크기가 일치하지 않습니다."
msgid "Expected array initialization."
-msgstr "예상 배열 초기화."
+msgstr "배열 초기화가 와야 합니다."
+
+msgid "Cannot convert from '%s' to '%s'."
+msgstr "'%s'을(를) '%s'로 변환할 수 없습니다."
+
+msgid "Expected ')' in expression."
+msgstr "표현식에 ')'가 와야 합니다."
+
+msgid "Void value not allowed in expression."
+msgstr "void형은 표현식에서 사용할 수 없습니다."
msgid "Expected '(' after the type name."
-msgstr "유형 이름 뒤에 '('가 예상됩니다."
+msgstr "타입 이름 뒤에 '('가 와야 합니다."
+
+msgid "No matching constructor found for: '%s'."
+msgstr "다음에 대한 생성자를 찾을 수 없습니다: '%s'."
+
+msgid "Expected a function name."
+msgstr "함수 이름이 와야 합니다."
+
+msgid "No matching function found for: '%s'."
+msgstr "다음 함수를 찾을 수 없습니다: '%s'."
+
+msgid ""
+"Varying '%s' must be assigned in the 'vertex' or 'fragment' function first."
+msgstr ""
+"Varying '%s'는 반드시 먼저 'vertex' 또는 'fragment' 함수에서 할당되어야 합니"
+"다."
+
+msgid "Varying '%s' cannot be passed for the '%s' parameter in that context."
+msgstr "Varying '%s'은 해당 문맥에서 '%s' 인자로 전달할 수 없습니다."
msgid "A constant value cannot be passed for '%s' parameter."
msgstr "'%s' 매개 변수에 상수 값을 전달할 수 없습니다."
+msgid ""
+"Unable to pass a multiview texture sampler as a parameter to custom "
+"function. Consider to sample it in the main function and then pass the "
+"vector result to it."
+msgstr ""
+"멀티뷰 텍스처 샘플러를 커스텀 함수의 인자로 넘겨줄 수 없습니다. 메인 함수에"
+"서 샘플한 뒤 그 결과값을 벡터로 넘겨주는 것을 고려해 보세요."
+
msgid "Unknown identifier in expression: '%s'."
-msgstr "식의 알 수 없는 식별자: '%s'입니다."
+msgstr "표현식에 알 수 없는 식별자가 있습니다: '%s'."
msgid ""
"%s has been removed in favor of using hint_%s with a uniform.\n"
"To continue with minimal code changes add 'uniform sampler2D %s : hint_%s, "
"filter_linear_mipmap;' near the top of your shader."
msgstr ""
-"유니폼에 hint_%s를 사용하기 위해 %s가 제거되었습니다.\n"
-"최소한의 코드 변경으로 계속하려면 셰이더 상단에 '유니폼 샘플러2D %s : "
+"%s는 uniform과 hint_%s를 사용하는 것으로 대체되었습니다.\n"
+"최소한의 코드 변경으로 계속하려면 셰이더 상단에 'uniform sampler2D %s : "
"hint_%s, filter_linear_mipmap;'을 추가하세요."
msgid ""
+"Varying with '%s' data type may only be used in the 'fragment' function."
+msgstr "'%s' 타입의 varying은 'fragment' 함수에서만 사용될 수 있습니다."
+
+msgid "Varying '%s' must be assigned in the 'fragment' function first."
+msgstr "Varying '%s'는 반드시 먼저 'fragment' 함수에서 할당되어야 합니다."
+
+msgid ""
"Varying with integer data type must be declared with `flat` interpolation "
"qualifier."
msgstr ""
-"정수 데이터 유형으로 변경하려면 `flat` 보간 한정자를 사용하여 선언해야 합니"
-"다."
+"정수형 타입을 가진 varying은 `flat` 보간 한정자를 사용하여 선언해야 합니다."
msgid "Can't use function as identifier: '%s'."
msgstr "함수를 식별자로 사용할 수 없습니다: '%s'."
@@ -9752,17 +14304,20 @@ msgid "Index [%d] out of range [%d..%d]."
msgstr "인덱스 [%d]가 범위[%d..%d]를 벗어났습니다."
msgid "Expected expression, found: '%s'."
-msgstr "예상 표현식을 찾았습니다: '%s'."
+msgstr "표현식이 와야 하는데, 찾은 것은 다음과 같습니다: '%s'."
msgid "Empty statement. Remove ';' to fix this warning."
msgstr "빈 문입니다. 이 경고를 수정하려면 ';'을 제거하세요."
msgid "Expected an identifier as a member."
-msgstr "회원으로서 식별자를 예상했습니다."
+msgstr "멤버로서 식별자가 와야 합니다."
msgid "Cannot combine symbols from different sets in expression '.%s'."
msgstr "표현식 '.%s'에서 서로 다른 집합의 기호를 결합할 수 없습니다."
+msgid "Invalid member for '%s' expression: '.%s'."
+msgstr "'%s' 표현식에 잘못된 멤버가 있습니다: '.%s'."
+
msgid "An object of type '%s' can't be indexed."
msgstr "'%s' 유형의 개체를 인덱싱할 수 없습니다."
@@ -9770,62 +14325,89 @@ msgid "Invalid base type for increment/decrement operator."
msgstr "증분/감소 연산자에 대한 기본 유형이 잘못되었습니다."
msgid "Invalid use of increment/decrement operator in a constant expression."
-msgstr "상수 표현식에 증분/감소 연산자를 잘못 사용했습니다."
+msgstr "상수 표현식에 증분/감소 연산자를 사용할 수 없습니다."
+
+msgid "Invalid token for the operator: '%s'."
+msgstr "연산자에 잘못된 토큰이 있습니다: '%s'."
+
+msgid "Unexpected end of expression."
+msgstr "예기치 못한 표현식의 끝입니다."
+
+msgid "Invalid arguments to unary operator '%s': %s."
+msgstr "단항 연산자 '%s'에 잘못된 인수가 있습니다: '%s'."
msgid "Missing matching ':' for select operator."
msgstr "선택 연산자에 일치하는 ':'가 없습니다."
+msgid "Invalid argument to ternary operator: '%s'."
+msgstr "삼항 연산자에 잘못된 인수가 있습니다: '%s'."
+
+msgid "Invalid arguments to operator '%s': '%s'."
+msgstr "연산자 '%s'에 잘못된 인수가 있습니다: '%s'."
+
msgid "A switch may only contain '%s' and '%s' blocks."
-msgstr "스위치에는 '%s' 및 '%s' 블록만 포함할 수 있습니다."
+msgstr "스위치는 '%s' 및 '%s' 블록만 포함할 수 있습니다."
msgid "Expected variable type after precision modifier."
-msgstr "정밀도 수정자 뒤에 예상되는 변수 유형입니다."
+msgstr "정밀도 수정자 뒤에 변수 타입이 와야 합니다."
+
+msgid "Invalid variable type (samplers are not allowed)."
+msgstr "잘못된 변수 타입입니다 (샘플러는 허용하지 않습니다)."
msgid "Expected an identifier or '[' after type."
-msgstr "유형 뒤에 식별자 또는 '['를 입력할 것으로 예상했습니다."
+msgstr "타입 뒤에 식별자 또는 '['가 와야 합니다."
msgid "Expected an identifier."
-msgstr "식별자를 예상했습니다."
+msgstr "식별자가 와야 합니다."
msgid "Expected array initializer."
-msgstr "예상 배열 초기화기입니다."
+msgstr "배열 초기화 문이 와야 합니다."
msgid "Expected data type after precision modifier."
-msgstr "정밀도 수정자 뒤에 예상되는 데이터 유형입니다."
+msgstr "정밀도 수정자 뒤에 데이터 타입이 와야 합니다."
msgid "Expected a constant expression."
-msgstr "상수 표현식을 기대했습니다."
+msgstr "상수 표현식이 와야 합니다."
msgid "Expected initialization of constant."
-msgstr "상수의 예상 초기화."
+msgstr "상수의 초기화가 와야 합니다."
msgid ""
"Expected constant expression for argument %d of function call after '='."
-msgstr "'=' 뒤에 오는 함수 호출의 인수 %d에 대해 예상되는 상수 표현식입니다."
+msgstr "'=' 뒤에 오는 함수 호출의 인수 %d에 대해 상수 표현식이 와야 합니다."
msgid "Expected a boolean expression."
-msgstr "부울 표현식을 예상했습니다."
+msgstr "부울 표현식이 와야 합니다."
msgid "Expected an integer expression."
-msgstr "정수 표현식을 예상했습니다."
+msgstr "정수 표현식이 와야 합니다."
msgid "Cases must be defined before default case."
-msgstr "기본 케이스보다 먼저 케이스를 정의해야 합니다."
+msgstr "케이스 정의는 기본 케이스 정의 이전에 와야 합니다."
msgid "Default case must be defined only once."
msgstr "기본 케이스는 한 번만 정의해야 합니다."
+msgid "Duplicated case label: %d."
+msgstr "중복된 케이스 라벨: %d."
+
msgid "'%s' must be placed within a '%s' block."
msgstr "'%s'는 '%s' 블록 내에 배치해야 합니다."
+msgid "Expected an integer constant."
+msgstr "정수형 상수가 와야 합니다."
+
msgid "Using '%s' in the '%s' processor function is incorrect."
-msgstr "'%s' 프로세서 함수에서 '%s'를 사용하는 것은 올바르지 않습니다."
+msgstr "'%s'를 '%s' 프로세서 함수에서 사용하는 것은 올바르지 않습니다."
msgid "Expected '%s' with an expression of type '%s'."
-msgstr "'%s' 유형의 식에 '%s'를 예상했습니다."
+msgstr "여기서 '%s'가 ('%s' 타입을 가진 표현문과 함께) 와야 합니다."
msgid "Expected return with an expression of type '%s'."
-msgstr "'%s' 유형의 식에 대한 예상 반환입니다."
+msgstr "여기서 '%s' 타입을 가지는 표현문을 반환해야 합니다."
+
+msgid "Use of '%s' is not allowed here."
+msgstr "'%s'은(는) 여기에 쓸 수 없습니다."
msgid "'%s' is not allowed outside of a loop or '%s' statement."
msgstr "'%s'는 루프 또는 '%s' 문 외부에서 허용되지 않습니다."
@@ -9834,10 +14416,10 @@ msgid "'%s' is not allowed outside of a loop."
msgstr "'%s'는 루프 외부에서 허용되지 않습니다."
msgid "The middle expression is expected to be a boolean operator."
-msgstr "중간 표현식은 부울 연산자로 예상됩니다."
+msgstr "중간 표현식에 부울 연산자가 와야 합니다."
msgid "The left expression is expected to be a variable declaration."
-msgstr "왼쪽 표현식은 변수 선언으로 예상됩니다."
+msgstr "왼쪽 표현식에 변수 선언이 와야 합니다."
msgid "The precision modifier cannot be used on structs."
msgstr "정밀도 수정자는 구조체에는 사용할 수 없습니다."
@@ -9846,52 +14428,77 @@ msgid "The precision modifier cannot be used on boolean types."
msgstr "정밀도 수정자는 부울 유형에는 사용할 수 없습니다."
msgid "Expected '%s' at the beginning of shader. Valid types are: %s."
-msgstr "셰이더 시작 부분에 '%s'가 예상됩니다. 유효한 유형은 %s."
+msgstr ""
+"셰이더 시작 부분에 '%s'가 와야 합니다. 유효한 타입들은 다음과 같습니다: %s."
msgid ""
"Expected an identifier after '%s', indicating the type of shader. Valid "
"types are: %s."
msgstr ""
-"셰이더 유형을 나타내는 '%s' 뒤에 식별자가 있을 것으로 예상됩니다. 유효한 유형"
-"은 다음과 같습니다: %s."
+"'%s' 뒤에 셰이더 유형을 나타내는 식별자가 있어야 합니다. 유효한 타입들은 다음"
+"과 같습니다: %s."
+
+msgid "Invalid shader type. Valid types are: %s"
+msgstr "잘못된 셰이더 타입입니다. 유효한 타입들은 다음과 같습니다: %s"
msgid "Expected an identifier for render mode."
-msgstr "렌더링 모드에 대한 식별자를 기대했습니다."
+msgstr "렌더링 모드에 대한 식별자가 와야 합니다."
+
+msgid "Duplicated render mode: '%s'."
+msgstr "중복된 렌더링 모드: '%s'."
msgid ""
"Redefinition of render mode: '%s'. The '%s' mode has already been set to "
"'%s'."
-msgstr "렌더링 모드의 재정의: '%s'. '%s' 모드가 이미 '%s'로 설정되었습니다."
+msgstr "렌더링 모드의 재정의: '%s'. '%s' 모드는 이미 '%s'로 설정되었습니다."
+
+msgid "Invalid render mode: '%s'."
+msgstr "잘못된 렌더 모드: '%s'."
+
+msgid "Unexpected token: '%s'."
+msgstr "예기치 못한 토큰: '%s'."
msgid "Expected a struct identifier."
-msgstr "구조 식별자를 예상했습니다."
+msgstr "구조체 식별자가 와야 합니다."
msgid "Nested structs are not allowed."
-msgstr "중첩 구조는 허용되지 않습니다."
+msgstr "중첩 구조체는 허용되지 않습니다."
+
+msgid "Expected data type."
+msgstr "데이터 타입이 와야 합니다."
msgid "A '%s' data type is not allowed here."
msgstr "여기에서는 '%s' 데이터 유형이 허용되지 않습니다."
msgid "Expected an identifier or '['."
-msgstr "식별자 또는 '['를 예상했습니다."
+msgstr "식별자 또는 '['가 와야 합니다."
msgid "Empty structs are not allowed."
-msgstr "빈 구조는 허용되지 않습니다."
+msgstr "빈 구조체는 허용되지 않습니다."
msgid "Uniform instances are not yet implemented for '%s' shaders."
-msgstr "'%s' 셰이더에 대한 유니폼 인스턴스가 아직 구현되지 않았습니다."
+msgstr "'%s' 셰이더에 대한 유니폼 인스턴스는 아직 구현되지 않았습니다."
msgid "Uniform instances are not supported in gl_compatibility shaders."
msgstr "유니폼 인스턴스는 gl_compatibility 셰이더에서 지원되지 않습니다."
+msgid "Varyings cannot be used in '%s' shaders."
+msgstr "varying은 '%s' 셰이더에서 사용할 수 없습니다."
+
msgid "Interpolation qualifiers are not supported for uniforms."
msgstr "유니폼에는 보간 한정자가 지원되지 않습니다."
msgid "The '%s' data type is not supported for uniforms."
-msgstr "유니폼에는 '%s' 데이터 유형이 지원되지 않습니다."
+msgstr "유니폼에는 '%s' 데이터 타입이 지원되지 않습니다."
+
+msgid "The '%s' data type is not allowed here."
+msgstr "여기서 '%s' 데이터 타입을 사용할 수 없습니다."
msgid "Interpolation modifier '%s' cannot be used with boolean types."
-msgstr "보간 수정자 '%s'는 부울 유형과 함께 사용할 수 없습니다."
+msgstr "보간 수정자 '%s'는 부울 타입과 함께 사용할 수 없습니다."
+
+msgid "Invalid data type for varying."
+msgstr "잘못된 varying 데이터 타입입니다."
msgid "Global uniform '%s' does not exist. Create it in Project Settings."
msgstr "글로벌 유니폼 '%s'가 존재하지 않습니다. 프로젝트 설정에서 생성하세요."
@@ -9915,13 +14522,19 @@ msgid "This hint is not supported for uniform arrays."
msgstr "이 힌트는 균일 배열에는 지원되지 않습니다."
msgid "Source color hint is for '%s', '%s' or sampler types only."
-msgstr "소스 색상 힌트는 '%s', '%s' 또는 샘플러 유형에만 해당됩니다."
+msgstr "소스 색상 힌트는 '%s', '%s', 샘플러 유형에만 사용할 수 있습니다."
+
+msgid "Duplicated hint: '%s'."
+msgstr "중복된 힌트: '%s'."
msgid "Range hint is for '%s' and '%s' only."
-msgstr "범위 힌트는 '%s' 및 '%s'에만 해당됩니다."
+msgstr "범위 힌트는 '%s' 및 '%s'에만 사용할 수 있습니다."
msgid "Expected ',' after integer constant."
-msgstr "정수 상수 뒤에 ','가 예상됩니다."
+msgstr "정수형 상수 뒤에 ','가 와야 합니다."
+
+msgid "Expected an integer constant after ','."
+msgstr "',' 뒤에 정수형 상수가 와야 합니다."
msgid "Can only specify '%s' once."
msgstr "'%s'를 한 번만 지정할 수 있습니다."
@@ -9935,7 +14548,14 @@ msgstr "허용되는 인스턴스 균일 인덱스는 [0..%d] 범위 내에 있
msgid ""
"'hint_normal_roughness_texture' is not supported in gl_compatibility shaders."
msgstr ""
-"'힌트_노멀_거칠기_텍스처'는 gl_compatibility 셰이더에서 지원되지 않습니다."
+"'hint_normal_roughness_texture'는 gl_compatibility 셰이더에서 지원되지 않습니"
+"다."
+
+msgid "'hint_normal_roughness_texture' is not supported in '%s' shaders."
+msgstr "'hint_normal_roughness_texture'는 '%s' 셰이더에서 지원되지 않습니다."
+
+msgid "'hint_depth_texture' is not supported in '%s' shaders."
+msgstr "'hint_depth_texture'는 '%s' 셰이더에서 지원되지 않습니다."
msgid "This hint is only for sampler types."
msgstr "이 힌트는 샘플러 유형에만 해당됩니다."
@@ -9943,119 +14563,205 @@ msgstr "이 힌트는 샘플러 유형에만 해당됩니다."
msgid "Redefinition of hint: '%s'. The hint has already been set to '%s'."
msgstr "힌트 재정의: '%s'. 힌트가 이미 '%s'로 설정되었습니다."
+msgid "Duplicated filter mode: '%s'."
+msgstr "중복된 필터 모드: '%s'."
+
msgid ""
"Redefinition of filter mode: '%s'. The filter mode has already been set to "
"'%s'."
-msgstr "필터 모드의 재정의: '%s'. 필터 모드가 이미 '%s'로 설정되었습니다."
+msgstr "필터 모드의 재정의: '%s'. 필터 모드는 이미 '%s'로 설정되었습니다."
+
+msgid "Duplicated repeat mode: '%s'."
+msgstr "중복된 반복 모드: '%s'."
msgid ""
"Redefinition of repeat mode: '%s'. The repeat mode has already been set to "
"'%s'."
-msgstr "반복 모드의 재정의: '%s'. 반복 모드가 이미 '%s'로 설정되었습니다."
+msgstr "반복 모드의 재정의: '%s'. 반복 모드는 이미 '%s'로 설정되었습니다."
msgid "Too many '%s' uniforms in shader, maximum supported is %d."
-msgstr "셰이더에 '%s' 유니폼이 너무 많아서 지원되는 최대값이 %d입니다."
+msgstr "셰이더에 '%s' 유니폼이 너무 많습니다, 지원되는 최대 개수는 %d입니다."
msgid "Setting default values to uniform arrays is not supported."
-msgstr "기본값을 균일 배열로 설정하는 것은 지원되지 않습니다."
+msgstr "uniform 배열에 기본값을 설정하는 것은 지원되지 않습니다."
msgid "Expected constant expression after '='."
-msgstr "'=' 뒤에 예상되는 상수 표현식입니다."
+msgstr "'=' 뒤에 상수 표현식이 와야 합니다."
+
+msgid "Can't convert constant to '%s'."
+msgstr "상수를 '%s'로 변환할 수 없습니다."
msgid "Expected an uniform subgroup identifier."
-msgstr "균일한 하위 그룹 식별자를 기대했습니다."
+msgstr "uniform 하위 그룹 식별자를 기대했습니다."
msgid "Expected an uniform group identifier."
-msgstr "균일한 그룹 식별자를 기대했습니다."
+msgstr "uniform 그룹 식별자를 기대했습니다."
msgid "Expected an uniform group identifier or `;`."
-msgstr "균일한 그룹 식별자 또는 `;`가 예상됩니다."
+msgstr "uniform 그룹 식별자 또는 `;`이 와야 합니다."
msgid "Group needs to be opened before."
-msgstr "이전에 그룹을 열어야 합니다."
+msgstr "이 앞에 열린 그룹이 있어야 합니다."
msgid "Shader type is already defined."
msgstr "셰이더 유형이 이미 정의되어 있습니다."
msgid "Expected constant, function, uniform or varying."
-msgstr "예상 상수, 함수, 균일 또는 가변."
+msgstr "상수, 함수, uniform, varying 중 하나가 와야 합니다."
+
+msgid "Invalid constant type (samplers are not allowed)."
+msgstr "잘못된 상수 타입입니다 (샘플러는 허용하지 않습니다)."
+
+msgid "Invalid function type (samplers are not allowed)."
+msgstr "잘못된 함수 타입입니다 (샘플러는 허용하지 않습니다)."
msgid "Expected a function name after type."
-msgstr "유형 뒤에 함수 이름을 예상했습니다."
+msgstr "타입 뒤에 함수 이름이 와야 합니다."
msgid "Expected '(' after function identifier."
-msgstr "함수 식별자 뒤에 '('가 예상됩니다."
+msgstr "함수 식별자 뒤에 '('가 와야 합니다."
msgid ""
"Global non-constant variables are not supported. Expected '%s' keyword "
"before constant definition."
msgstr ""
-"전역 비상수 변수는 지원되지 않습니다. 상수 정의 앞에 '%s' 키워드가 예상되었습"
-"니다."
+"상수가 아닌 전역 변수는 지원되지 않습니다. 상수 정의 앞에 '%s' 키워드가 와야 "
+"합니다."
msgid "Expected an identifier after type."
-msgstr "유형 뒤에 식별자를 입력할 것으로 예상됩니다."
+msgstr "유형 뒤에 식별자가 와야 합니다."
msgid ""
"The '%s' qualifier cannot be used within a function parameter declared with "
"'%s'."
-msgstr ""
-"'%s'로 선언된 함수 매개 변수 내에서는 '%s' 한정자를 사용할 수 없습니다."
+msgstr "'%s' 한정자는 '%s'로 선언된 함수 매개 변수 내에서 사용할 수 없습니다."
msgid "Expected a valid data type for argument."
-msgstr "인수의 유효한 데이터 유형이 예상됩니다."
+msgstr "인자로 유효한 데이터 타입이 있어야 합니다."
+
+msgid "Opaque types cannot be output parameters."
+msgstr "불투명한 타입이 출력 인자일 수 없습니다."
msgid "Void type not allowed as argument."
-msgstr "무효 유형은 인자로 허용되지 않습니다."
+msgstr "void 타입은 인자로 허용되지 않습니다."
msgid "Expected an identifier for argument name."
-msgstr "인자 이름에 대한 식별자를 기대했습니다."
+msgstr "인자 이름에 대한 식별자가 필요합니다."
msgid "Function '%s' expects no arguments."
-msgstr "함수 '%s'에 인수가 없습니다."
+msgstr "함수 '%s'에는 인수가 없습니다."
msgid "Function '%s' must be of '%s' return type."
msgstr "함수 '%s'는 반환 유형이 '%s'여야 합니다."
+msgid "Expected a '{' to begin function."
+msgstr "함수를 시작하는 '{'가 필요합니다."
+
msgid "Expected at least one '%s' statement in a non-void function."
-msgstr "무효화되지 않은 함수에서 하나 이상의 '%s' 문이 예상됩니다."
+msgstr "void가 아닌 함수에는 하나 이상의 '%s' 문이 와야 합니다."
+
+msgid "uniform buffer"
+msgstr "uniform 버퍼"
+
+msgid "Expected a '%s'."
+msgstr "'%s'가 와야 합니다."
+
+msgid "Expected a '%s' or '%s'."
+msgstr "'%s' 또는 '%s'가 와야 합니다."
+
+msgid "Expected a '%s' after '%s'."
+msgstr "'%s' 앞에 '%s'가 와야 합니다."
+
+msgid "Redefinition of '%s'."
+msgstr "'%s'의 재정의입니다."
msgid "Unknown directive."
-msgstr "알 수 없는 지시문."
+msgstr "알 수 없는 지시문입니다."
+
+msgid "Invalid macro name."
+msgstr "잘못된 매크로 이름입니다."
msgid "Macro redefinition."
-msgstr "매크로 재정의."
+msgstr "매크로 재정의가 있습니다."
+
+msgid "Invalid argument name."
+msgstr "잘못된 인자명입니다."
msgid "Expected a comma in the macro argument list."
-msgstr "매크로 인수 목록에 쉼표가 예상됩니다."
+msgstr "매크로 인수 목록에 쉼표가 필요합니다."
msgid "Unmatched elif."
-msgstr "타의 추종을 불허하는 엘리프."
+msgstr "매칭되지 않은 elif입니다."
+
+msgid "Missing condition."
+msgstr "조건이 없습니다."
+
+msgid "Condition evaluation error."
+msgstr "조건을 계산하는 데 오류가 있습니다."
+
+msgid "Unmatched else."
+msgstr "매칭되지 않은 else입니다."
+
+msgid "Invalid else."
+msgstr "잘못된 else입니다."
msgid "Unmatched endif."
-msgstr "타의 추종을 불허하는 엔디프."
+msgstr "매칭되지 않은 endif입니다."
+
+msgid "Invalid endif."
+msgstr "잘못된 endif입니다."
+
+msgid "Invalid ifdef."
+msgstr "잘못된 ifdef입니다."
+
+msgid "Invalid ifndef."
+msgstr "잘못된 ifndef입니다."
+
+msgid "Shader include file does not exist:"
+msgstr "셰이더 인클루드 파일이 존재하지 않습니다:"
msgid ""
"Shader include load failed. Does the shader include exist? Is there a cyclic "
"dependency?"
msgstr ""
-"셰이더 포함 로드에 실패했습니다. 셰이더 인클루드가 존재합니까? 순환 종속성이 "
-"있습니까?"
+"셰이더 인클루드를 불러오지 못했습니다. 셰이더 인클루드가 존재하나요? 순환 참"
+"조가 있나요?"
msgid "Shader include resource type is wrong."
-msgstr "셰이더 포함 리소스 유형이 잘못되었습니다."
+msgstr "셰이더 인클루드 리소스 유형이 잘못되었습니다."
+
+msgid "Cyclic include found"
+msgstr "순환 참조가 발견되었습니다"
msgid "Shader max include depth exceeded."
-msgstr "셰이더 최대 포함 깊이가 초과되었습니다."
+msgstr "셰이더의 최대 참조 깊이가 초과되었습니다."
+
+msgid "Invalid pragma directive."
+msgstr "잘못된 pragma 지시문입니다."
+
+msgid "Invalid undef."
+msgstr "잘못된 undef입니다."
msgid "Macro expansion limit exceeded."
msgstr "매크로 확장 제한을 초과했습니다."
+msgid "Invalid macro argument list."
+msgstr "매크로의 인자 리스트가 잘못되었습니다."
+
+msgid "Invalid macro argument."
+msgstr "매크로의 인자가 잘못되었습니다."
+
+msgid "Invalid macro argument count."
+msgstr "매크로의 인자 개수가 잘못되었습니다."
+
msgid "Can't find matching branch directive."
msgstr "일치하는 브랜치 지시문을 찾을 수 없습니다."
+msgid "Invalid symbols placed before directive."
+msgstr "지시문 앞에 올바르지 않은 기호가 있습니다."
+
msgid "Unmatched conditional statement."
-msgstr "타의 추종을 불허하는 조건문."
+msgstr "매칭되지 않은 조건문이 있습니다."
msgid ""
"Direct floating-point comparison (this may not evaluate to `true` as you "
@@ -10075,10 +14781,10 @@ msgid "The struct '%s' is declared but never used."
msgstr "구조체 '%s'가 선언되었지만 사용되지 않았습니다."
msgid "The uniform '%s' is declared but never used."
-msgstr "균일한 '%s'가 선언되었지만 사용되지 않았습니다."
+msgstr "uniform '%s'가 선언되었지만 사용되지 않았습니다."
msgid "The varying '%s' is declared but never used."
-msgstr "다양한 '%s'가 선언되었지만 사용되지 않았습니다."
+msgstr "varying '%s'가 선언되었지만 사용되지 않았습니다."
msgid "The local variable '%s' is declared but never used."
msgstr "로컬 변수 '%s'가 선언되었지만 사용되지 않았습니다."
diff --git a/editor/translations/editor/pl.po b/editor/translations/editor/pl.po
index b799f91a51..efe197b92b 100644
--- a/editor/translations/editor/pl.po
+++ b/editor/translations/editor/pl.po
@@ -85,7 +85,7 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-20 03:05+0000\n"
+"PO-Revision-Date: 2023-07-04 00:53+0000\n"
"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
@@ -95,7 +95,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Unset"
msgstr "Wymaż"
@@ -2549,6 +2549,11 @@ msgstr "Zaimportuj zasoby typu: %s"
msgid "No return value."
msgstr "Brak zwracanego typu."
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr ""
+"Ta wartość jest liczbą całkowitą złożoną jako maska bitowa następujących "
+"flag."
+
msgid "Deprecated"
msgstr "Przestarzałe"
@@ -4082,6 +4087,12 @@ msgstr "Joystick 4 w górę"
msgid "Joystick 4 Down"
msgstr "Joystick 4 w dół"
+msgid "or"
+msgstr "lub"
+
+msgid "Unicode"
+msgstr "Unikod"
+
msgid "Joypad Axis %d %s (%s)"
msgstr "Oś joypada %d %s (%s)"
@@ -6834,7 +6845,7 @@ msgid "units"
msgstr "jednostki"
msgid "Moving:"
-msgstr "Przeniesienie:"
+msgstr "Przesuwanie:"
msgid "Rotating:"
msgstr "Obrót:"
@@ -8199,6 +8210,9 @@ msgstr "Rozmiar: %s (%.1fMP)\n"
msgid "Objects: %d\n"
msgstr "Obiektów: %d\n"
+msgid "Primitives: %d\n"
+msgstr "Prymitywy: %d\n"
+
msgid "Draw Calls: %d"
msgstr "Wywołania rysowania: %d"
@@ -10536,6 +10550,13 @@ msgstr "Rozproszenie:"
msgid "Tiles"
msgstr "Kafelki"
+msgid ""
+"This TileMap's TileSet has no source configured. Go to the TileSet bottom "
+"tab to add one."
+msgstr ""
+"TileSet tej TileMapy nie ma skonfigurowanego źródła. Przejdź do dolnej "
+"zakładki TileSet, by jakieś dodać."
+
msgid "Sort sources"
msgstr "Sortuj źródła"
@@ -10612,6 +10633,13 @@ msgstr "Przełącz widoczność siatki."
msgid "Automatically Replace Tiles with Proxies"
msgstr "Automatycznie zastąp kafelki zamiennikami"
+msgid ""
+"The edited TileMap node has no TileSet resource.\n"
+"Create or load a TileSet resource in the Tile Set property in the inspector."
+msgstr ""
+"Edytowany węzeł TileMap nie ma zasobu TileSet.\n"
+"Utwórz lub wczytaj zasób TileSet we właściowości Tile Set w inspektorze."
+
msgid "Remove Tile Proxies"
msgstr "Usuń zamienniki kafelków"
@@ -10830,6 +10858,15 @@ msgstr "Otwórz narzędzie scalania atlasów"
msgid "Manage Tile Proxies"
msgstr "Zarządzaj zamiennikami kafelków"
+msgid ""
+"No TileSet source selected. Select or create a TileSet source.\n"
+"You can create a new source by using the Add button on the left or by "
+"dropping a tileset texture onto the source list."
+msgstr ""
+"Nie wybrano źródła TileSet. Wybierz lub utwórz źródło TileSet.\n"
+"Możesz utworzyć nowe źródło używając przycisku Dodaj po lewej albo "
+"upuszczając teksturę kafelków na listę źródeł."
+
msgid "Add new patterns in the TileMap editing mode."
msgstr "Dodaj nowe wzory w trybie edycji TileMap."
@@ -12942,6 +12979,9 @@ msgstr "Nazwa pliku nieprawidłowa."
msgid "File already exists."
msgstr "Plik już istnieje."
+msgid "Root node valid."
+msgstr "Korzeń prawidłowy."
+
msgid "Invalid root node name."
msgstr "Nieprawidłowa nazwa korzenia."
@@ -14135,6 +14175,20 @@ msgid "Could not execute on device."
msgstr "Nie udało się uruchomić na urządzeniu."
msgid ""
+"Exporting to Android is currently not supported in Godot 4 when using C#/."
+"NET. Use Godot 3 to target Android with C#/Mono instead."
+msgstr ""
+"Eksportowanie na Androida nie jest aktualnie wspierane w Godocie 4 z użyciem "
+"C#/.NET. Zamiast tego użyj Godota 3, by celować w Androida z C#/Mono."
+
+msgid ""
+"If this project does not use C#, use a non-C# editor build to export the "
+"project."
+msgstr ""
+"Jeśli ten projekt nie używa C#, użyj edytora bez C#, by wyeksportować "
+"projekt."
+
+msgid ""
"Android build template not installed in the project. Install it from the "
"Project menu."
msgstr ""
@@ -14384,6 +14438,13 @@ msgstr ""
".ipa można zbudować tylko w systemie macOS. Opuszczanie projektu Xcode bez "
"budowania pakietu."
+msgid ""
+"Exporting to iOS is currently not supported in Godot 4 when using C#/.NET. "
+"Use Godot 3 to target iOS with C#/Mono instead."
+msgstr ""
+"Eksportowanie na iOS nie jest aktualnie wspierane w Godocie 4 z użyciem C#/."
+"NET. Zamiast tego użyj Godota 3, by celować w iOS z C#/Mono."
+
msgid "Identifier is missing."
msgstr "Brakuje identyfikatora."
@@ -14396,6 +14457,12 @@ msgstr "Eksport skryptu debugowania"
msgid "Could not open file \"%s\"."
msgstr "Nie można otworzyć pliku \"%s\"."
+msgid "Debug Console Export"
+msgstr "Eksport konsoli debugowania"
+
+msgid "Could not create console wrapper."
+msgstr "Nie udało się utworzyć pliku konsoli."
+
msgid "Failed to open executable file \"%s\"."
msgstr "Nie udało się otworzyć pliku wykonywalnego \"%s\"."
@@ -14873,6 +14940,14 @@ msgstr "Nie można odczytać pliku: \"%s\"."
msgid "PWA"
msgstr "PWA"
+msgid ""
+"Exporting to Web is currently not supported in Godot 4 when using C#/.NET. "
+"Use Godot 3 to target Web with C#/Mono instead."
+msgstr ""
+"Eksportowanie na przeglądarki nie jest aktualnie wspierane w Godocie 4 z "
+"użyciem C#/.NET. Zamiast tego użyj Godota 3, by celować w przeglądarki z C#/"
+"Mono."
+
msgid "Could not read HTML shell: \"%s\"."
msgstr "Nie można odczytać powłoki HTML: \"%s\"."
@@ -15091,6 +15166,13 @@ msgstr ""
"Ścieżki cząstek są dostępne tylko w przypadku korzystania z zaplecza "
"renderowania Forward+ lub Mobile."
+msgid ""
+"Particle sub-emitters are not available when using the GL Compatibility "
+"rendering backend."
+msgstr ""
+"Podemitery cząstek nie są dostępne w przypadku korzystania z zaplecza "
+"renderowania Kompatybilności GL."
+
msgid "Node A and Node B must be PhysicsBody2Ds"
msgstr "Node A i Node B muszą być węzłami PhysicsBody2D"
@@ -15432,6 +15514,13 @@ msgstr ""
"nie ustawione na renderowanie śladów."
msgid ""
+"Particle sub-emitters are only available when using the Forward+ or Mobile "
+"rendering backends."
+msgstr ""
+"Podemitery cząstek są dostępne tylko w przypadku korzystania z zaplecza "
+"renderowania Forward+ lub Mobile."
+
+msgid ""
"The Bake Mask has no bits enabled, which means baking will not produce any "
"collision for this GPUParticlesCollisionSDF3D.\n"
"To resolve this, enable at least one bit in the Bake Mask property."
@@ -16071,6 +16160,16 @@ msgid "Invalid BMFont block type."
msgstr "Nieprawidłowy typ bloku BMFont."
msgid ""
+"An incoming node's name clashes with %s already in the scene (presumably, "
+"from a more nested instance).\n"
+"The less nested node will be renamed. Please fix and re-save the scene."
+msgstr ""
+"Przychodząca nazwa węzła konfliktuje z %s, która jest już na scenie "
+"(przypuszczalnie z bardziej zagnieżdżonej instancji).\n"
+"Mniej zagnieżdżony węzeł zostanie przemianowany. Proszę naprawić i zapisać "
+"scenę ponownie."
+
+msgid ""
"Shader keywords cannot be used as parameter names.\n"
"Choose another name."
msgstr ""
diff --git a/editor/translations/editor/ro.po b/editor/translations/editor/ro.po
index 124dbe712e..1fee93a433 100644
--- a/editor/translations/editor/ro.po
+++ b/editor/translations/editor/ro.po
@@ -25,13 +25,14 @@
# Vlad Cuciureanu <vlad.cuciureanu@pm.me>, 2023.
# "Hash Volt[ing]" <hashvolting@gmail.com>, 2023.
# RaresX22 <raresadv22@gmail.com>, 2023.
+# omoNattie <omonattie@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-04-23 20:05+0000\n"
-"Last-Translator: RaresX22 <raresadv22@gmail.com>\n"
+"PO-Revision-Date: 2023-06-27 20:09+0000\n"
+"Last-Translator: omoNattie <omonattie@gmail.com>\n"
"Language-Team: Romanian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ro/>\n"
"Language: ro\n"
@@ -40,7 +41,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
"20)) ? 1 : 2;\n"
-"X-Generator: Weblate 4.18-dev\n"
+"X-Generator: Weblate 4.18.1\n"
msgid "Unset"
msgstr "Nesetat"
@@ -638,7 +639,7 @@ msgid "Cannot connect signal"
msgstr "Nu se poate conecta semnalul"
msgid "Close"
-msgstr "Aproape"
+msgstr "Închide"
msgid "Connect"
msgstr "Conectați"
diff --git a/editor/translations/editor/ru.po b/editor/translations/editor/ru.po
index 3a2f98ab58..90688f670e 100644
--- a/editor/translations/editor/ru.po
+++ b/editor/translations/editor/ru.po
@@ -147,12 +147,13 @@
# Don Miguel <mikhail.bratus@gmail.com>, 2023.
# Mmaxum <max55926@yandex.ru>, 2023.
# ZIP2020 <folstagking@gmail.com>, 2023.
+# Plizik <channelofplizik@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-23 12:52+0000\n"
+"PO-Revision-Date: 2023-07-05 13:48+0000\n"
"Last-Translator: ZIP2020 <folstagking@gmail.com>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ru/>\n"
@@ -162,7 +163,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Unset"
msgstr "Не задано"
@@ -1189,6 +1190,10 @@ msgid "Select Transition and Easing"
msgstr "Выбрать переход и ослабление"
msgctxt "Transition Type"
+msgid "Linear"
+msgstr "Линейный"
+
+msgctxt "Transition Type"
msgid "Sine"
msgstr "Синусоидальный"
@@ -1213,6 +1218,10 @@ msgid "Elastic"
msgstr "Эластичный"
msgctxt "Transition Type"
+msgid "Cubic"
+msgstr "Кубический"
+
+msgctxt "Transition Type"
msgid "Circ"
msgstr "По окружности"
@@ -1236,6 +1245,9 @@ msgctxt "Ease Type"
msgid "OutIn"
msgstr "Выход и вход"
+msgid "Transition Type:"
+msgstr "Тип перехода:"
+
msgid "Ease Type:"
msgstr "Сглаживание:"
@@ -1245,6 +1257,9 @@ msgstr "Кадр. в сек.:"
msgid "3D Pos/Rot/Scl Track:"
msgstr "3D поз./Поворот/Масштаб:"
+msgid "Value Track:"
+msgstr "Дорожка значения:"
+
msgid "Select Tracks to Copy"
msgstr "Выбрать дорожки для копирования"
@@ -1537,9 +1552,24 @@ msgstr "Переключить видимость"
msgid "Updating assets on target device:"
msgstr "Обновление ассетов на целевом устройстве:"
+msgid "Syncing headers"
+msgstr "Синхронизация заголовков"
+
+msgid "Getting remote file system"
+msgstr "Получение удалённой файловой системы"
+
+msgid "Decompressing remote file system"
+msgstr "Распаковка удалённой файловой системы"
+
+msgid "Scanning for local changes"
+msgstr "Сканирование локальных изменений"
+
msgid "Sending list of changed files:"
msgstr "Отправка списка измененных файлов:"
+msgid "Sending file:"
+msgstr "Отправка файла:"
+
msgid "ms"
msgstr "мс"
@@ -1801,6 +1831,12 @@ msgstr "Редактор зависимостей"
msgid "Search Replacement Resource:"
msgstr "Найти заменяемый ресурс:"
+msgid "Open Scene"
+msgid_plural "Open Scenes"
+msgstr[0] "Открыть сцену"
+msgstr[1] "Открыть сцены"
+msgstr[2] "Открыть сцены"
+
msgid "Open"
msgstr "Открыть"
@@ -1870,14 +1906,32 @@ msgstr "Кол-во"
msgid "Resources Without Explicit Ownership:"
msgstr "Ресурсы без явного владения:"
+msgid "Folder name cannot be empty."
+msgstr "Имя папки не может быть пустым."
+
+msgid "Folder name contains invalid characters."
+msgstr "Имя папки содержит недопустимые символы."
+
+msgid "File with that name already exists."
+msgstr "Файл с таким именем уже существует."
+
+msgid "Folder with that name already exists."
+msgstr "Папка с таким именем уже существует."
+
msgid "Using slashes in folder names will create subfolders recursively."
msgstr ""
"Использование косой черты в именах папок приведет к рекурсивному созданию "
"подпапок."
+msgid "Folder name is valid."
+msgstr "Имя папки допустимо."
+
msgid "Could not create folder."
msgstr "Невозможно создать папку."
+msgid "Create new folder in %s:"
+msgstr "Создать новую папку в %s:"
+
msgid "Create Folder"
msgstr "Создать папку"
@@ -2557,6 +2611,11 @@ msgstr "Импорт ресурсов типа: %s"
msgid "No return value."
msgstr "Возвращаемое значение отсутствует."
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr ""
+"Это значение является целым числом, составленным как битовая маска следующих "
+"флагов."
+
msgid "Deprecated"
msgstr "Устаревший"
@@ -2817,6 +2876,12 @@ msgstr ""
msgid "Open Documentation"
msgstr "Открыть документацию"
+msgid "(%d change)"
+msgid_plural "(%d changes)"
+msgstr[0] "(%d изменение)"
+msgstr[1] "(%d изменения)"
+msgstr[2] "(%d изменений)"
+
msgid "Add element to property array with prefix %s."
msgstr "Добавить элемент в массив свойств с префиксом %s."
@@ -3991,6 +4056,12 @@ msgid ""
msgstr ""
"Не удалось запустить скрипт редактора, вы забыли переопределить метод '_run'?"
+msgid "Undo: %s"
+msgstr "Отменить: %s"
+
+msgid "Redo: %s"
+msgstr "Повторить: %s"
+
msgid "Edit Built-in Action"
msgstr "Изменить встроенное действие"
@@ -4078,6 +4149,12 @@ msgstr "Джойстик 4 вверх"
msgid "Joystick 4 Down"
msgstr "Джойстик 4 вниз"
+msgid "or"
+msgstr "или"
+
+msgid "Unicode"
+msgstr "Unicode"
+
msgid "Joypad Axis %d %s (%s)"
msgstr "Ось %d джойстика %s (%s)"
@@ -4408,6 +4485,9 @@ msgstr "Ресурсы для экспорта:"
msgid "Delete preset '%s'?"
msgstr "Удалить пресет '%s'?"
+msgid "(Inherited)"
+msgstr "(Унаследовано)"
+
msgid "%s Export"
msgstr "Экспорт для %s"
@@ -4657,6 +4737,14 @@ msgid "Unable to update dependencies:"
msgstr "Не удалось обновить зависимости:"
msgid ""
+"This filename begins with a dot rendering the file invisible to the editor.\n"
+"If you want to rename it anyway, use your operating system's file manager."
+msgstr ""
+"Имя этого файла начинается с точки, что делает его невидимым для редактора.\n"
+"Если вы всё равно хотите переименовать его, воспользуйтесь файловым "
+"менеджером вашей операционной системы."
+
+msgid ""
"This file extension is not recognized by the editor.\n"
"If you want to rename it anyway, use your operating system's file manager.\n"
"After renaming to an unknown extension, the file won't be shown in the "
@@ -4671,6 +4759,13 @@ msgstr ""
msgid "A file or folder with this name already exists."
msgstr "Файл или папка с таким именем уже существует."
+msgid ""
+"The following files or folders conflict with items in the target location "
+"'%s':"
+msgstr ""
+"Следующие файлы или папки конфликтуют с элементами в целевом расположении "
+"«%s»:"
+
msgid "Do you wish to overwrite them or rename the copied files?"
msgstr "Вы хотите перезаписать их или переименовать скопированные файлы?"
@@ -4701,6 +4796,9 @@ msgstr "Редактировать зависимости..."
msgid "View Owners..."
msgstr "Просмотреть владельцев..."
+msgid "Create New"
+msgstr "Создать новый"
+
msgid "Folder..."
msgstr "Папка..."
@@ -4716,6 +4814,18 @@ msgstr "Ресурс..."
msgid "TextFile..."
msgstr "Текстовый файл..."
+msgid "Expand Folder"
+msgstr "Развернуть папку"
+
+msgid "Expand Hierarchy"
+msgstr "Развернуть иерархию"
+
+msgid "Collapse Hierarchy"
+msgstr "Свернуть иерархию"
+
+msgid "Move/Duplicate To..."
+msgstr "Переместить/дублировать в..."
+
msgid "Add to Favorites"
msgstr "Добавить в избранное"
@@ -4898,6 +5008,9 @@ msgstr "Не удалось создать папку. Файл с таким и
msgid "Choose a Directory"
msgstr "Выбрать каталог"
+msgid "Copy File(s)"
+msgstr "Копировать файл(ы)"
+
msgid "Network"
msgstr "Сеть"
@@ -5154,7 +5267,7 @@ msgid "This script is currently running in the editor."
msgstr "В данный момент этот скрипт запущен в редакторе."
msgid "This script is a custom type."
-msgstr "Данный скрипт принадлежит к пользовательскому типу."
+msgstr "Этот скрипт является пользовательским типом."
msgid "Open Script:"
msgstr "Открыть скрипт:"
@@ -5181,7 +5294,7 @@ msgstr ""
"Нажмите, чтобы открепить."
msgid "\"%s\" is not a known filter."
-msgstr "\"%s\" - неизвестный фильтр."
+msgstr "«%s» не является известным фильтром."
msgid "Invalid node name, the following characters are not allowed:"
msgstr "Некорректное имя узла, следующие символы недопустимы:"
@@ -7233,6 +7346,13 @@ msgstr "Справа по всей высоте"
msgid "Full Rect"
msgstr "Полный прямоугольник"
+msgid ""
+"Enable to also set the Expand flag.\n"
+"Disable to only set Shrink/Fill flags."
+msgstr ""
+"Включите, чтобы также установить флаг Expand.\n"
+"Отключите, чтобы установить только Shrink/Fill флаги."
+
msgid "Some parents of the selected nodes do not support the Expand flag."
msgstr ""
"Некоторые родительские узлы выбранных узлов не поддерживают расширенный флаг."
@@ -7318,6 +7438,9 @@ msgstr "Создать излучатель из узла"
msgid "Load Curve Preset"
msgstr "Загрузить заготовку кривой"
+msgid "Add Curve Point"
+msgstr "Добавить точку кривой"
+
msgid "Remove Curve Point"
msgstr "Удалить точку кривой"
@@ -7454,6 +7577,12 @@ msgstr[0] "Запустить %d экземпляр"
msgstr[1] "Запустить %d экземпляра"
msgstr[2] "Запустить %d экземпляров"
+msgid "Size: %s"
+msgstr "Размер: %s"
+
+msgid "Type: %s"
+msgstr "Тип: %s"
+
msgid "Overrides (%d)"
msgstr "Переопределения (%d)"
@@ -8003,6 +8132,9 @@ msgstr "Задать end_position"
msgid "Set NavigationObstacle3D Vertices"
msgstr "Установить вершины NavigationObstacle3D"
+msgid "Edit Vertices"
+msgstr "Редактировать вершины"
+
msgid "Edit Poly"
msgstr "Редактировать полигон"
@@ -8105,6 +8237,9 @@ msgstr "Размер: %s (%.1fMP)\n"
msgid "Objects: %d\n"
msgstr "Объекты: %d\n"
+msgid "Primitives: %d\n"
+msgstr "Примитивы: %d\n"
+
msgid "Draw Calls: %d"
msgstr "Вызовы отрисовки: %d"
@@ -8537,7 +8672,7 @@ msgid "Transform Change"
msgstr "Изменение преобразования"
msgid "Translate:"
-msgstr "Перемещение:"
+msgstr "Перемещать:"
msgid "Rotate (deg.):"
msgstr "Поворот (градусы):"
@@ -8595,6 +8730,9 @@ msgstr "Предпросмотр окружения"
msgid "Sky Color"
msgstr "Цвет неба"
+msgid "Sky Energy"
+msgstr "Энергия неба"
+
msgid "AO"
msgstr "AO"
@@ -8997,6 +9135,9 @@ msgstr "Переоткрыть закрытый скрипт"
msgid "Save All"
msgstr "Сохранить всё"
+msgid "Soft Reload Tool Script"
+msgstr "Мягкая перезагрузка tool-скрипта"
+
msgid "Copy Script Path"
msgstr "Копировать путь к скрипту"
@@ -9045,6 +9186,9 @@ msgstr "Перейти к предыдущему редактируемому д
msgid "Go to next edited document."
msgstr "Перейти к следующему редактируемому документу."
+msgid "Make the script editor floating."
+msgstr "Сделать редактор скриптов плавающим."
+
msgid "Discard"
msgstr "Сброс"
@@ -9111,6 +9255,12 @@ msgstr "Поиск"
msgid "Pick Color"
msgstr "Выбрать цвет"
+msgid "Folding"
+msgstr "Сворачивание"
+
+msgid "Indentation"
+msgstr "Отступ"
+
msgid "Uppercase"
msgstr "ВЕРХНИЙ РЕГИСТР"
@@ -9150,6 +9300,9 @@ msgstr "Развернуть все строки"
msgid "Evaluate Selection"
msgstr "Вычислить выделенное"
+msgid "Toggle Word Wrap"
+msgstr "Переключить перенос слов"
+
msgid "Trim Trailing Whitespace"
msgstr "Обрезать замыкающие пробелы"
@@ -9204,6 +9357,9 @@ msgstr "Перейти к предыдущей точке останова"
msgid "Shader Editor"
msgstr "Редактор шейдеров"
+msgid "New Shader Include"
+msgstr "Новый включаемый файл шейдера"
+
msgid "Load Shader File"
msgstr "Открыть файл шейдера"
@@ -9239,7 +9395,7 @@ msgstr ""
"\n"
msgid "ShaderFile"
-msgstr "Файл шейдера"
+msgstr "Файл Шейдера"
msgid "This skeleton has no bones, create some children Bone2D nodes."
msgstr "У этого скелета нет костей, создайте дочерние Bone2D узлы."
@@ -9309,6 +9465,9 @@ msgstr ""
msgid "Insert key of bone poses already exist track."
msgstr "Вставьте ключ позиции кости в уже существующей дорожке."
+msgid "Insert Key (All Bones)"
+msgstr "Вставить ключ (все кости)"
+
msgid "Bone Transform"
msgstr "Трансформация костей"
@@ -9479,6 +9638,9 @@ msgstr "Выбрать кадры"
msgid "Frame Order"
msgstr "Порядок кадров"
+msgid "By Row"
+msgstr "По строкам"
+
msgid "Left to Right, Top to Bottom"
msgstr "Слева направо, сверху вниз"
@@ -9491,6 +9653,9 @@ msgstr "Справа налево, сверху вниз"
msgid "Right to Left, Bottom to Top"
msgstr "Справа налево, снизу вверх"
+msgid "By Column"
+msgstr "По столбцам"
+
msgid "Top to Bottom, Left to Right"
msgstr "Сверху вниз, слева направо"
@@ -10092,6 +10257,9 @@ msgstr "Объединить (сохранить исходные атласы)"
msgid "Next Line After Column"
msgstr "Следующая строка после столбца"
+msgid "Please select two atlases or more."
+msgstr "Пожалуйста, выберите два атласа или более."
+
msgid ""
"Source: %d\n"
"Atlas coordinates: %s\n"
@@ -10119,9 +10287,27 @@ msgstr "Базовые тайлы"
msgid "Alternative Tiles"
msgstr "Альтернативные тайлы"
+msgid "Reset Polygons"
+msgstr "Сбросить полигоны"
+
+msgid "Clear Polygons"
+msgstr "Очистить полигоны"
+
+msgid "Flip Polygons Horizontally"
+msgstr "Отразить полигоны по горизонтали"
+
+msgid "Flip Polygons Vertically"
+msgstr "Отразить полигоны по вертикали"
+
+msgid "Edit Polygons"
+msgstr "Редактировать полигоны"
+
msgid "Edit points tool"
msgstr "Инструмент редактирования точек"
+msgid "Reset to default tile shape"
+msgstr "Сбросить к форме тайла по умолчанию"
+
msgid "Rotate Right"
msgstr "Повернуть вправо"
@@ -10134,6 +10320,9 @@ msgstr "Перевернуть по горизонтали"
msgid "Flip Vertically"
msgstr "Перевернуть по вертикали"
+msgid "Disable Snap"
+msgstr "Отключить привязку"
+
msgid "Painting:"
msgstr "Рисование:"
@@ -10149,6 +10338,9 @@ msgstr "Добавить шаблон TileSet"
msgid "Remove TileSet patterns"
msgstr "Удалить шаблон TileSet"
+msgid "Index: %d"
+msgstr "Индекс: %d"
+
msgid "Delete tiles"
msgstr "Удалить тайл"
@@ -10190,7 +10382,7 @@ msgstr "Разместить случайный тайл"
msgid ""
"Modifies the chance of painting nothing instead of a randomly selected tile."
-msgstr "Изменяет шанс покрасить пустоту вместо случайно выбранного тайла."
+msgstr "Изменяет шанс нарисовать пустоту вместо случайно выбранного тайла."
msgid "Tiles"
msgstr "Тайлы"
@@ -10224,7 +10416,14 @@ msgid "Highlight Selected TileMap Layer"
msgstr "Выделить выбранный TileMap"
msgid "Toggle grid visibility."
-msgstr "Отображение сетки."
+msgstr "Переключение видимости сетки."
+
+msgid ""
+"The edited TileMap node has no TileSet resource.\n"
+"Create or load a TileSet resource in the Tile Set property in the inspector."
+msgstr ""
+"Редактированный узел TileMap не имеет набора тайлов TileSet.\n"
+"Создайте или загрузите набор тайлов TileSet в свойство TileSet в инспекторе."
msgid "Create Alternative-level Tile Proxy"
msgstr "Создание прокси Тайл альтернативного уровня"
@@ -10232,6 +10431,9 @@ msgstr "Создание прокси Тайл альтернативного у
msgid "Create Coords-level Tile Proxy"
msgstr "Создание прокси Тайл на уровне координат"
+msgid "Create source-level Tile Proxy"
+msgstr "Создает Тайл-Прокси на уровне исходного кода"
+
msgid "Delete All Invalid Tile Proxies"
msgstr "Удалить все недопустимые Tile Proxies"
@@ -10330,6 +10532,16 @@ msgstr "Добавить новый исходник атласа"
msgid "Open Atlas Merging Tool"
msgstr "Открыть инструмент слияния атласов"
+msgid ""
+"No TileSet source selected. Select or create a TileSet source.\n"
+"You can create a new source by using the Add button on the left or by "
+"dropping a tileset texture onto the source list."
+msgstr ""
+"Источник набора тайлов TileSet не выбран. Выберите или создайте источник "
+"набора тайлов TileSet.\n"
+"Вы можете создать новый источник, используя кнопку \"Добавить\" слева, или "
+"закидывая текстуры набора тайлов TileSet в список источника."
+
msgid "Add new patterns in the TileMap editing mode."
msgstr "Добавляйте новые шаблоны в режиме редактирования тайловой карты."
@@ -10345,6 +10557,9 @@ msgstr "Свойства тайла:"
msgid "TileSet"
msgstr "Набор тайлов"
+msgid "TileMap"
+msgstr "TileMap"
+
msgid ""
"No VCS plugins are available in the project. Install a VCS plugin to use VCS "
"integration features."
@@ -10576,7 +10791,7 @@ msgid "Remove Output Port"
msgstr "Удалить выходной порт"
msgid "Set Comment Node Title"
-msgstr "Задать заголовок в узле комментария"
+msgstr "Задать заголовок узла комментария"
msgid "Set Parameter Name"
msgstr "Задать имя параметра"
@@ -11059,7 +11274,7 @@ msgid "Apply panning function on texture coordinates."
msgstr "Применить функцию панорамирования к координатам текстуры."
msgid "Apply scaling function on texture coordinates."
-msgstr "Использовать функцию масштабирования к координатам текстуры."
+msgstr "Применить функцию масштабирования к координатам текстуры."
msgid "Transform function."
msgstr "Функция преобразования."
@@ -11478,6 +11693,9 @@ msgstr ""
msgid "Version Control Metadata:"
msgstr "Метаданные контроля версий:"
+msgid "The project uses features unsupported by the current build:"
+msgstr "В проекте используются функции, не поддерживаемые текущей сборкой:"
+
msgid "Error: Project is missing on the filesystem."
msgstr "Ошибка: Проект отсутствует в файловой системе."
@@ -11667,6 +11885,18 @@ msgstr ""
msgid "Are you sure to run %d projects at once?"
msgstr "Вы уверены, что хотите запустить %d проектов одновременно?"
+msgid "Tag name can't be empty."
+msgstr "Имя метки не может быть пустым."
+
+msgid "Tag name can't contain spaces."
+msgstr "Имя метки не может содержать пробелы."
+
+msgid "These characters are not allowed in tags: %s."
+msgstr "Следующие символы не разрешены в метках: %s."
+
+msgid "Tag name must be lowercase."
+msgstr "Имя метки должно быть в нижнем регистре."
+
msgid "Remove %d projects from the list?"
msgstr "Удалить %d проектов из списка?"
@@ -11716,6 +11946,9 @@ msgstr "Загрузка, пожалуйста, ждите..."
msgid "Last Edited"
msgstr "Последнее изменение"
+msgid "Tags"
+msgstr "Метки"
+
msgid "New Project"
msgstr "Новый проект"
@@ -11752,6 +11985,9 @@ msgstr "Удалить все"
msgid "Also delete project contents (no undo!)"
msgstr "Также удалить содержимое проекта (нельзя отменить!)"
+msgid "Convert Full Project"
+msgstr "Конвертировать весь проект"
+
msgid ""
"This option will perform full project conversion, updating scenes, resources "
"and scripts from Godot 3.x to work in Godot 4.0.\n"
@@ -11784,6 +12020,27 @@ msgstr ""
"В настоящее время у вас нет никаких проектов.\n"
"Хотите изучить официальные примеры в Библиотеке ассетов?"
+msgid "Manage Project Tags"
+msgstr "Управление метками проекта"
+
+msgid "Project Tags"
+msgstr "Метки проекта"
+
+msgid "Click tag to remove it from the project."
+msgstr "Нажмите на метку, чтобы удалить её из проекта."
+
+msgid "All Tags"
+msgstr "Все метки"
+
+msgid "Click tag to add it to the project."
+msgstr "Нажмите на метку, чтобы добавить её в проект."
+
+msgid "Create New Tag"
+msgstr "Создать новую метку"
+
+msgid "Tags are capitalized automatically when displayed."
+msgstr "Метки автоматически пишутся с заглавной буквы при отображении."
+
msgid "Add Project Setting"
msgstr "Добавить настройку проекта"
@@ -11799,9 +12056,15 @@ msgstr "Добавить действие ввода"
msgid "Change Action deadzone"
msgstr "Изменить мёртвую зону действия"
+msgid "Change Input Action Event(s)"
+msgstr "Изменить событие(я) действия ввода"
+
msgid "Erase Input Action"
msgstr "Удалить действие ввода"
+msgid "Rename Input Action"
+msgstr "Переименовать действие ввода"
+
msgid "Update Input Action Order"
msgstr "Обновить порядок действий ввода"
@@ -11949,9 +12212,30 @@ msgstr "Сохранить глобальные преобразования"
msgid "Reparent"
msgstr "Переподчинить"
+msgid "Pick Root Node Type"
+msgstr "Выбрать тип корневого узла"
+
+msgid "Pick"
+msgstr "Выбрать"
+
+msgid "Scene name is valid."
+msgstr "Имя сцены допустимо."
+
+msgid "Scene name is empty."
+msgstr "Имя сцены пусто."
+
msgid "File name invalid."
msgstr "Недопустимое имя файла."
+msgid "File already exists."
+msgstr "Файл уже существует."
+
+msgid "Root node valid."
+msgstr "Корневой узел допустим."
+
+msgid "Invalid root node name."
+msgstr "Недопустимое имя корневого узла."
+
msgid "Root Type:"
msgstr "Тип корня:"
@@ -11973,6 +12257,15 @@ msgstr "Имя корня:"
msgid "Leave empty to use scene name"
msgstr "Оставьте пустым, чтобы использовать название сцены"
+msgid "Create New Scene"
+msgstr "Создать новую сцену"
+
+msgid "No parent to instantiate a child at."
+msgstr "Нет родителя для инстанцирования ребёнка."
+
+msgid "No parent to instantiate the scenes at."
+msgstr "Нет родителя для инстанцирования сцен сюда."
+
msgid "Error loading scene from %s"
msgstr "Ошибка при загрузке сцены из %s"
@@ -11983,9 +12276,15 @@ msgstr ""
"Невозможно создать экземпляр сцены '%s', потому что текущая сцена находится "
"в одном из её узлов."
+msgid "Instantiate Scene(s)"
+msgstr "Инстанцировать сцену(ы)"
+
msgid "Replace with Branch Scene"
msgstr "Заменить на сцену-ветку"
+msgid "Instantiate Child Scene"
+msgstr "Инстанцировать дочернюю сцену"
+
msgid "Detach Script"
msgstr "Открепить скрипт"
@@ -12030,6 +12329,9 @@ msgstr "Удалить узел \"%s\" и дочерние?"
msgid "Delete node \"%s\"?"
msgstr "Удалить узел \"%s\"?"
+msgid "Some nodes are referenced by animation tracks."
+msgstr "Дорожки анимации ссылаются на некоторые узлы."
+
msgid ""
"Saving the branch as a scene requires having a scene open in the editor."
msgstr ""
@@ -12057,6 +12359,16 @@ msgstr ""
"унаследованная сцена..."
msgid ""
+"Can't save the branch of an already instantiated scene.\n"
+"To create a variation of a scene, you can make an inherited scene based on "
+"the instantiated scene using Scene > New Inherited Scene... instead."
+msgstr ""
+"Невозможно сохранить ветку уже инстанцированной сцены.\n"
+"Чтобы создать вариацию сцены, вы можете создать унаследованную сцену на "
+"основе инстанцированной сцены, используя вместо этого Сцена > Новая "
+"унаследованная сцена..."
+
+msgid ""
"Can't save a branch which is a child of an already instantiated scene.\n"
"To save this branch into its own scene, open the original scene, right click "
"on this branch, and select \"Save Branch as Scene\"."
@@ -12113,18 +12425,32 @@ msgstr "Новый корень сцены"
msgid "Create Root Node:"
msgstr "Создать корневой узел:"
+msgid "Switch to Favorite Nodes"
+msgstr "Переключить на избранные узлы"
+
msgid "Other Node"
msgstr "Другой узел"
+msgid "Paste From Clipboard"
+msgstr "Вставить из буфера обмена"
+
msgid "Can't operate on nodes from a foreign scene!"
-msgstr "Не могу работать с узлами из внешней сцены!"
+msgstr "Невозможно выполнить операцию на узлах из внешней сцены!"
msgid "Can't operate on nodes the current scene inherits from!"
-msgstr "Невозможно работать с узлами, от которых унаследована текущая сцена!"
+msgstr ""
+"Невозможно выполнить операцию на узлах, от которых унаследована текущая "
+"сцена!"
+
+msgid "This operation can't be done on instantiated scenes."
+msgstr "Эта операция не может быть выполнена на инстанцированных сценах."
msgid "Attach Script"
msgstr "Прикрепить скрипт"
+msgid "Set Shader"
+msgstr "Задать шейдер"
+
msgid "Cut Node(s)"
msgstr "Вырезать узел(узлы)"
@@ -12150,9 +12476,18 @@ msgstr "Ошибка сохранения сцены."
msgid "Error duplicating scene to save it."
msgstr "Ошибка дублирования сцены, при её сохранении."
+msgid "Instantiate Script"
+msgstr "Инстанцировать скрипт"
+
msgid "Sub-Resources"
msgstr "Вложенные ресурсы"
+msgid "Revoke Unique Name"
+msgstr "Убрать уникальное имя"
+
+msgid "Access as Unique Name"
+msgstr "Доступ по уникальному имени"
+
msgid "Clear Inheritance"
msgstr "Очистить наследование"
@@ -12162,15 +12497,27 @@ msgstr "Редактируемые потомки"
msgid "Load As Placeholder"
msgstr "Загрузить как заполнитель"
+msgid "All Scene Sub-Resources"
+msgstr "Все вложенные ресурсы сцены"
+
msgid "Filters"
msgstr "Фильтры"
+msgid "Filter by Type"
+msgstr "Фильтр по типу"
+
+msgid "Filter by Group"
+msgstr "Фильтр по группе"
+
+msgid "Selects all Nodes of the given type."
+msgstr "Выбирает все узлы данного типа."
+
msgid ""
"Selects all Nodes belonging to the given group.\n"
"If empty, selects any Node belonging to any group."
msgstr ""
-"Выбирает все узлы, принадлежащие к данной группе.\n"
-"Если пусто, выбирается любой узел, принадлежащий к любой группе."
+"Выбирает все узлы, принадлежащие данной группе.\n"
+"Если пусто, выбирает любой узел, принадлежащий любой группе."
msgid ""
"Cannot attach a script: there are no languages registered.\n"
@@ -12187,9 +12534,18 @@ msgstr "Невозможно вставить корневой узел в ту
msgid "Paste Node(s)"
msgstr "Вставить узел(узлы)"
+msgid "<Unnamed> at %s"
+msgstr "<Безымянный> в %s"
+
+msgid "(used %d times)"
+msgstr "(использовано %d раз)"
+
msgid "Add Child Node"
msgstr "Добавить дочерний узел"
+msgid "Expand/Collapse Branch"
+msgstr "Развернуть/свернуть ветку"
+
msgid "Change Type"
msgstr "Изменить тип"
@@ -12199,6 +12555,9 @@ msgstr "Переподчинить на новый узел"
msgid "Make Scene Root"
msgstr "Создать корневой узел сцены"
+msgid "Toggle Access as Unique Name"
+msgstr "Переключить доступ по уникальному имени"
+
msgid "Delete (No Confirm)"
msgstr "Удалить (без подтверждения)"
@@ -12211,6 +12570,9 @@ msgstr "Прикрепить новый или существующий скри
msgid "Detach the script from the selected node."
msgstr "Убрать скрипт у выбранного узла."
+msgid "Extra scene options."
+msgstr "Дополнительные параметры сцены."
+
msgid "Remote"
msgstr "Удалённый"
@@ -12233,9 +12595,15 @@ msgstr "Не указан путь."
msgid "Filename is empty."
msgstr "Пустое имя файла."
+msgid "Filename is invalid."
+msgstr "Недопустимое имя файла."
+
msgid "Path is not local."
msgstr "Путь не локальный."
+msgid "Base path is invalid."
+msgstr "Недопустимый базовый путь."
+
msgid "A directory with the same name exists."
msgstr "Каталог с таким же именем существует."
@@ -12296,12 +12664,21 @@ msgstr "Встроенный скрипт (в файл сцены)."
msgid "Will create a new script file."
msgstr "Будет создан новый файл скрипта."
+msgid "Using existing script file."
+msgstr "Будет использован существующий файл скрипта."
+
msgid "Will load an existing script file."
msgstr "Будет загружен существующий скрипт."
msgid "Script file already exists."
msgstr "Файл скрипта уже существует."
+msgid "No suitable template."
+msgstr "Нет подходящего шаблона."
+
+msgid "Empty"
+msgstr "Пусто"
+
msgid ""
"Note: Built-in scripts have some limitations and can't be edited using an "
"external editor."
@@ -12325,12 +12702,40 @@ msgstr "Встроенный скрипт:"
msgid "Attach Node Script"
msgstr "Прикрепить скрипт"
+msgid "Error - Could not create shader include in filesystem."
+msgstr ""
+"Ошибка - Не удалось создать включаемый файл шейдера в файловой системе."
+
+msgid "Error - Could not create shader in filesystem."
+msgstr "Ошибка - Не удалось создать шейдер в файловой системе."
+
+msgid "Error loading shader from %s"
+msgstr "Ошибка загрузки шейдера из %s"
+
+msgid "Open Shader / Choose Location"
+msgstr "Открыть шейдер / Выбрать расположение"
+
msgid "Invalid base path."
msgstr "Недопустимый базовый путь."
msgid "Wrong extension chosen."
msgstr "Выбрано неверное расширение."
+msgid "Shader path/name is valid."
+msgstr "Путь/имя шейдера допустимы."
+
+msgid "Built-in shader (into scene file)."
+msgstr "Встроенный шейдер (в файл сцены)."
+
+msgid "Will create a new shader file."
+msgstr "Будет создан новый файл шейдера."
+
+msgid "Will load an existing shader file."
+msgstr "Будет загружен существующий файл шейдера."
+
+msgid "Shader file already exists."
+msgstr "Файл шейдера уже существует."
+
msgid "Note: Built-in shaders can't be edited using an external editor."
msgstr ""
"Примечание: Встроенные шейдеры нельзя редактировать с помощью внешнего "
@@ -12339,6 +12744,15 @@ msgstr ""
msgid "Mode:"
msgstr "Режим:"
+msgid "Built-in Shader:"
+msgstr "Встроенный шейдер:"
+
+msgid "Create Shader"
+msgstr "Создать шейдер"
+
+msgid "Set Shader Global Variable"
+msgstr "Задать глобальную переменную шейдера"
+
msgid "Please specify a valid shader uniform identifier name."
msgstr "Укажите допустимое имя универсального идентификатора шейдера."
@@ -12348,6 +12762,16 @@ msgstr "Глобальный параметр шейдера '%s' уже сущ
msgid "Name '%s' is a reserved shader language keyword."
msgstr "Имя '%s' является зарезервированным словом языка шейдера."
+msgid "Add Shader Global Parameter"
+msgstr "Добавить глобальный параметр шейдера"
+
+msgid ""
+"Make this panel floating.\n"
+"Right click to open the screen selector."
+msgstr ""
+"Сделайте эту панель плавающей.\n"
+"Нажмите ПКМ чтобы открыть выбор экрана."
+
msgid "Change Cylinder Radius"
msgstr "Изменить радиус цилиндра"
@@ -12640,6 +13064,9 @@ msgstr "MultiplayerSynchronizer(у) нужен корневой путь."
msgid "Delete Property?"
msgstr "Удалить свойство?"
+msgid "Property of this type not supported."
+msgstr "Свойство данного типа не поддерживается."
+
msgid ""
"A valid NodePath must be set in the \"Spawn Path\" property in order for "
"MultiplayerSpawner to be able to spawn Nodes."
@@ -12683,6 +13110,9 @@ msgstr ""
"Задаёт, будет ли предварительный просмотр шума вычисляться в трехмерном "
"пространстве."
+msgid "Rename Actions Localized name"
+msgstr "Переименовать Действия Локализованного имени"
+
msgid "Add action set"
msgstr "Добавить набор действий"
@@ -12704,6 +13134,9 @@ msgstr "Сброс карты действий OpenXR по умолчанию."
msgid "Action Sets"
msgstr "Набор действий"
+msgid "Rename Action Sets Localized name"
+msgstr "Переименование Действия Изменяет Локализированное имя"
+
msgid "Remove action from interaction profile"
msgstr "Удалить действие из профиля взаимодействий"
@@ -12824,6 +13257,13 @@ msgid "Could not execute on device."
msgstr "Не удалось выполнить на устройстве."
msgid ""
+"Exporting to Android is currently not supported in Godot 4 when using C#/."
+"NET. Use Godot 3 to target Android with C#/Mono instead."
+msgstr ""
+"Экспорт в Android пока не доступен в Godot 4 при использовании C#/.NET. "
+"Используйте Godot 3 для экспорта на Android при C#/Mono."
+
+msgid ""
"Android build template not installed in the project. Install it from the "
"Project menu."
msgstr ""
@@ -13059,6 +13499,13 @@ msgstr ""
"Пакет .ipa может быть собран только на macOS. Выход из проекта Xcode без "
"сборки пакета."
+msgid ""
+"Exporting to iOS is currently not supported in Godot 4 when using C#/.NET. "
+"Use Godot 3 to target iOS with C#/Mono instead."
+msgstr ""
+"Экспорт на iOS пока не доступен в Godot 4 при использовании C#/.NET. "
+"Используйте Godot 3 для экспорта на iOS. при C#/Mono."
+
msgid "Identifier is missing."
msgstr "Отсутствует определитель."
@@ -13153,6 +13600,15 @@ msgstr "Неизвестный тип объекта."
msgid "Invalid bundle identifier:"
msgstr "Неверный идентификатор пакета:"
+msgid "Apple Team ID is required for App Store distribution."
+msgstr "Требуется Apple Team ID для распространения в App Store."
+
+msgid "Provisioning profile is required for App Store distribution."
+msgstr "Требуется профиль обеспечения для распространения в App Store."
+
+msgid "App sandbox is required for App Store distribution."
+msgstr "Требуется приложение-песочница для распространения в App Store."
+
msgid ""
"Neither Apple ID name nor App Store Connect issuer ID name not specified."
msgstr ""
@@ -13412,6 +13868,13 @@ msgstr "Не удалось прочитать файл: \"%s\"."
msgid "PWA"
msgstr "Прогрессивное веб-приложение"
+msgid ""
+"Exporting to Web is currently not supported in Godot 4 when using C#/.NET. "
+"Use Godot 3 to target Web with C#/Mono instead."
+msgstr ""
+"Экспорт в Web пока не доступен в Godot 4 при использовании C#/.NET. "
+"Используйте Godot 3 для экспорта Web с C#/Mono."
+
msgid "Could not read HTML shell: \"%s\"."
msgstr "Не удалось прочитать HTML-оболочку: \"%s\"."
@@ -13439,6 +13902,15 @@ msgstr "Размер иконки \"%d\" отсутствует."
msgid "Failed to rename temporary file \"%s\"."
msgstr "Невозможно удалить временный файл \"%s\"."
+msgid "Invalid icon path."
+msgstr "Недопустимый путь к иконке."
+
+msgid "Invalid file version."
+msgstr "Недопустимая версия файла."
+
+msgid "Invalid product version."
+msgstr "Недопустимая версия продукта."
+
msgid "Could not find rcedit executable at \"%s\"."
msgstr "Не удалось найти исполняемый файл rcedit по адресу \"%s\"."
@@ -13729,6 +14201,16 @@ msgstr ""
"кость, чтобы прикрепить этот узел."
msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape3D or CollisionPolygon3D as a child to "
+"define its shape."
+msgstr ""
+"Этот узел не имеет форму, поэтому не может сталкиваться или "
+"взаимодействовать с другими объектами.\n"
+"Подумайте о добавлении CollisionShape3D или CollisionPolygon3D как ребёнка, "
+"чтобы определить его форму."
+
+msgid ""
"With a non-uniform scale this node will probably not function as expected.\n"
"Please make its scale uniform (i.e. the same on all axes), and change the "
"size in children collision shapes instead."
@@ -13749,6 +14231,9 @@ msgstr ""
"Пожалуйста используйте его только в качестве дочернего для Area3D, "
"StaticBody3D, RigidBody3D, CharacterBody3D и др. чтобы придать им форму."
+msgid "An empty CollisionPolygon3D has no effect on collision."
+msgstr "Пустой CollisionPolygon3D не влияет на столкновения."
+
msgid ""
"A non-uniformly scaled CollisionPolygon3D node will probably not function as "
"expected.\n"
@@ -13772,6 +14257,24 @@ msgstr ""
"StaticBody3D, RigidBody3D, CharacterBody3D и др. чтобы придать им форму."
msgid ""
+"A shape must be provided for CollisionShape3D to function. Please create a "
+"shape resource for it."
+msgstr ""
+"Shape должен быть предоставлен для CollisionShape3D. Пожалуйста, создайте "
+"ресурс Shape для него."
+
+msgid ""
+"ConcavePolygonShape3D doesn't support RigidBody3D in another mode than "
+"static."
+msgstr ""
+"ConcavePolygonShape3D поддерживает RigidBody3D только в статическом режиме."
+
+msgid ""
+"WorldBoundaryShape3D doesn't support RigidBody3D in another mode than static."
+msgstr ""
+"WorldBoundaryShape3D поддерживает RigidBody3D только в статическом режиме."
+
+msgid ""
"A non-uniformly scaled CollisionShape3D node will probably not function as "
"expected.\n"
"Please make its scale uniform (i.e. the same on all axes), and change the "
@@ -13819,6 +14322,23 @@ msgstr ""
"параметра Albedo Mix значение 0."
msgid ""
+"The decal's Cull Mask has no bits enabled, which means the decal will not "
+"paint objects on any layer.\n"
+"To resolve this, enable at least one bit in the Cull Mask property."
+msgstr ""
+"Маска выбраковки декаля не имеет битов. что значит декаль не нарисует "
+"объекты на любом слое.\n"
+"Для решения проблемы включите хотя бы один бит в свойстве Маски выбраковки."
+
+msgid "Fog Volumes are only visible when using the Forward+ backend."
+msgstr "Шумы Тумана только видимы при использовании бэкенда Forward+."
+
+msgid ""
+"Fog Volumes need volumetric fog to be enabled in the scene's Environment in "
+"order to be visible."
+msgstr "Чтобы Шумы Тумана были видны, включите объемный туман в сцене среды."
+
+msgid ""
"Nothing is visible because meshes have not been assigned to draw passes."
msgstr ""
"Ничего не видно, потому что меши не были назначены на проходы отрисовки."
diff --git a/editor/translations/editor/tr.po b/editor/translations/editor/tr.po
index 050efd857e..1fd8ef6289 100644
--- a/editor/translations/editor/tr.po
+++ b/editor/translations/editor/tr.po
@@ -99,13 +99,14 @@
# Yılmaz Durmaz <yilmaz_durmaz@hotmail.com>, 2023.
# ErcanPasha <dayanomerercan@gmail.com>, 2023.
# Yoldaş Ulaş <yutalas@gmail.com>, 2023.
+# Mertcan YILDIRIM <mertcanyildirim463@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-23 12:52+0000\n"
-"Last-Translator: Black <ebubekir23atalay@gmail.com>\n"
+"PO-Revision-Date: 2023-07-05 13:48+0000\n"
+"Last-Translator: Yılmaz Durmaz <yilmaz_durmaz@hotmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot/tr/>\n"
"Language: tr\n"
@@ -113,7 +114,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Unset"
msgstr "Atamayı Kaldır"
@@ -271,6 +272,25 @@ msgstr "dokunuldu"
msgid "released"
msgstr "bırakıldı"
+msgid "Screen %s at (%s) with %s touch points"
+msgstr "Ekran %s (%s üzerinde, %s dokunma noktalı)"
+
+msgid ""
+"Screen dragged with %s touch points at position (%s) with velocity of (%s)"
+msgstr "Ekran sürüklendi ( %s dokunma noktası ile, %s konumuna, %s hızında)"
+
+msgid "Magnify Gesture at (%s) with factor %s"
+msgstr "Büyütme Hareketi (%s konumunda, %s oranında)"
+
+msgid "Pan Gesture at (%s) with delta (%s)"
+msgstr "Kaydırma Hareketi (%s konumunda, %s artışlı)"
+
+msgid "MIDI Input on Channel=%s Message=%s"
+msgstr "MIDI Girişi (Kanal=%s İleti=%s)"
+
+msgid "Input Event with Shortcut=%s"
+msgstr "Girdi Olayı (Kısayol=%s)"
+
msgid "Accept"
msgstr "Kabul Et"
@@ -343,12 +363,87 @@ msgstr "Girintile"
msgid "Dedent"
msgstr "Çıkıntıla"
+msgid "Backspace"
+msgstr "Gerisilme"
+
+msgid "Backspace Word"
+msgstr "Kelime Gersilme"
+
+msgid "Backspace all to Left"
+msgstr "Soldakilerin tümünü Gersilme"
+
msgid "Delete"
msgstr "Sil"
+msgid "Delete Word"
+msgstr "Kelime Silme"
+
+msgid "Delete all to Right"
+msgstr "Sağdakilerin tümünü Silme"
+
+msgid "Caret Left"
+msgstr "İmleç Sola"
+
+msgid "Caret Word Left"
+msgstr "İmleç Kelimenin Soluna"
+
+msgid "Caret Right"
+msgstr "İmleç Sağa"
+
+msgid "Caret Word Right"
+msgstr "İmleç Kelimenin Sağına"
+
+msgid "Caret Up"
+msgstr "İmleç Yukarı"
+
+msgid "Caret Down"
+msgstr "İmleci Aşağı"
+
+msgid "Caret Line Start"
+msgstr "İmleç Satır Başına"
+
+msgid "Caret Line End"
+msgstr "İmleç Satır Sonuna"
+
+msgid "Caret Page Up"
+msgstr "İmleç Sayfa Yukarı"
+
+msgid "Caret Page Down"
+msgstr "İmleç Sayfa Aşağı"
+
+msgid "Caret Document Start"
+msgstr "İmleç Belge Başlangıcına"
+
+msgid "Caret Document End"
+msgstr "İmleç Belge Sonuna"
+
+msgid "Caret Add Below"
+msgstr "Alta İmleç Ekle"
+
+msgid "Caret Add Above"
+msgstr "Üste İmleç Ekle"
+
+msgid "Scroll Up"
+msgstr "Yukarı Kaydır"
+
+msgid "Scroll Down"
+msgstr "Aşağı Kaydır"
+
msgid "Select All"
msgstr "Hepsini Seç"
+msgid "Select Word Under Caret"
+msgstr "İmlecin Durduğu Kelimeyi Seç"
+
+msgid "Clear Carets and Selection"
+msgstr "İmleçleri ve Seçimi Temizle"
+
+msgid "Toggle Insert Mode"
+msgstr "Araekleme Şeklini Değiştir"
+
+msgid "Submit Text"
+msgstr "Metin Gönder"
+
msgid "Duplicate Nodes"
msgstr "Düğümleri Çokla"
@@ -379,6 +474,12 @@ msgstr "'%s' oluşturulurken geçersiz argümanlar atandı"
msgid "On call to '%s':"
msgstr "'%s' çağrıldığında:"
+msgid "Built-in script"
+msgstr "Yerleşik Betik"
+
+msgid "Built-in"
+msgstr "Yerleşik"
+
msgid "B"
msgstr "B"
@@ -412,6 +513,9 @@ msgstr "İşlem '%s' zaten var."
msgid "Add Event"
msgstr "Olay Ekle"
+msgid "Cannot Remove Action"
+msgstr "Eylem Kaldırılamıyor"
+
msgid "Add"
msgstr "Ekle"
@@ -445,6 +549,9 @@ msgstr "Bezier Noktalarını Taşı"
msgid "Focus"
msgstr "Odak"
+msgid "Animation Change %s"
+msgstr "Animasyon Değişimi %s"
+
msgid "Change Animation Length"
msgstr "Animasyon Uzunluğunu Değiştir"
@@ -769,6 +876,9 @@ msgstr "Temizlik"
msgid "Scale Ratio:"
msgstr "Ölçek Oranı:"
+msgid "Value Track:"
+msgstr "Değer Takibi:"
+
msgid "Select Tracks to Copy"
msgstr "Kopyalanacak izleri seç"
@@ -876,6 +986,9 @@ msgstr "Ekstra Çağrı Argümanı Ekle:"
msgid "Extra Call Arguments:"
msgstr "Ekstra Çağrı Argümanları:"
+msgid "Unbind Signal Arguments:"
+msgstr "Sinyal Argümanlarını Çöz:"
+
msgid "Receiver Method:"
msgstr "Alıcı Metodu:"
@@ -1058,6 +1171,9 @@ msgstr "Zaman"
msgid "Calls"
msgstr "Çağrılar"
+msgid "Linked"
+msgstr "Bağlantılı"
+
msgid "Bytes:"
msgstr "Baytlar:"
@@ -1070,9 +1186,15 @@ msgstr "Hata:"
msgid "%s Error"
msgstr "%s Hatası"
+msgid "%s Error:"
+msgstr "%s Hatası:"
+
msgid "Stack Trace"
msgstr "Bellek Dökümü"
+msgid "Stack Trace:"
+msgstr "Yığın İzleme:"
+
msgid "Copy Error"
msgstr "Hatayı Kopyala"
@@ -1113,7 +1235,7 @@ msgid "Collapse All"
msgstr "Hepsini Daralt"
msgid "Profiler"
-msgstr "Profil Oluşturucu"
+msgstr "Profil Çıkarıcı"
msgid "List of Video Memory Usage by Resource:"
msgstr "Kaynağa Göre İzleti Belleği Kullanımının Dizelgesi:"
@@ -1267,6 +1389,9 @@ msgstr "Belirgin Sahipliği Olmayan Kaynaklar:"
msgid "Could not create folder."
msgstr "Klasör oluşturulamadı."
+msgid "Create new folder in %s:"
+msgstr "Şurada yeni klasör oluştur: %s"
+
msgid "Create Folder"
msgstr "Klasör Oluştur"
@@ -1586,6 +1711,9 @@ msgstr "Yeni"
msgid "Save"
msgstr "Kaydet"
+msgid "Profile:"
+msgstr "Profil:"
+
msgid "Reset to Defaults"
msgstr "Varsayılanlara dön"
@@ -1770,6 +1898,9 @@ msgstr ""
msgid "(Re)Importing Assets"
msgstr "Varlıklar Yeniden-İçe Aktarılıyor"
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr "Bu değer, şu bayrakların bitmaskesi olarak birleştiği bir tam sayıdır."
+
msgid "Experimental"
msgstr "Deneysel"
@@ -3275,6 +3406,12 @@ msgstr ""
msgid "A file or folder with this name already exists."
msgstr "Bu isimde zaten bir dosya ve ya klasör mevcut."
+msgid ""
+"The following files or folders conflict with items in the target location "
+"'%s':"
+msgstr ""
+"Aşağıdaki dosyalar veya klasörler '%s' hedef konumundaki ögelerle çakışıyor:"
+
msgid "Duplicating file:"
msgstr "Dosya çoğaltılıyor:"
@@ -3578,6 +3715,16 @@ msgstr "(Gelen Bağlantı)"
msgid "Node configuration warning:"
msgstr "Düğüm yapılandırma uyarısı:"
+msgid "Node has one connection."
+msgid_plural "Node has {num} connections."
+msgstr[0] "Düğümün bir bağlantısı var."
+msgstr[1] "Düğümün {num} bağlantısı var."
+
+msgid "Node is in this group:"
+msgid_plural "Node is in the following groups:"
+msgstr[0] "Düğüm bu grupta:"
+msgstr[1] "Düğüm bu gruplarda:"
+
msgid "Open in Editor"
msgstr "Düzenleyicide Aç"
@@ -4950,6 +5097,11 @@ msgstr ""
"Bir cihazda uzaktan kullanıldığında, bu, ağ dosya sistemi seçeneği "
"etkinleştirildiğinde daha etkilidir."
+msgid "Run %d Instance"
+msgid_plural "Run %d Instances"
+msgstr[0] "%d Örnekleme çalıştır"
+msgstr[1] "%d Örnekleme çalıştır"
+
msgid "No supported features"
msgstr "Desteklenen özellik yok"
@@ -6225,6 +6377,9 @@ msgstr "Sonraki Kesme Noktasına Git"
msgid "Go to Previous Breakpoint"
msgstr "Önceki Kesme Noktasına Git"
+msgid "ShaderFile"
+msgstr "GölgelendirmeDosyası"
+
msgid "This skeleton has no bones, create some children Bone2D nodes."
msgstr "Bu iskelette hiç kemik yok, alt öge olarak Kemik2D düğümleri oluştur."
@@ -6389,7 +6544,7 @@ msgid "Separation:"
msgstr "Ayrım:"
msgid "Styleboxes"
-msgstr "StilKutusu"
+msgstr "Tarzkutuları"
msgid "1 color"
msgid_plural "{num} colors"
@@ -6418,8 +6573,18 @@ msgstr[1] "{num} yazı boyutu"
msgid "No icons found."
msgstr "Simge bulunamadı."
+msgid "1 stylebox"
+msgid_plural "{num} styleboxes"
+msgstr[0] "1 tarzkutusu"
+msgstr[1] "{num} tarzkutusu"
+
msgid "No styleboxes found."
-msgstr "Stil kutusu bulunamadı."
+msgstr "Hiç tarzkutusu bulunamadı."
+
+msgid "{num} currently selected"
+msgid_plural "{num} currently selected"
+msgstr[0] "{num} şuan seçili"
+msgstr[1] "{num} şuan seçili"
msgid "Nothing was selected for the import."
msgstr "İçe aktarma için hiçbir şey seçilmedi."
@@ -6479,13 +6644,13 @@ msgid "Deselect all visible icon items."
msgstr "Tüm görünür simge öğelerinin seçimini kaldırın."
msgid "Select all visible stylebox items."
-msgstr "Tüm görünür stil kutusu öğelerini seçin."
+msgstr "Tüm görünür tarzkutusu öğelerini seç."
msgid "Select all visible stylebox items and their data."
-msgstr "Tüm görünür stil kutusu öğelerini ve verilerini seçin."
+msgstr "Tüm görünür tarzkutusu öğelerini ve bunların verilerini seç."
msgid "Deselect all visible stylebox items."
-msgstr "Tüm görünür stil kutusu öğelerinin seçimini kaldırın."
+msgstr "Tüm görünür tarzkutusu öğelerinin seçimini kaldır."
msgid ""
"Caution: Adding icon data may considerably increase the size of your Theme "
@@ -6551,7 +6716,7 @@ msgid "Remove All Icon Items"
msgstr "Tüm Simge Öğelerini Kaldır"
msgid "Remove All StyleBox Items"
-msgstr "Tüm Stil Kutusu Öğelerini Kaldır"
+msgstr "Tüm TarzKutusu Öğelerini Kaldır"
msgid ""
"This theme type is empty.\n"
@@ -6573,7 +6738,7 @@ msgid "Add Icon Item"
msgstr "Simge Öğesi Ekle"
msgid "Add Stylebox Item"
-msgstr "Stil Kutusu Öğesi Ekle"
+msgstr "Tarzkutusu Öğesi Ekle"
msgid "Rename Color Item"
msgstr "Renk Öğesini Yeniden Adlandır"
@@ -6588,7 +6753,7 @@ msgid "Rename Icon Item"
msgstr "Simge Öğesini Yeniden Adlandır"
msgid "Rename Stylebox Item"
-msgstr "Stil Kutusu Öğesini Yeniden Adlandır"
+msgstr "Tarzkutusu Öğesini Yeniden Adlandır"
msgid "Invalid file, not a Theme resource."
msgstr "Geçersiz dosya, Tema kaynağı değil."
@@ -6612,7 +6777,7 @@ msgid "Add Item:"
msgstr "Öğe Ekle:"
msgid "Add StyleBox Item"
-msgstr "Stil Kutusu Öğesi Ekle"
+msgstr "TarzKutusu Öğesi Ekle"
msgid "Remove Items:"
msgstr "Öğeleri kaldır:"
@@ -6669,14 +6834,14 @@ msgid "Override Item"
msgstr "Öğeyi Geçersiz Kıl"
msgid "Unpin this StyleBox as a main style."
-msgstr "Bu Stil Kutusunun ana stil olarak sabitlemesini kaldırın."
+msgstr "Bu TarzKutusu'nun ana tarz sabitlemesini kaldır."
msgid ""
"Pin this StyleBox as a main style. Editing its properties will update the "
"same properties in all other StyleBoxes of this type."
msgstr ""
-"Bu Stil Kutusunu ana stil olarak sabitleyin. Özelliklerini düzenlemek, bu "
-"tipteki diğer tüm StyleBox'larda aynı özellikleri güncelleyecektir."
+"Bu TarzKutusunu ana tarz olarak sabitle. Bunun özelliklerini düzenlemek, bu "
+"tipteki diğer tüm TarzKutularının aynı özelliklerini güncelleyecektir."
msgid "Add Item Type"
msgstr "Öğe Türü Ekle"
@@ -6684,6 +6849,15 @@ msgstr "Öğe Türü Ekle"
msgid "Add Type"
msgstr "Tür Ekle"
+msgid "Set Stylebox Item in Theme"
+msgstr "TarzKutusu Öğesini Temaya Ayarla"
+
+msgid "Pin Stylebox"
+msgstr "TarzKutusunu Sabitle"
+
+msgid "Unpin Stylebox"
+msgstr "TarzKutusunun Sabitlemesini Kaldır"
+
msgid "Show Default"
msgstr "Varsayılanı Göster"
@@ -8553,6 +8727,9 @@ msgstr "Tanımlayıcı eksik."
msgid "The character '%s' is not allowed in Identifier."
msgstr "Tanımlayıcı'da '%s' karakterine izin verilmiyor."
+msgid "Starting project..."
+msgstr "Proje Başlatılıyor..."
+
msgid "Can't get filesystem access."
msgstr "Dosya sistemi erişimi alınamıyor."
@@ -8926,3 +9103,6 @@ msgstr "uniform için atama."
msgid "Constants cannot be modified."
msgstr "Sabit değerler değiştirilemez."
+
+msgid "Shader include file does not exist:"
+msgstr "Gölgelendirici içerme dosyası mevcut değil:"
diff --git a/editor/translations/editor/uk.po b/editor/translations/editor/uk.po
index 6e3815ac98..6d29ebb2c8 100644
--- a/editor/translations/editor/uk.po
+++ b/editor/translations/editor/uk.po
@@ -31,13 +31,14 @@
# Dmytro Kyrychuk <dmytro@kyrych.uk>, 2023.
# Maksym <maksym@mowemax.com>, 2023.
# Lost Net <pc.mirkn@gmail.com>, 2023.
+# Dan <jonweblin2205@protonmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-05-21 11:48+0000\n"
-"Last-Translator: Lost Net <pc.mirkn@gmail.com>\n"
+"PO-Revision-Date: 2023-06-30 21:27+0000\n"
+"Last-Translator: Dan <jonweblin2205@protonmail.com>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot/uk/>\n"
"Language: uk\n"
@@ -46,7 +47,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.18-dev\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Unset"
msgstr "Зняти"
@@ -14125,7 +14126,7 @@ msgid ""
"> rcedit) to change the icon or app information data."
msgstr ""
"Інструмент rcedit має бути налаштований у Параметрах редактора (Експорт > "
-"Windows > rcedit), щоб змінювати піктограму або інформаційні дані додатка."
+"Windows > rcedit), щоб змінювати піктограму або інформаційні дані застосунку."
msgid "Windows executables cannot be >= 4 GiB."
msgstr "Виконувані файли Windows не можуть мати розмір >= 4 Гб."
diff --git a/editor/translations/editor/zh_CN.po b/editor/translations/editor/zh_CN.po
index ce638cdfb6..4b02a497fc 100644
--- a/editor/translations/editor/zh_CN.po
+++ b/editor/translations/editor/zh_CN.po
@@ -96,7 +96,7 @@ msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2023-06-14 03:00+0000\n"
+"PO-Revision-Date: 2023-06-29 16:02+0000\n"
"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hans/>\n"
@@ -105,7 +105,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.18-dev\n"
+"X-Generator: Weblate 4.18.1\n"
msgid "Unset"
msgstr "未设置"
@@ -2511,6 +2511,9 @@ msgstr "导入 %s 类型的资源"
msgid "No return value."
msgstr "无返回值。"
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr "这个值是由下列标志构成的位掩码整数。"
+
msgid "Deprecated"
msgstr "已废弃"
@@ -3991,6 +3994,12 @@ msgstr "控制杆 4 向上"
msgid "Joystick 4 Down"
msgstr "控制杆 4 向下"
+msgid "or"
+msgstr "或"
+
+msgid "Unicode"
+msgstr "Unicode"
+
msgid "Joypad Axis %d %s (%s)"
msgstr "游戏手柄轴 %d %s (%s)"
@@ -7951,6 +7960,9 @@ msgstr "大小:%s(%.1fMP)\n"
msgid "Objects: %d\n"
msgstr "对象数:%d\n"
+msgid "Primitives: %d\n"
+msgstr "图元:%d\n"
+
msgid "Draw Calls: %d"
msgstr "绘制调用:%d"
@@ -10239,6 +10251,12 @@ msgstr "散布:"
msgid "Tiles"
msgstr "图块"
+msgid ""
+"This TileMap's TileSet has no source configured. Go to the TileSet bottom "
+"tab to add one."
+msgstr ""
+"这个 TileMap 的 TileSet 中没有配置任何源。请在 TileSet 底部面板中进行添加。"
+
msgid "Sort sources"
msgstr "源排序"
@@ -10309,6 +10327,13 @@ msgstr "切换栅格可见性。"
msgid "Automatically Replace Tiles with Proxies"
msgstr "自动将图块替换为代理"
+msgid ""
+"The edited TileMap node has no TileSet resource.\n"
+"Create or load a TileSet resource in the Tile Set property in the inspector."
+msgstr ""
+"正在编辑的 TileMap 节点没有 TileSet 资源。\n"
+"请在检查器的 Tile Set 属性中创建或加载 TileSet 资源。"
+
msgid "Remove Tile Proxies"
msgstr "移除图块代理"
@@ -10524,6 +10549,15 @@ msgstr "打开图集合并工具"
msgid "Manage Tile Proxies"
msgstr "管理图块代理"
+msgid ""
+"No TileSet source selected. Select or create a TileSet source.\n"
+"You can create a new source by using the Add button on the left or by "
+"dropping a tileset texture onto the source list."
+msgstr ""
+"尚未选择 TileSet 源。请选择或创建 TileSet 源。\n"
+"源的新建方法有两种,可以使用左侧的“添加”按钮,也可以将图块集纹理拖放到源列表"
+"中。"
+
msgid "Add new patterns in the TileMap editing mode."
msgstr "请在 TileMap 编辑模式中添加新的图案。"
@@ -12524,6 +12558,9 @@ msgstr "文件名无效。"
msgid "File already exists."
msgstr "文件已经存在。"
+msgid "Root node valid."
+msgstr "根节点有效。"
+
msgid "Invalid root node name."
msgstr "根节点名称无效。"
@@ -13656,6 +13693,18 @@ msgid "Could not execute on device."
msgstr "无法在设备上运行。"
msgid ""
+"Exporting to Android is currently not supported in Godot 4 when using C#/."
+"NET. Use Godot 3 to target Android with C#/Mono instead."
+msgstr ""
+"Godot 4 中目前尚不支持使用 C#/.NET 导出到 Android。要在 Android 目标上使用 "
+"C#/Mono,请改用 Godot 3。"
+
+msgid ""
+"If this project does not use C#, use a non-C# editor build to export the "
+"project."
+msgstr "如果这个项目不使用 C#,请使用非 C# 版本的编辑器来导出项目。"
+
+msgid ""
"Android build template not installed in the project. Install it from the "
"Project menu."
msgstr "未在项目中安装 Android 构建模板。从项目菜单安装它。"
@@ -13876,6 +13925,13 @@ msgid ""
"package."
msgstr ".ipa 只能在 macOS 上构建。正在离开 Xcode 项目,未构建包。"
+msgid ""
+"Exporting to iOS is currently not supported in Godot 4 when using C#/.NET. "
+"Use Godot 3 to target iOS with C#/Mono instead."
+msgstr ""
+"Godot 4 中目前尚不支持使用 C#/.NET 导出到 iOS。要在 iOS 目标上使用 C#/Mono,"
+"请改用 Godot 3。"
+
msgid "Identifier is missing."
msgstr "缺少标识符。"
@@ -13888,6 +13944,12 @@ msgstr "调试脚本导出"
msgid "Could not open file \"%s\"."
msgstr "无法打开文件“%s”。"
+msgid "Debug Console Export"
+msgstr "调试控制台导出"
+
+msgid "Could not create console wrapper."
+msgstr "无法创建控制台封装。"
+
msgid "Failed to open executable file \"%s\"."
msgstr "打开可执行文件“%s”失败。"
@@ -14322,6 +14384,13 @@ msgstr "无法读取文件:“%s”。"
msgid "PWA"
msgstr "PWA"
+msgid ""
+"Exporting to Web is currently not supported in Godot 4 when using C#/.NET. "
+"Use Godot 3 to target Web with C#/Mono instead."
+msgstr ""
+"Godot 4 中目前尚不支持使用 C#/.NET 导出到 Web。要在 Web 目标上使用 C#/Mono,"
+"请改用 Godot 3。"
+
msgid "Could not read HTML shell: \"%s\"."
msgstr "无法读取 HTML 壳:“%s”。"
@@ -14520,6 +14589,11 @@ msgid ""
"rendering backends."
msgstr "粒子尾迹仅在使用 Forward+ 或 Mobile 渲染后端时可用。"
+msgid ""
+"Particle sub-emitters are not available when using the GL Compatibility "
+"rendering backend."
+msgstr "粒子的子发射器在使用 GL 兼容渲染后端时不可用。"
+
msgid "Node A and Node B must be PhysicsBody2Ds"
msgstr "Node A 与 Node B 必须为 PhysicsBody2D"
@@ -14805,6 +14879,11 @@ msgid ""
msgstr "尾迹已启用,但至少有一个网格材质处于缺失状态,或未设置尾迹渲染。"
msgid ""
+"Particle sub-emitters are only available when using the Forward+ or Mobile "
+"rendering backends."
+msgstr "粒子的子发射器仅在使用 Forward+ 或 Mobile 渲染后端时可用。"
+
+msgid ""
"The Bake Mask has no bits enabled, which means baking will not produce any "
"collision for this GPUParticlesCollisionSDF3D.\n"
"To resolve this, enable at least one bit in the Bake Mask property."
@@ -15386,6 +15465,14 @@ msgid "Invalid BMFont block type."
msgstr "无效的 BMFont 块类型。"
msgid ""
+"An incoming node's name clashes with %s already in the scene (presumably, "
+"from a more nested instance).\n"
+"The less nested node will be renamed. Please fix and re-save the scene."
+msgstr ""
+"引入节点的名称与场景中已有的 %s 冲突(可能来自于嵌套的实例)。\n"
+"会对较外层的节点进行重命名。请修复并重新保存该场景。"
+
+msgid ""
"Shader keywords cannot be used as parameter names.\n"
"Choose another name."
msgstr ""
diff --git a/editor/translations/editor/zh_TW.po b/editor/translations/editor/zh_TW.po
index 49de884da4..b9cac0863a 100644
--- a/editor/translations/editor/zh_TW.po
+++ b/editor/translations/editor/zh_TW.po
@@ -18,7 +18,7 @@
# leela <53352@protonmail.com>, 2019.
# Kenneth Lo <closer.tw@gmail.com>, 2019.
# SIYU FU <1002492607@qq.com>, 2019.
-# 鄭惟中 <biglionlion06@gmail.com>, 2020.
+# 鄭惟中 <biglionlion06@gmail.com>, 2020, 2023.
# Alexander Wang <zxcvb22217@gmail.com>, 2020.
# binotaliu <binota@protonmail.ch>, 2020.
# Allen H. <w84miracle@gmail.com>, 2020.
@@ -47,8 +47,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-13 15:35+0000\n"
-"Last-Translator: adenpun <adenpun2000@gmail.com>\n"
+"PO-Revision-Date: 2023-07-01 13:08+0000\n"
+"Last-Translator: 鄭惟中 <biglionlion06@gmail.com>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hant/>\n"
"Language: zh_TW\n"
@@ -56,7 +56,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.18-dev\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Unset"
msgstr "未設定"
@@ -554,21 +554,72 @@ msgstr "新增貝茲曲線控制點"
msgid "Move Bezier Points"
msgstr "移動貝茲曲線控制點"
+msgid "Animation Duplicate Keys"
+msgstr "重複動畫關鍵畫格"
+
msgid "Animation Delete Keys"
msgstr "刪除動畫關鍵畫格"
+msgid "Focus"
+msgstr "焦點"
+
+msgid "Select All Keys"
+msgstr "選擇全部關鍵畫格"
+
+msgid "Deselect All Keys"
+msgstr "取消全選關鍵畫格"
+
+msgid "Animation Change Transition"
+msgstr "更改動畫轉場效果"
+
msgid "Animation Change %s"
msgstr "修改動畫 %s"
+msgid "Animation Change Keyframe Value"
+msgstr "更改動畫關鍵畫格數值"
+
+msgid "Animation Change Call"
+msgstr "更改動畫呼叫"
+
+msgid "Animation Multi Change Transition"
+msgstr "更改多個動畫的轉場效果"
+
+msgid "Animation Multi Change %s"
+msgstr "更改多個動畫的呼叫 %s"
+
+msgid "Animation Multi Change Keyframe Value"
+msgstr "更改多個動畫的關鍵畫格數值"
+
+msgid "Animation Multi Change Call"
+msgstr "更改多個動畫的呼叫"
+
msgid "Change Animation Length"
msgstr "更改動畫長度"
msgid "Change Animation Loop"
msgstr "更改動畫循環"
+msgid "Can't change loop mode on animation instanced from imported scene."
+msgstr "無法更改從導入場景instance的動畫的循環播放模式。"
+
+msgid "Can't change loop mode on animation embedded in another scene."
+msgstr "無法更改從其他場景嵌入的動畫的循環播放模式。"
+
msgid "Property Track"
msgstr "屬性軌道"
+msgid "3D Position Track"
+msgstr "3D座標軌道"
+
+msgid "3D Rotation Track"
+msgstr "3D旋轉軌道"
+
+msgid "3D Scale Track"
+msgstr "3D 尺寸軌道"
+
+msgid "Blend Shape Track"
+msgstr "Blend Shape軌道"
+
msgid "Call Method Track"
msgstr "呼叫方法軌道"
@@ -599,6 +650,9 @@ msgstr "函式:"
msgid "Audio Clips:"
msgstr "音訊片段:"
+msgid "Animation Clips:"
+msgstr "多個動畫片段:"
+
msgid "Change Track Path"
msgstr "調整軌道路徑"
@@ -632,6 +686,9 @@ msgstr "旋轉:"
msgid "Scale:"
msgstr "縮放:"
+msgid "Blend Shape:"
+msgstr "Blend Shape:"
+
msgid "Type:"
msgstr "型別:"
@@ -647,6 +704,18 @@ msgstr "進入控點:"
msgid "Out-Handle:"
msgstr "離開控點:"
+msgid "Handle mode: Free\n"
+msgstr "控制模式:自由\n"
+
+msgid "Handle mode: Linear\n"
+msgstr "控制模式:線性\n"
+
+msgid "Handle mode: Balanced\n"
+msgstr "控制模式:平衡\n"
+
+msgid "Handle mode: Mirrored\n"
+msgstr "控制模式:鏡像\n"
+
msgid "Stream:"
msgstr "流:"
@@ -662,6 +731,9 @@ msgstr "動畫片段:"
msgid "Toggle Track Enabled"
msgstr "啟用/禁用軌道"
+msgid "Don't Use Blend"
+msgstr "不要使用Blend"
+
msgid "Continuous"
msgstr "連續"
@@ -680,6 +752,12 @@ msgstr "線性"
msgid "Cubic"
msgstr "立方體"
+msgid "Linear Angle"
+msgstr "線性角度"
+
+msgid "Cubic Angle"
+msgstr "立方角度"
+
msgid "Clamp Loop Interp"
msgstr "鉗制內插循環 (Clamp)"
@@ -707,12 +785,29 @@ msgstr "更改動畫插值模式"
msgid "Change Animation Loop Mode"
msgstr "更改動畫循環模式"
+msgid "Change Animation Use Blend"
+msgstr "更改動畫使用混合"
+
+msgid ""
+"Compressed tracks can't be edited or removed. Re-import the animation with "
+"compression disabled in order to edit."
+msgstr "壓縮軌道沒有辦法被編輯或移除。重新加上不要壓縮的選項重新導入來編輯。"
+
msgid "Remove Anim Track"
msgstr "刪除動畫軌"
+msgid "Create new track for %s and insert key?"
+msgstr "確定要為 %s 建立動畫軌並插入關鍵畫格嗎?"
+
+msgid "Create %d new tracks and insert keys?"
+msgstr "確定要建立 %d 個動畫軌並插入畫格嗎?"
+
msgid "Create"
msgstr "建立"
+msgid "Animation Insert Key"
+msgstr "新增動畫關鍵畫格"
+
msgid "node '%s'"
msgstr "無法開啟 \"%s\""
@@ -731,6 +826,12 @@ msgstr "更改動畫步長"
msgid "Rearrange Tracks"
msgstr "重新排列軌道"
+msgid "Blend Shape tracks only apply to MeshInstance3D nodes."
+msgstr "Blend Shape軌僅可套用至 MeshInstance3D 節點。"
+
+msgid "Position/Rotation/Scale 3D tracks only apply to 3D-based nodes."
+msgstr "座標/旋轉/縮放軌僅可套用至3D節點。"
+
msgid ""
"Audio tracks can only point to nodes of type:\n"
"-AudioStreamPlayer\n"
@@ -757,6 +858,18 @@ msgstr "新增貝茲曲線軌"
msgid "Track path is invalid, so can't add a key."
msgstr "無效的軌道路徑,無法新增關鍵畫格。"
+msgid "Track is not of type Node3D, can't insert key"
+msgstr "非NODE3D類型之軌道,無法插入關鍵畫格"
+
+msgid "Add Position Key"
+msgstr "添加座標關鍵畫格"
+
+msgid "Add Rotation Key"
+msgstr "添加旋轉關鍵畫格"
+
+msgid "Add Scale Key"
+msgstr "添加縮放關鍵畫格"
+
msgid "Add Track Key"
msgstr "添加軌道關鍵畫格"
@@ -769,6 +882,9 @@ msgstr "新增方法軌道關鍵畫格"
msgid "Method not found in object:"
msgstr "在物件中找不到該方法:"
+msgid "Animation Move Keys"
+msgstr "動畫移動關鍵畫格"
+
msgid "Position"
msgstr "位置"
@@ -778,6 +894,9 @@ msgstr "旋轉"
msgid "Scale"
msgstr "縮放"
+msgid "BlendShape"
+msgstr "BlendShape(混合形狀)"
+
msgid "Methods"
msgstr "方法"
@@ -793,16 +912,51 @@ msgstr "剪貼簿為空!"
msgid "Paste Tracks"
msgstr "貼上關鍵畫格"
+msgid "Animation Scale Keys"
+msgstr "動畫縮放關鍵影格"
+
+msgid "Make Easing Keys"
+msgstr "產生中間(Easing)關鍵畫格"
+
msgid ""
"This option does not work for Bezier editing, as it's only a single track."
msgstr "該選項不適用貝茲曲線編輯,因曲線僅有單一軌道。"
+msgid "Animation Add RESET Keys"
+msgstr "新增動畫 RESET 關鍵畫格"
+
+msgid "Bake Animation as Linear keys."
+msgstr "烘焙動畫產生線性關鍵畫格。"
+
+msgid ""
+"This animation belongs to an imported scene, so changes to imported tracks "
+"will not be saved.\n"
+"\n"
+"To modify this animation, navigate to the scene's Advanced Import settings "
+"and select the animation.\n"
+"Some options, including looping, are available here. To add custom tracks, "
+"enable \"Save To File\" and\n"
+"\"Keep Custom Tracks\"."
+msgstr ""
+"該動畫屬於外部匯入之場景,套用於匯入軌道的修改將不會被儲存。\n"
+"\n"
+"若要修改此動畫,請在場景在進階匯入設定中選擇此動畫\n"
+"某些選項,例如循環模式,可以被使用。如果要加上自訂軌道,啟動「保存至檔案」然"
+"後\n"
+"「維持自訂軌道」。"
+
msgid "Warning: Editing imported animation"
msgstr "警告:正在編輯匯入的動畫"
msgid "Select an AnimationPlayer node to create and edit animations."
msgstr "選擇 AnimationPlayer 節點以建立並編輯動畫。"
+msgid "Imported Scene"
+msgstr "導入場景"
+
+msgid "Toggle between the bezier curve editor and track editor."
+msgstr "在貝茲曲線編輯器與軌道編輯器之間切換。"
+
msgid "Only show tracks from nodes selected in tree."
msgstr "僅顯示樹中所選節點的軌跡。"
@@ -836,6 +990,9 @@ msgstr "縮放所選"
msgid "Scale From Cursor"
msgstr "以游標縮放"
+msgid "Make Easing Selection"
+msgstr "清除Easing所選"
+
msgid "Duplicate Selection"
msgstr "重複所選"
@@ -854,12 +1011,36 @@ msgstr "跳至上一步"
msgid "Apply Reset"
msgstr "套用重設"
+msgid "Bake Animation"
+msgstr "烘焙動畫"
+
+msgid "Optimize Animation (no undo)"
+msgstr "最佳化動畫(不能反悔)"
+
+msgid "Clean-Up Animation (no undo)"
+msgstr "清除動畫(不能反悔)"
+
+msgid "Pick a node to animate:"
+msgstr "選擇欲設定動畫之節點:"
+
msgid "Use Bezier Curves"
msgstr "使用貝茲曲線"
msgid "Create RESET Track(s)"
msgstr "貼上關鍵畫格"
+msgid "Animation Optimizer"
+msgstr "最佳化動畫工具"
+
+msgid "Max Velocity Error:"
+msgstr "最大速度誤差:"
+
+msgid "Max Angular Error:"
+msgstr "最大角度誤差:"
+
+msgid "Max Precision Error:"
+msgstr "最大精準度誤差:"
+
msgid "Optimize"
msgstr "最佳化"
@@ -881,12 +1062,103 @@ msgstr "清除"
msgid "Scale Ratio:"
msgstr "縮放比例:"
+msgid "Select Transition and Easing"
+msgstr "選擇轉換與Easing"
+
+msgctxt "Transition Type"
+msgid "Linear"
+msgstr "線性的"
+
+msgctxt "Transition Type"
+msgid "Sine"
+msgstr "正弦"
+
+msgctxt "Transition Type"
+msgid "Quint"
+msgstr "五次方"
+
+msgctxt "Transition Type"
+msgid "Quart"
+msgstr "四次方"
+
+msgctxt "Transition Type"
+msgid "Quad"
+msgstr "平方"
+
+msgctxt "Transition Type"
+msgid "Expo"
+msgstr "指數"
+
+msgctxt "Transition Type"
+msgid "Elastic"
+msgstr "彈性"
+
+msgctxt "Transition Type"
+msgid "Cubic"
+msgstr "立方"
+
+msgctxt "Transition Type"
+msgid "Circ"
+msgstr "根號"
+
+msgctxt "Transition Type"
+msgid "Bounce"
+msgstr "反彈"
+
+msgctxt "Transition Type"
+msgid "Back"
+msgstr "倒轉"
+
+msgctxt "Transition Type"
+msgid "Spring"
+msgstr "彈簧"
+
+msgctxt "Ease Type"
+msgid "In"
+msgstr "進入"
+
+msgctxt "Ease Type"
+msgid "Out"
+msgstr "離開"
+
+msgctxt "Ease Type"
+msgid "InOut"
+msgstr "進入離開"
+
+msgctxt "Ease Type"
+msgid "OutIn"
+msgstr "離開進入"
+
+msgid "Transition Type:"
+msgstr "轉換效果:"
+
+msgid "Ease Type:"
+msgstr "Ease型別:"
+
+msgid "FPS:"
+msgstr "FPS:"
+
+msgid "Animation Baker"
+msgstr "動畫烘焙器:"
+
+msgid "3D Pos/Rot/Scl Track:"
+msgstr "3D位置/旋轉/縮放軌道:"
+
+msgid "Blendshape Track:"
+msgstr "Blendshape軌道:"
+
+msgid "Value Track:"
+msgstr "數值軌道:"
+
msgid "Select Tracks to Copy"
msgstr "選擇軌道以複製"
msgid "Select All/None"
msgstr "選擇全部/取消選擇"
+msgid "Animation Change Keyframe Time"
+msgstr "更改動畫關鍵畫格時間"
+
msgid "Add Audio Track Clip"
msgstr "新增音訊軌片段"
@@ -905,6 +1177,14 @@ msgstr "行號:"
msgid "%d replaced."
msgstr "已取代 %d 件。"
+msgid "%d match"
+msgid_plural "%d matches"
+msgstr[0] "%d 件相符合的結果"
+
+msgid "%d of %d match"
+msgid_plural "%d of %d matches"
+msgstr[0] "%d 件中%d件相符合的結果"
+
msgid "Match Case"
msgstr "區分大小寫"
@@ -952,6 +1232,9 @@ msgid ""
"target node."
msgstr "找不到目標方法!請指定一個有效的方法,或將腳本附加至目標節點上。"
+msgid "Attached Script"
+msgstr "添加腳本"
+
msgid "Connect to Node:"
msgstr "連接至節點:"
@@ -961,12 +1244,30 @@ msgstr "連接至腳本:"
msgid "From Signal:"
msgstr "自訊號:"
+msgid "Filter Nodes"
+msgstr "篩選節點s"
+
+msgid "Go to Source"
+msgstr "前往來源"
+
msgid "Scene does not contain any script."
msgstr "場景中無任何腳本。"
msgid "Select Method"
msgstr "選擇方法"
+msgid "Filter Methods"
+msgstr "篩選方法s"
+
+msgid "No method found matching given filters."
+msgstr "找不到方法能符合給予的條件。"
+
+msgid "Script Methods Only"
+msgstr "僅腳本方法"
+
+msgid "Compatible Methods Only"
+msgstr "僅相容方法"
+
msgid "Remove"
msgstr "移除"
@@ -976,6 +1277,9 @@ msgstr "新增額外呼叫引數:"
msgid "Extra Call Arguments:"
msgstr "額外呼叫引數:"
+msgid "Allows to drop arguments sent by signal emitter."
+msgstr "允許放出訊號的可以不放參數(drop arguments)。"
+
msgid "Unbind Signal Arguments:"
msgstr "解除綁定訊號引數"
@@ -992,6 +1296,9 @@ msgid ""
"Defers the signal, storing it in a queue and only firing it at idle time."
msgstr "延後送出訊號,將其存放於佇列中並待閒置時再送出。"
+msgid "One Shot"
+msgstr "一次性"
+
msgid "Disconnects the signal after its first emission."
msgstr "首次發送訊號後中斷連接。"
@@ -1007,6 +1314,9 @@ msgstr "連接"
msgid "Signal:"
msgstr "訊號:"
+msgid "No description."
+msgstr "沒說明。"
+
msgid "Connect '%s' to '%s'"
msgstr "將「%s」連接至「%s」"
@@ -1034,18 +1344,27 @@ msgstr "確定要删除所有來自訊號「%s」的連接嗎?"
msgid "Signals"
msgstr "訊號"
+msgid "Filter Signals"
+msgstr "篩選訊號s"
+
msgid "Are you sure you want to remove all connections from this signal?"
msgstr "確定要刪除所有來自此訊號的連接嗎?"
msgid "Disconnect All"
msgstr "中斷全部"
+msgid "Copy Name"
+msgstr "複製名稱"
+
msgid "Edit..."
msgstr "編輯…"
msgid "Go to Method"
msgstr "跳至方法"
+msgid "Change Type of \"%s\""
+msgstr "更改型別「%s」"
+
msgid "Change"
msgstr "更改"
@@ -1055,6 +1374,12 @@ msgstr "建立新的 %s"
msgid "No results for \"%s\"."
msgstr "找不到與「%s」相關的結果。"
+msgid "This class is marked as deprecated."
+msgstr "這個class已經標記不用了。"
+
+msgid "This class is marked as experimental."
+msgstr "這個class已經標記實驗性了。"
+
msgid "No description available for %s."
msgstr "缺少對%s的可用解釋。"
@@ -1064,6 +1389,9 @@ msgstr "我的最愛:"
msgid "Recent:"
msgstr "最近存取:"
+msgid "(Un)favorite selected item."
+msgstr "將目前物件新增或移除至我的最愛。"
+
msgid "Search:"
msgstr "搜尋:"
@@ -1091,9 +1419,42 @@ msgstr "複製節點路徑"
msgid "Instance:"
msgstr "實體:"
+msgid ""
+"This node has been instantiated from a PackedScene file:\n"
+"%s\n"
+"Click to open the original file in the Editor."
+msgstr ""
+"這個節點是從PackedScene中instantiated,來自:\n"
+"「%s」\n"
+"點擊以在編輯器中開啟原始檔案。"
+
msgid "Toggle Visibility"
msgstr "切換可見/隱藏"
+msgid "Updating assets on target device:"
+msgstr "在目標裝置上更新素材:"
+
+msgid "Syncing headers"
+msgstr "同步Headers"
+
+msgid "Getting remote file system"
+msgstr "取得遠端檔案系統"
+
+msgid "Decompressing remote file system"
+msgstr "解壓縮遠端檔案系統"
+
+msgid "Scanning for local changes"
+msgstr "尋找本地改變"
+
+msgid "Sending list of changed files:"
+msgstr "傳送更改檔案表:"
+
+msgid "Sending file:"
+msgstr "正在傳送檔案:"
+
+msgid "ms"
+msgstr "毫秒"
+
msgid "Monitors"
msgstr "監視器"
@@ -1162,6 +1523,21 @@ msgstr "時間"
msgid "Calls"
msgstr "呼叫"
+msgid "Fit to Frame"
+msgstr "吻合影格"
+
+msgid "Linked"
+msgstr "已連接"
+
+msgid "CPU"
+msgstr "CPU"
+
+msgid "GPU"
+msgstr "GPU"
+
+msgid "Execution resumed."
+msgstr "恢復操作。"
+
msgid "Bytes:"
msgstr "位元組:"
@@ -1177,15 +1553,36 @@ msgstr "%s 錯誤"
msgid "%s Error:"
msgstr "%s 錯誤:"
+msgid "%s Source"
+msgstr "%s 來源"
+
+msgid "%s Source:"
+msgstr "%s原始檔:"
+
msgid "Stack Trace"
msgstr "堆疊回溯"
msgid "Stack Trace:"
msgstr "堆疊追蹤:"
+msgid "Debug session started."
+msgstr "除錯階段開始。"
+
+msgid "Debug session closed."
+msgstr "除錯階段結束。"
+
+msgid "Line %d"
+msgstr "%d行"
+
+msgid "Delete Breakpoint"
+msgstr "移除中斷點"
+
msgid "Delete All Breakpoints in:"
msgstr "移除所有中斷點:"
+msgid "Delete All Breakpoints"
+msgstr "移除全部中斷點"
+
msgid "Copy Error"
msgstr "複製錯誤"
@@ -1216,6 +1613,9 @@ msgstr "繼續"
msgid "Stack Frames"
msgstr "堆疊框"
+msgid "Filter Stack Variables"
+msgstr "篩選堆疊變數s"
+
msgid "Breakpoints"
msgstr "中斷點"
@@ -1228,6 +1628,9 @@ msgstr "收合全部"
msgid "Profiler"
msgstr "分析工具"
+msgid "Visual Profiler"
+msgstr "圖形化紀錄器"
+
msgid "List of Video Memory Usage by Resource:"
msgstr "依據資源列出視訊記憶體佔用:"
@@ -1308,12 +1711,22 @@ msgstr "相依性編輯器"
msgid "Search Replacement Resource:"
msgstr "搜尋並取代資源:"
+msgid "Open Scene"
+msgid_plural "Open Scenes"
+msgstr[0] "開啟場景"
+
msgid "Open"
msgstr "開啟"
msgid "Owners of: %s (Total: %d)"
msgstr "%s 的所有者(總計:%d)"
+msgid "Localization remap"
+msgstr "在地化重新對應"
+
+msgid "Localization remap for path '%s' and locale '%s'."
+msgstr "在地化重對應,路徑「%s」對應本地「%s」。"
+
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
@@ -1369,9 +1782,30 @@ msgstr "擁有"
msgid "Resources Without Explicit Ownership:"
msgstr "沒有明確從屬關係的資源:"
+msgid "Folder name cannot be empty."
+msgstr "資料夾名稱不能為空。"
+
+msgid "Folder name contains invalid characters."
+msgstr "資料夾名稱包含無效字元。"
+
+msgid "File with that name already exists."
+msgstr "已存在相同名稱的檔案。"
+
+msgid "Folder with that name already exists."
+msgstr "已存在相同名稱的資料夾。"
+
+msgid "Using slashes in folder names will create subfolders recursively."
+msgstr "如果使用斜線在資料夾名稱,會對應產生子資料夾。"
+
+msgid "Folder name is valid."
+msgstr "資料夾名稱為空。"
+
msgid "Could not create folder."
msgstr "無法新增資料夾。"
+msgid "Create new folder in %s:"
+msgstr "建立新資料夾在%s:"
+
msgid "Create Folder"
msgstr "建立資料夾"
@@ -1532,6 +1966,12 @@ msgstr "忽略效果"
msgid "Bus Options"
msgstr "匯流排選項"
+msgid "Duplicate Bus"
+msgstr "重複Bus"
+
+msgid "Delete Bus"
+msgstr "刪除Bus"
+
msgid "Reset Volume"
msgstr "重設音量"
@@ -1619,18 +2059,27 @@ msgstr "可使用的字元:"
msgid "Must not collide with an existing engine class name."
msgstr "不可與現存的引擎類別名稱衝突。"
+msgid "Must not collide with an existing global script class name."
+msgstr "不可與現存的全域腳本class名稱衝突。"
+
msgid "Must not collide with an existing built-in type name."
msgstr "不可與內建的類別名稱衝突。"
msgid "Must not collide with an existing global constant name."
msgstr "不可與現存的全域常數名稱衝突。"
+msgid "Keyword cannot be used as an Autoload name."
+msgstr "不可使用關鍵字作為 Autoload 名稱。"
+
msgid "Autoload '%s' already exists!"
msgstr "Autoload「%s」已經存在!"
msgid "Rename Autoload"
msgstr "重新命名 Autoload"
+msgid "Toggle Autoload Globals"
+msgstr "開啟/關閉全域 AutoLoad"
+
msgid "Move Autoload"
msgstr "移動 Autoload"
@@ -1643,27 +2092,144 @@ msgstr "啟用"
msgid "Rearrange Autoloads"
msgstr "重新排列 Autoload"
+msgid "Can't add Autoload:"
+msgstr "無法新增 Autoload:"
+
msgid "%s is an invalid path. File does not exist."
msgstr "%s為無效路徑。檔案不存在。"
msgid "%s is an invalid path. Not in resource path (res://)."
msgstr "%s為無效路徑,並非資源路徑(res://)。"
+msgid "Add Autoload"
+msgstr "新增 Autoload"
+
msgid "Path:"
msgstr "路徑:"
+msgid "Set path or press \"%s\" to create a script."
+msgstr "設定路徑或按\"%s\"以產生腳本。"
+
msgid "Node Name:"
msgstr "節點名稱:"
msgid "Global Variable"
msgstr "全域變數"
+msgid "3D Engine"
+msgstr "3D引擎"
+
+msgid "2D Physics"
+msgstr "2D物理"
+
+msgid "3D Physics"
+msgstr "3D物理"
+
msgid "Navigation"
msgstr "導航"
+msgid "XR"
+msgstr "XR"
+
+msgid "RenderingDevice"
+msgstr "渲染裝置"
+
+msgid "OpenGL"
+msgstr "OpenGL(開放圖形庫)"
+
msgid "Vulkan"
msgstr "Vulkan"
+msgid "Text Server: Fallback"
+msgstr "文字伺服器:Fallback"
+
+msgid "Text Server: Advanced"
+msgstr "文字伺服器:進間"
+
+msgid "TTF, OTF, Type 1, WOFF1 Fonts"
+msgstr "TTF, OTF, Type 1, WOFF1字型"
+
+msgid "WOFF2 Fonts"
+msgstr "WOFF2字型"
+
+msgid "SIL Graphite Fonts"
+msgstr "SIL Graphite字型"
+
+msgid "Multi-channel Signed Distance Field Font Rendering"
+msgstr "多通道距離場(Multi-channel Signed Distance Field)字型渲染"
+
+msgid "3D Nodes as well as RenderingServer access to 3D features."
+msgstr "3D節點,又或是RenderingServer會有3D功能。"
+
+msgid "2D Physics nodes and PhysicsServer2D."
+msgstr "2D物理節點與PhysicsServer2D。"
+
+msgid "3D Physics nodes and PhysicsServer3D."
+msgstr "3D物理節點與PhysicsServer3D。"
+
+msgid "Navigation, both 2D and 3D."
+msgstr "導航,包含2D與3D。"
+
+msgid "XR (AR and VR)."
+msgstr "XR(包含AR和VR)。"
+
+msgid ""
+"RenderingDevice based rendering (if disabled, the OpenGL back-end is "
+"required)."
+msgstr "基於渲染裝置的渲染(如果取消,那會需要OpenGL 的後端)。"
+
+msgid ""
+"OpenGL back-end (if disabled, the RenderingDevice back-end is required)."
+msgstr "OpenGL 的後端(如果取消,那會需要渲染裝置的後端)。"
+
+msgid "Vulkan back-end of RenderingDevice."
+msgstr "渲染裝置的Vulkan後端。"
+
+msgid ""
+"Fallback implementation of Text Server\n"
+"Supports basic text layouts."
+msgstr ""
+"文本服務器的fallback實現\n"
+"支持基本的文本佈局。"
+
+msgid ""
+"Text Server implementation powered by ICU and HarfBuzz libraries.\n"
+"Supports complex text layouts, BiDi, and contextual OpenType font features."
+msgstr ""
+"由 ICU 和 HarfBuzz libraries實現文本服務器。\n"
+"支持複雜的文本佈局、BiDi 和上下文 OpenType 字體功能。"
+
+msgid ""
+"TrueType, OpenType, Type 1, and WOFF1 font format support using FreeType "
+"library (if disabled, WOFF2 support is also disabled)."
+msgstr ""
+"使用 FreeType 庫可以支持 TrueType、OpenType、Type 1 和 WOFF1 字體格式(如果禁"
+"用,WOFF2 支持也會被禁用)。"
+
+msgid "WOFF2 font format support using FreeType and Brotli libraries."
+msgstr "使用 FreeType 和 Brotli 庫支持 WOFF2 字體格式。"
+
+msgid ""
+"SIL Graphite smart font technology support (supported by Advanced Text "
+"Server only)."
+msgstr "SIL Graphite 智能字體技術支持(僅受 Advanced Text Server 支持)。"
+
+msgid ""
+"Multi-channel signed distance field font rendering support using msdfgen "
+"library (pre-rendered MSDF fonts can be used even if this option disabled)."
+msgstr ""
+"使用 msdfgen 庫的多通道帶符號距離場(MSDF)字體渲染支持(即使禁用此選項,也可以"
+"使用預渲染的 MSDF 字體)。"
+
+msgid "General Features:"
+msgstr "通用功能:"
+
+msgid "Text Rendering and Font Options:"
+msgstr "文字渲染與字型選項:"
+
+msgid "File saving failed."
+msgstr "保存檔案時發生錯誤。"
+
msgid "Nodes and Classes:"
msgstr "節點與類別:"
@@ -1685,12 +2251,36 @@ msgstr "設定:"
msgid "Reset to Defaults"
msgstr "重設為預設"
+msgid "Detect from Project"
+msgstr "偵測到project"
+
+msgid "Actions:"
+msgstr "動作:"
+
+msgid "Configure Engine Build Profile:"
+msgstr "設定引擎建立設定檔:"
+
msgid "Please Confirm:"
msgstr "請確認:"
+msgid "Engine Build Profile"
+msgstr "引擎建立設定檔"
+
+msgid "Load Profile"
+msgstr "開啟設定檔"
+
msgid "Export Profile"
msgstr "匯出設定檔"
+msgid "Forced classes on detect:"
+msgstr "強制class被偵測:"
+
+msgid "Edit Build Configuration Profile"
+msgstr "更改 Build Configuration設定檔"
+
+msgid "Filter Commands"
+msgstr "篩選指令"
+
msgid "Paste Params"
msgstr "貼上參數"
@@ -1730,6 +2320,9 @@ msgstr "檔案系統停駐列"
msgid "Import Dock"
msgstr "匯入停駐列"
+msgid "History Dock"
+msgstr "歷史記錄Dock"
+
msgid "Allows to view and edit 3D scenes."
msgstr "允許檢視並編輯3D場景。"
@@ -1755,6 +2348,9 @@ msgid ""
"FileSystem dock to function."
msgstr "允許為個別素材調整匯入設定。需要檔案系統停佇列以運作。"
+msgid "Provides an overview of the editor's and each scene's undo history."
+msgstr "提供編輯器與各場景歷史紀錄的概覽。"
+
msgid "(current)"
msgstr "(目前)"
@@ -1841,6 +2437,9 @@ msgstr "匯入設定檔"
msgid "Manage Editor Feature Profiles"
msgstr "管理編輯器功能設定檔"
+msgid "Some extensions need the editor to restart to take effect."
+msgstr "部分extensions必須重新啟動編輯器才會使改動生效。"
+
msgid "Restart"
msgstr "重新啟動"
@@ -1858,9 +2457,58 @@ msgstr "由於有多個匯入器對檔案 %s 提供了不同的型別,已中
msgid "(Re)Importing Assets"
msgstr "(重新)匯入素材"
+msgid "Import resources of type: %s"
+msgstr "匯入資源的型態:%s"
+
+msgid "No return value."
+msgstr "沒有回傳值。"
+
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr "這個值是這些旗標(flag)的bitmask湊起來的integer。"
+
+msgid "Deprecated"
+msgstr "放棄(不用了)"
+
+msgid "Experimental"
+msgstr "實驗性"
+
+msgid "This method supports a variable number of arguments."
+msgstr "這個方法支援不同數量的參數。"
+
+msgid ""
+"This method is called by the engine.\n"
+"It can be overridden to customize built-in behavior."
+msgstr ""
+"這個方法是被引擎呼叫\n"
+"無法被自訂的行為所覆蓋(override)。"
+
+msgid ""
+"This method has no side effects.\n"
+"It does not modify the object in any way."
+msgstr ""
+"這個方法沒有副作用。\n"
+"他不會改變這個物件。"
+
+msgid ""
+"This method does not need an instance to be called.\n"
+"It can be called directly using the class name."
+msgstr ""
+"這個方法不需要產生instance就能呼叫。\n"
+"他是由class name直接呼叫。"
+
msgid "Error codes returned:"
msgstr "傳回錯誤碼:"
+msgid "There is currently no description for this %s."
+msgstr "現在沒有關於%s的敘述。"
+
+msgid ""
+"There is currently no description for this %s. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"該方法「%s」目前沒有說明。請幫我們[color=$color][url=$url]貢獻一個[/url][/"
+"color]!"
+
msgid "Top"
msgstr "頂端"
@@ -1873,9 +2521,29 @@ msgstr "繼承:"
msgid "Inherited by:"
msgstr "被繼承:"
+msgid ""
+"This class is marked as deprecated. It will be removed in future versions."
+msgstr "這個class已經被標記為廢棄。他會在未來版本被移除。"
+
+msgid ""
+"This class is marked as experimental. It is subject to likely change or "
+"possible removal in future versions. Use at your own discretion."
+msgstr ""
+"這個class已經被標記為實驗性。在未來版本中通常會被改變或可能被移除。你自己好好"
+"想想要不要用。"
+
msgid "Description"
msgstr "說明"
+msgid "There is currently no description for this class."
+msgstr "現在沒有關於這個class的描述喔<3。"
+
+msgid ""
+"There is currently no description for this class. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"該class目前沒有說明。請幫我們[color=$color][url=$url]貢獻一個[/url][/color]!"
+
msgid "Online Tutorials"
msgstr "線上教學"
@@ -1888,6 +2556,15 @@ msgstr "覆蓋 %s:"
msgid "default:"
msgstr "預設:"
+msgid "property:"
+msgstr "屬性:"
+
+msgid "Constructors"
+msgstr "建立子"
+
+msgid "Operators"
+msgstr "操作子"
+
msgid "Theme Properties"
msgstr "主題屬性"
@@ -1900,6 +2577,9 @@ msgstr "常數"
msgid "Fonts"
msgstr "字體"
+msgid "Font Sizes"
+msgstr "字體大小s"
+
msgid "Icons"
msgstr "圖示"
@@ -1909,21 +2589,42 @@ msgstr "樣式"
msgid "Enumerations"
msgstr "列舉"
+msgid "Annotations"
+msgstr "註釋s"
+
+msgid "There is currently no description for this annotation."
+msgstr "現在沒有關於這個註釋的描述<3。"
+
+msgid ""
+"There is currently no description for this annotation. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"該註解目前沒有說明。請幫我們[color=$color][url=$url]貢獻一個[/url][/color]!"
+
msgid "Property Descriptions"
msgstr "屬性說明"
msgid "(value)"
msgstr "(數值)"
+msgid "There is currently no description for this property."
+msgstr "現在沒有關於這個屬性的描述<3。"
+
msgid ""
"There is currently no description for this property. Please help us by "
"[color=$color][url=$url]contributing one[/url][/color]!"
msgstr ""
"該屬性目前無說明。請幫助我們[color=$color][url=$url]貢獻一個[/url][/color]!"
+msgid "Constructor Descriptions"
+msgstr "建立子說明"
+
msgid "Method Descriptions"
msgstr "方法說明"
+msgid "Operator Descriptions"
+msgstr "操作子說明"
+
msgid "%d match."
msgstr "%d 件相符合的結果。"
@@ -1945,12 +2646,21 @@ msgstr "全部顯示"
msgid "Classes Only"
msgstr "僅顯示類別"
+msgid "Constructors Only"
+msgstr "僅建立子"
+
msgid "Methods Only"
msgstr "僅顯示方法"
+msgid "Operators Only"
+msgstr "僅操作子"
+
msgid "Signals Only"
msgstr "僅顯示訊號"
+msgid "Annotations Only"
+msgstr "僅註釋"
+
msgid "Constants Only"
msgstr "僅顯示常數"
@@ -1963,6 +2673,9 @@ msgstr "僅顯示主題屬性"
msgid "Member Type"
msgstr "成員型別"
+msgid "(constructors)"
+msgstr "(建立子)"
+
msgid "Class"
msgstr "類別"
@@ -1972,6 +2685,9 @@ msgstr "方法"
msgid "Signal"
msgstr "訊號"
+msgid "Annotation"
+msgstr "註釋"
+
msgid "Constant"
msgstr "常數"
@@ -1981,9 +2697,21 @@ msgstr "屬性"
msgid "Theme Property"
msgstr "主題屬性"
+msgid "This member is marked as deprecated."
+msgstr "這個成員被標記廢棄:(。"
+
+msgid "This member is marked as experimental."
+msgstr "這個成員被標記實驗性:(。"
+
msgid "Property:"
msgstr "屬性:"
+msgid "Pin Value"
+msgstr "釘選數值"
+
+msgid "Pin Value [Disabled because '%s' is editor-only]"
+msgstr "釘選數值【已停用因'%s'僅適用於編輯器】"
+
msgid ""
"Pinning a value forces it to be saved even if it's equal to the default."
msgstr "釘選的數值將被迫儲存,即使其值與預設值相同。"
@@ -1991,30 +2719,106 @@ msgstr "釘選的數值將被迫儲存,即使其值與預設值相同。"
msgid "Open Documentation"
msgstr "開啟說明文件"
+msgid "(%d change)"
+msgid_plural "(%d changes)"
+msgstr[0] "(%d變更)"
+
+msgid "Add element to property array with prefix %s."
+msgstr "加入前綴%s元素到屬性陣列。"
+
+msgid "Remove element %d from property array with prefix %s."
+msgstr "從屬性陣列移除在%d的前綴%s元素。"
+
+msgid "Move element %d to position %d in property array with prefix %s."
+msgstr "移動在屬性陣列從%d到%d的前綴%s元素。"
+
+msgid "Clear property array with prefix %s."
+msgstr "清除%s前綴屬性陣列。"
+
+msgid "Resize property array with prefix %s."
+msgstr "重新定大小%s前綴屬性陣列。"
+
+msgid "Element %d: %s%d*"
+msgstr "元素 %d:%s%d*"
+
msgid "Move Up"
msgstr "上移"
msgid "Move Down"
msgstr "下移"
+msgid "Insert New Before"
+msgstr "在前一格插入新的"
+
+msgid "Insert New After"
+msgstr "在後一格插入新的"
+
+msgid "Clear Array"
+msgstr "清除陣列"
+
+msgid "Resize Array..."
+msgstr "調整陣列大小..."
+
+msgid "Add Element"
+msgstr "新增元素"
+
msgid "Resize Array"
msgstr "調整陣列大小"
+msgid "New Size:"
+msgstr "新大小:"
+
+msgid "Element %s"
+msgstr "元素%s"
+
+msgid "Add Metadata"
+msgstr "新增Metadata"
+
msgid "Set %s"
msgstr "設定 %s"
msgid "Set Multiple:"
msgstr "設定多個:"
+msgid "Remove metadata %s"
+msgstr "刪除metadata %s"
+
msgid "Pinned %s"
msgstr "已釘選%s"
msgid "Unpinned %s"
msgstr "已解除釘選%s"
+msgid "Add metadata %s"
+msgstr "新增metadata %s"
+
+msgid "Metadata name can't be empty."
+msgstr "metadata名稱不能是空的。"
+
+msgid "Metadata name must be a valid identifier."
+msgstr "metadata名稱必須為有效識別項。"
+
+msgid "Metadata with name \"%s\" already exists."
+msgstr "已存在名稱為「%s」的metadata。"
+
+msgid "Names starting with _ are reserved for editor-only metadata."
+msgstr "metadata名稱開頭為底線的是給編輯器專用的。"
+
+msgid "Metadata name is valid."
+msgstr "可用的metadata名稱。"
+
msgid "Name:"
msgstr "名稱:"
+msgid "Add Metadata Property for \"%s\""
+msgstr "新增metadata屬性給「%s」"
+
+msgid "Copy Value"
+msgstr "複製數值"
+
+msgid "Paste Value"
+msgstr "貼上數值"
+
msgid "Copy Property Path"
msgstr "複製屬性路徑"
@@ -2027,12 +2831,27 @@ msgstr "縮圖…"
msgid "Select existing layout:"
msgstr "選擇既存的畫面佈局:"
+msgid "Or enter new layout name"
+msgstr "或是輸入新的排版名稱"
+
+msgid "Changed Locale Language Filter"
+msgstr "更改地區語言篩選條件"
+
+msgid "Changed Locale Script Filter"
+msgstr "更改地區腳本篩選條件"
+
+msgid "Changed Locale Country Filter"
+msgstr "更改地區國家篩選條件"
+
msgid "Changed Locale Filter Mode"
msgstr "更改地區設定篩選模式"
msgid "[Default]"
msgstr "[預設]"
+msgid "Select a Locale"
+msgstr "選擇一個地區"
+
msgid "Show All Locales"
msgstr "顯示所有地區"
@@ -2055,15 +2874,47 @@ msgstr "國家:"
msgid "Language"
msgstr "語言"
+msgctxt "Locale"
+msgid "Script"
+msgstr "腳 本"
+
+msgid "Country"
+msgstr "國家"
+
msgid "Variant"
msgstr "變體"
+msgid "Filter Messages"
+msgstr "篩選訊息"
+
msgid "Clear Output"
msgstr "清除輸出"
msgid "Copy Selection"
msgstr "複製所選"
+msgid ""
+"Collapse duplicate messages into one log entry. Shows number of occurrences."
+msgstr "把重複訊息摺疊到一個log entry。顯示發生次數。"
+
+msgid "Focus Search/Filter Bar"
+msgstr "焦點搜尋/篩選條"
+
+msgid "Toggle visibility of standard output messages."
+msgstr "顯示/取消顯示輸出訊息。"
+
+msgid "Toggle visibility of errors."
+msgstr "顯示/取消顯示錯誤。"
+
+msgid "Toggle visibility of warnings."
+msgstr "顯示/取消顯示警告。"
+
+msgid "Toggle visibility of editor messages."
+msgstr "顯示/取消顯示編輯器訊息。"
+
+msgid "Native Shader Source Inspector"
+msgstr "內在Shader源頭檢視器"
+
msgid "New Window"
msgstr "新視窗"
@@ -2095,6 +2946,11 @@ msgid ""
"Make it unique first."
msgstr "由於該資源不屬於已編輯的場景,無法儲存該資源。請先使其獨立化。"
+msgid ""
+"This resource can't be saved because it was imported from another file. Make "
+"it unique first."
+msgstr "由於該資源已從別的檔案導入,無法儲存該資源。請先使其獨立化。"
+
msgid "Save Resource As..."
msgstr "另存資源為..."
@@ -2107,6 +2963,21 @@ msgstr "要求的檔案格式未知:"
msgid "Error while saving."
msgstr "保存時發生錯誤。"
+msgid "Can't open file '%s'. The file could have been moved or deleted."
+msgstr "無法開啟「%s」檔案。該檔案可能已被移動或刪除。"
+
+msgid "Error while parsing file '%s'."
+msgstr "無法解析檔案「%s」。"
+
+msgid "Scene file '%s' appears to be invalid/corrupt."
+msgstr "場景檔案「%s」可能損壞或不可用。"
+
+msgid "Missing file '%s' or one its dependencies."
+msgstr "缺少檔案「%s」或其相依性。"
+
+msgid "Error while loading file '%s'."
+msgstr "載入檔案「%s」時發生錯誤。"
+
msgid "Saving Scene"
msgstr "正在保存場景"
@@ -2120,6 +2991,13 @@ msgid "This operation can't be done without a tree root."
msgstr "無樹狀根目錄時無法進行此操作。"
msgid ""
+"This scene can't be saved because there is a cyclic instance inclusion.\n"
+"Please resolve it and then attempt to save again."
+msgstr ""
+"該場景有循環性實體化問題,無法儲存。\n"
+"請先解決此問題後再試一次。"
+
+msgid ""
"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
"be satisfied."
msgstr "無法儲存場景。可能是由於相依性(實體或繼承)無法滿足。"
@@ -2163,6 +3041,9 @@ msgstr "找不到配置名稱!"
msgid "Restored the Default layout to its base settings."
msgstr "已將預設配置還原至基本設定。"
+msgid "This object is marked as read-only, so it's not editable."
+msgstr "該物件被標示為唯讀,所以無法編輯。"
+
msgid ""
"This resource belongs to a scene that was imported, so it's not editable.\n"
"Please read the documentation relevant to importing scenes to better "
@@ -2172,13 +3053,33 @@ msgstr ""
"請閱讀有關匯入場景的說明文件以更瞭解該工作流程。"
msgid ""
+"This resource belongs to a scene that was instantiated or inherited.\n"
+"Changes to it must be made inside the original scene."
+msgstr ""
+"此資源屬於已被實例化或被繼承的場景。\n"
+"對它的改動必須在原本場景內。"
+
+msgid ""
"This resource was imported, so it's not editable. Change its settings in the "
"import panel and then re-import."
msgstr "該資源自外部匯入,無法編輯。請在匯入面板中修改設定並重新匯入。"
+msgid ""
+"This scene was imported, so changes to it won't be kept.\n"
+"Instantiating or inheriting it will allow you to make changes to it.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+"該場景自外部匯入,因此做出的改動將不會保存。\n"
+"實例化或繼承該場景即可對其做出修改。\n"
+"請閱讀與匯入相關的說明文件以更加瞭解該工作流程。"
+
msgid "Changes may be lost!"
msgstr "改動可能會遺失!"
+msgid "This object is read-only."
+msgstr "這個物件是唯讀。"
+
msgid "Open Base Scene"
msgstr "開啟基本場景"
@@ -2216,18 +3117,30 @@ msgstr "當滑鼠按鍵被按下時無法復原。"
msgid "Nothing to undo."
msgstr "無變更以復原。"
+msgid "Global Undo: %s"
+msgstr "全域復原:%s"
+
msgid "Remote Undo: %s"
msgstr "遠端復原: %s"
+msgid "Scene Undo: %s"
+msgstr "場景復原:%s"
+
msgid "Can't redo while mouse buttons are pressed."
msgstr "當滑鼠按鍵按下時無法復原。"
msgid "Nothing to redo."
msgstr "無變更以復原。"
+msgid "Global Redo: %s"
+msgstr "全域取消復原:%s"
+
msgid "Remote Redo: %s"
msgstr "遠端重做: %s"
+msgid "Scene Redo: %s"
+msgstr "場景取消復原:%s"
+
msgid "Can't reload a scene that was never saved."
msgstr "無法重新載入從未儲存過的場景。"
@@ -2244,9 +3157,15 @@ msgstr ""
msgid "Save & Reload"
msgstr "儲存並重新載入"
+msgid "Save modified resources before reloading?"
+msgstr "是否在重新載入前儲存變更?"
+
msgid "Save & Quit"
msgstr "儲存並退出"
+msgid "Save modified resources before closing?"
+msgstr "關閉前是否儲存更改?"
+
msgid "Save changes to the following scene(s) before reloading?"
msgstr "重新載入前要儲存下列場景的變更嗎?"
@@ -2317,6 +3236,9 @@ msgstr "清除最近開啟的場景"
msgid "There is no defined scene to run."
msgstr "未定義欲執行之場景。"
+msgid "%s - Godot Engine"
+msgstr "%s - Godot 引擎<3"
+
msgid ""
"No main scene has ever been defined, select one?\n"
"You can change it later in \"Project Settings\" under the 'application' "
@@ -2399,6 +3321,9 @@ msgstr "平移檢視"
msgid "Dock Position"
msgstr "停駐列位置"
+msgid "Make Floating"
+msgstr "使其Floating"
+
msgid "Add a new scene."
msgstr "新增場景。"
@@ -2420,6 +3345,18 @@ msgstr "跳至上一個開啟的場景。"
msgid "Copy Text"
msgstr "複製文字"
+msgid "Next Scene Tab"
+msgstr "下個場景分頁"
+
+msgid "Previous Scene Tab"
+msgstr "上個場景分頁"
+
+msgid "Focus FileSystem Filter"
+msgstr "焦點檔案系統篩選"
+
+msgid "Command Palette"
+msgstr "Command表"
+
msgid "New Scene"
msgstr "新場景"
@@ -2438,6 +3375,9 @@ msgstr "最近開啟的場景"
msgid "Save Scene"
msgstr "儲存場景"
+msgid "Export As..."
+msgstr "匯出成..."
+
msgid "MeshLibrary..."
msgstr "網格庫…"
@@ -2453,6 +3393,9 @@ msgstr "專案"
msgid "Project Settings..."
msgstr "專案設定..."
+msgid "Project Settings"
+msgstr "專案設定"
+
msgid "Version Control"
msgstr "版本控制"
@@ -2465,6 +3408,9 @@ msgstr "安裝 Android 建置樣板..."
msgid "Open User Data Folder"
msgstr "打開使用者資料資料夾"
+msgid "Customize Engine Build Configuration..."
+msgstr "正在設定自訂Engine Build選項..."
+
msgid "Tools"
msgstr "工具"
@@ -2483,6 +3429,9 @@ msgstr "編輯器"
msgid "Editor Settings..."
msgstr "編輯器設定..."
+msgid "Command Palette..."
+msgstr "Command表..."
+
msgid "Editor Layout"
msgstr "編輯器配置"
@@ -2510,6 +3459,9 @@ msgstr "管理編輯器功能..."
msgid "Manage Export Templates..."
msgstr "管理匯出樣板..."
+msgid "Configure FBX Importer..."
+msgstr "設定FBX匯入器..."
+
msgid "Help"
msgstr "說明"
@@ -2522,6 +3474,12 @@ msgstr "常見問答"
msgid "Report a Bug"
msgstr "回報錯誤"
+msgid "Copy System Info"
+msgstr "複製系統資訊"
+
+msgid "Copies the system info as a single-line text into the clipboard."
+msgstr "複製系統資訊到clipboard為單行文字。"
+
msgid "Suggest a Feature"
msgstr "提出功能建議"
@@ -2537,9 +3495,27 @@ msgstr "關於Godot"
msgid "Support Godot Development"
msgstr "支援 Godot 開發"
+msgid "Choose a renderer."
+msgstr "選擇渲染器。"
+
+msgid "Forward+"
+msgstr "前向渲染(Forward+)"
+
+msgid "Mobile"
+msgstr "移動裝置"
+
+msgid "Compatibility"
+msgstr "相容"
+
+msgid "Changing the renderer requires restarting the editor."
+msgstr "更改渲染器需要重新啟動編輯器。"
+
msgid "Update Continuously"
msgstr "持續更新"
+msgid "Update When Changed"
+msgstr "更新所有變更"
+
msgid "Hide Update Spinner"
msgstr "隱藏更新旋轉圖"
@@ -2552,6 +3528,9 @@ msgstr "屬性面板"
msgid "Node"
msgstr "節點"
+msgid "History"
+msgstr "歷史記錄"
+
msgid "Expand Bottom Panel"
msgstr "展開底部面板"
@@ -2570,6 +3549,25 @@ msgstr "管理樣板"
msgid "Install from file"
msgstr "自檔案安裝"
+msgid "Select Android sources file"
+msgstr "選擇Android原始檔"
+
+msgid ""
+"This will set up your project for gradle Android builds by installing the "
+"source template to \"res://android/build\".\n"
+"You can then apply modifications and build your own custom APK on export "
+"(adding modules, changing the AndroidManifest.xml, etc.).\n"
+"Note that in order to make gradle builds instead of using pre-built APKs, "
+"the \"Use Gradle Build\" option should be enabled in the Android export "
+"preset."
+msgstr ""
+"將於「res://android/build」安裝原始樣板以為該項目設定自定 Android 建置樣"
+"板。\n"
+"輸出時可套用修改並建置自定 APK(如新增模組、修改 AndroidManifest.xml …"
+"等)。\n"
+"請注意,若要使用自定建置而非使用預先建置之 APK,請啟用 Android 匯出預設設定中"
+"的 [Use Custom Build] 選項。"
+
msgid ""
"The Android build template is already installed in this project and it won't "
"be overwritten.\n"
@@ -2613,6 +3611,12 @@ msgstr "重新載入"
msgid "Resave"
msgstr "重新儲存"
+msgid "Create Version Control Metadata"
+msgstr "設定版本控制metadata"
+
+msgid "Version Control Settings"
+msgstr "版本控制系統 (VCS)設定"
+
msgid "New Inherited"
msgstr "新增繼承"
@@ -2640,6 +3644,9 @@ msgstr "開啟下一個編輯器"
msgid "Open the previous Editor"
msgstr "開啟上一個編輯器"
+msgid "Ok"
+msgstr "Ok"
+
msgid "Warning!"
msgstr "警告!"
@@ -2652,6 +3659,9 @@ msgstr "編輯外掛"
msgid "Installed Plugins:"
msgstr "已安裝的外掛:"
+msgid "Create New Plugin"
+msgstr "建立插件"
+
msgid "Version"
msgstr "版本"
@@ -2667,6 +3677,9 @@ msgstr "編輯文字:"
msgid "On"
msgstr "開啟"
+msgid "Renaming layer %d:"
+msgstr "重新命名%d圖層:"
+
msgid "No name provided."
msgstr "未提供名稱。"
@@ -2679,12 +3692,45 @@ msgstr "位元 %d,值 %d"
msgid "Rename"
msgstr "重新命名"
+msgid "Rename layer"
+msgstr "重新命名圖層"
+
+msgid "Layer %d"
+msgstr "圖層%d"
+
+msgid "No Named Layers"
+msgstr "沒有命名圖層"
+
+msgid "Edit Layer Names"
+msgstr "更改圖層名稱"
+
+msgid "<empty>"
+msgstr "<空>"
+
+msgid "Temporary Euler may be changed implicitly!"
+msgstr "Temporary Euler可能會偷偷改變!"
+
+msgid ""
+"Temporary Euler will not be stored in the object with the original value. "
+"Instead, it will be stored as Quaternion with irreversible conversion.\n"
+"This is due to the fact that the result of Euler->Quaternion can be "
+"determined uniquely, but the result of Quaternion->Euler can be multi-"
+"existent."
+msgstr ""
+"臨時Euler不會以原始值存儲在對象中。 相反,它將被存儲為具有不可逆轉換的"
+"Quaternion 。\n"
+"這是因為Euler->Quaternion的結果可以唯一確定,而Quaternion->Euler的結果可以是"
+"多重存在的。"
+
msgid "Assign..."
msgstr "指派..."
msgid "Invalid RID"
msgstr "無效的 RID"
+msgid "Recursion detected, unable to assign resource to property."
+msgstr "偵測到遞迴,沒辦法指定資源到屬性。"
+
msgid ""
"Can't create a ViewportTexture on resources saved as a file.\n"
"Resource needs to belong to a scene."
@@ -2707,12 +3753,24 @@ msgstr "選擇 Viewport"
msgid "Selected node is not a Viewport!"
msgstr "所選節點並非 Viewport!"
+msgid "(Nil) %s"
+msgstr "「Nil」%s"
+
+msgid "%s (size %s)"
+msgstr "%s (大小 %s)"
+
msgid "Size:"
msgstr "大小:"
msgid "Remove Item"
msgstr "移除項目"
+msgid "Dictionary (Nil)"
+msgstr "字典(Nil)"
+
+msgid "Dictionary (size %d)"
+msgstr "字典(大小%d)"
+
msgid "New Key:"
msgstr "新增索引鍵:"
@@ -2722,6 +3780,18 @@ msgstr "新增數值:"
msgid "Add Key/Value Pair"
msgstr "新增索引鍵/值組"
+msgid "Localizable String (Nil)"
+msgstr "在地化字串(Nil)"
+
+msgid "Localizable String (size %d)"
+msgstr "在地化字串(大小%d)"
+
+msgid "Add Translation"
+msgstr "新增翻譯"
+
+msgid "Lock/Unlock Component Ratio"
+msgstr "鎖定/解除鎖定元件比例"
+
msgid ""
"The selected resource (%s) does not match any type expected for this "
"property (%s)."
@@ -2730,9 +3800,15 @@ msgstr "所選資源(%s)不符合任該屬性(%s)的任何型別。"
msgid "Quick Load"
msgstr "快速載入"
+msgid "Inspect"
+msgstr "屬性檢視"
+
msgid "Make Unique"
msgstr "獨立化"
+msgid "Make Unique (Recursive)"
+msgstr "獨立化(遞迴)"
+
msgid "Convert to %s"
msgstr "轉換為 %s"
@@ -2745,6 +3821,15 @@ msgstr "新增腳本"
msgid "Extend Script"
msgstr "擴充腳本"
+msgid "New Shader"
+msgstr "新shader"
+
+msgid "No Remote Debug export presets configured."
+msgstr "沒有遠端除錯輸出預設被設定。"
+
+msgid "Remote Debug"
+msgstr "遠端除錯"
+
msgid ""
"No runnable export preset found for this platform.\n"
"Please add a runnable preset in the Export menu or define an existing preset "
@@ -2762,9 +3847,22 @@ msgstr "在 _run() 方法中填寫邏輯。"
msgid "There is an edited scene already."
msgstr "已有一個已編輯的場景。"
+msgid ""
+"Couldn't run editor script, did you forget to override the '_run' method?"
+msgstr "沒辦法執行編輯器腳本,是否忘記覆蓋「_run」方法?"
+
+msgid "Undo: %s"
+msgstr "復原:%s"
+
+msgid "Redo: %s"
+msgstr "取消復原:%s"
+
msgid "Edit Built-in Action"
msgstr "編輯內建動作"
+msgid "Edit Shortcut"
+msgstr "編輯快捷鍵"
+
msgid "Common"
msgstr "常見"
@@ -2774,6 +3872,9 @@ msgstr "編輯器設定"
msgid "General"
msgstr "一般"
+msgid "Filter Settings"
+msgstr "篩選設定"
+
msgid "The editor must be restarted for changes to take effect."
msgstr "必須重新啟動編輯器才會使改動生效。"
@@ -2783,6 +3884,72 @@ msgstr "快捷鍵"
msgid "Binding"
msgstr "綁定"
+msgid "Left Stick Left, Joystick 0 Left"
+msgstr "左搖桿往左,搖桿0往左"
+
+msgid "Left Stick Right, Joystick 0 Right"
+msgstr "左搖桿往右,搖桿0往右"
+
+msgid "Left Stick Up, Joystick 0 Up"
+msgstr "左搖桿往上,搖桿0往上"
+
+msgid "Left Stick Down, Joystick 0 Down"
+msgstr "左搖桿往下,搖桿0往下"
+
+msgid "Right Stick Left, Joystick 1 Left"
+msgstr "右搖桿往左,搖桿1往左"
+
+msgid "Right Stick Right, Joystick 1 Right"
+msgstr "右搖桿往右,搖桿1往右"
+
+msgid "Right Stick Up, Joystick 1 Up"
+msgstr "右搖桿往上,搖桿1往上"
+
+msgid "Right Stick Down, Joystick 1 Down"
+msgstr "右搖桿往下,搖桿1往下"
+
+msgid "Joystick 2 Left"
+msgstr "搖桿2往左"
+
+msgid "Left Trigger, Sony L2, Xbox LT, Joystick 2 Right"
+msgstr "左觸發器,Sony L2,Xbox LT,搖桿 2 往右"
+
+msgid "Joystick 2 Up"
+msgstr "搖桿2往上"
+
+msgid "Right Trigger, Sony R2, Xbox RT, Joystick 2 Down"
+msgstr "右觸發器,Sony R2,Xbox RT,搖桿 2 往下"
+
+msgid "Joystick 3 Left"
+msgstr "搖桿 3 往左"
+
+msgid "Joystick 3 Right"
+msgstr "搖桿 3 往右"
+
+msgid "Joystick 3 Up"
+msgstr "搖桿 3 往上"
+
+msgid "Joystick 3 Down"
+msgstr "搖桿 3 往下"
+
+msgid "Joystick 4 Left"
+msgstr "搖桿 4 往左"
+
+msgid "Joystick 4 Right"
+msgstr "搖桿 4 往右"
+
+msgid "Joystick 4 Up"
+msgstr "搖桿 4 往上"
+
+msgid "Joystick 4 Down"
+msgstr "搖桿 4 往下"
+
+msgid "or"
+msgstr "或"
+
+msgid "Unicode"
+msgstr "Unicode"
+
msgid "Joypad Axis %d %s (%s)"
msgstr "搖桿軸 %d %s (%s)"
@@ -2792,6 +3959,26 @@ msgstr "所有裝置"
msgid "Device"
msgstr "裝置"
+msgid "Listening for input..."
+msgstr "聆聽輸入...."
+
+msgid "Filter by event..."
+msgstr "篩選event..."
+
+msgid ""
+"Target platform requires 'ETC2/ASTC' texture compression. Enable 'Import "
+"ETC2 ASTC' in Project Settings."
+msgstr ""
+"目標平台上 必須使用「ETC2/ASTC」紋理壓縮。請在專案設定中啟用「Import ETC2 "
+"ASTC」。"
+
+msgid ""
+"Target platform requires 'S3TC/BPTC' texture compression. Enable 'Import "
+"S3TC BPTC' in Project Settings."
+msgstr ""
+"目標平台上必須使用「S3TC/BPTC」紋理壓縮。請在專案設定中啟用「Import S3TC/"
+"BPTC」。"
+
msgid "Project export for platform:"
msgstr "專案匯出平台:"
@@ -2804,12 +3991,18 @@ msgstr "套件安裝成功。"
msgid "Failed."
msgstr "失敗。"
+msgid "Storing File: %s"
+msgstr "儲存檔案:%s"
+
msgid "Storing File:"
msgstr "儲存檔案:"
msgid "No export template found at the expected path:"
msgstr "在預期的路徑中找不到匯出樣板:"
+msgid "ZIP Creation"
+msgstr "ZIP壓縮檔產生"
+
msgid "Could not open file to read from path \"%s\"."
msgstr "無法打開位於「%s」的檔案進行讀取。"
@@ -2825,6 +4018,15 @@ msgstr "無法建立「%s」檔案。"
msgid "Failed to export project files."
msgstr "無法匯出專案檔。"
+msgid "Can't open file for writing at path \"%s\"."
+msgstr "無法用寫入模式開啟檔案「%s」。"
+
+msgid "Can't open file for reading-writing at path \"%s\"."
+msgstr "無法用讀取-寫入模式開啟檔案「%s」。"
+
+msgid "Can't create encrypted file."
+msgstr "無法產生加密檔案。"
+
msgid "Can't open encrypted file to write."
msgstr "無法開啟加密檔案並寫入。"
@@ -2951,6 +4153,9 @@ msgstr "正在下載"
msgid "Connection Error"
msgstr "連線錯誤"
+msgid "TLS Handshake Error"
+msgstr "TLS交握錯誤"
+
msgid "Can't open the export templates file."
msgstr "無法開啟匯出樣板檔。"
@@ -3056,12 +4261,21 @@ msgstr "使用每個已定義的預設設定來匯出該專案。"
msgid "All presets must have an export path defined for Export All to work."
msgstr "所有預設設定都必須定義好匯出路徑,才可使用 [匯出全部] 功能。"
+msgid "Resources to exclude:"
+msgstr "排除的資源:"
+
msgid "Resources to export:"
msgstr "匯出的資源:"
msgid "Delete preset '%s'?"
msgstr "確定要刪除預設設定「%s」?"
+msgid "(Inherited)"
+msgstr "(繼承)"
+
+msgid "%s Export"
+msgstr "%s 匯出"
+
msgid "Release"
msgstr "發行"
@@ -3102,9 +4316,22 @@ msgstr "匯出所選場景(與其所有相依性)"
msgid "Export selected resources (and dependencies)"
msgstr "匯出所選資源(與其所有相依性)"
+msgid "Export all resources in the project except resources checked below"
+msgstr "匯出專案內所有資源,除了以下被勾選的資源"
+
+msgid "Export as dedicated server"
+msgstr "匯出成伺服器"
+
msgid "Export Mode:"
msgstr "匯出模式:"
+msgid ""
+"\"Strip Visuals\" will replace the following resources with placeholders:"
+msgstr "“Strip Visuals”將用佔位符(placeholders)替換以下資源:"
+
+msgid "Strip Visuals"
+msgstr "Strip Visual"
+
msgid "Keep"
msgstr "保持"
@@ -3131,9 +4358,35 @@ msgstr "自訂(以逗號分隔):"
msgid "Feature List:"
msgstr "功能清單:"
+msgid "Encryption"
+msgstr "加密"
+
+msgid "Encrypt Exported PCK"
+msgstr "加密匯出PCK"
+
+msgid "Encrypt Index (File Names and Info)"
+msgstr "加密指標(檔案名及其說明)"
+
+msgid ""
+"Filters to include files/folders\n"
+"(comma-separated, e.g: *.tscn, *.tres, scenes/*)"
+msgstr ""
+"包含檔案/資料夾的篩選條件\n"
+"(以半形逗號區分,如: *.tscn, *.tres, scenes/*)"
+
+msgid ""
+"Filters to exclude files/folders\n"
+"(comma-separated, e.g: *.ctex, *.import, music/*)"
+msgstr ""
+"排除檔案/資料夾的篩選條件\n"
+"(以半形逗號區分,如: *.ctex, *.import, music/*)"
+
msgid "Invalid Encryption Key (must be 64 hexadecimal characters long)"
msgstr "無效的加密密鑰(長度需為 64 個十六進位字元)"
+msgid "Encryption Key (256-bits as hexadecimal):"
+msgstr "加密密鑰(256 位元的 16 進位):"
+
msgid ""
"Note: Encryption key needs to be stored in the binary,\n"
"you need to build the export templates from source."
@@ -3144,6 +4397,9 @@ msgstr ""
msgid "More Info..."
msgstr "更多資訊..."
+msgid "Export PCK/ZIP..."
+msgstr "匯出 PCK/ZIP..."
+
msgid "Export Project..."
msgstr "匯出專案..."
@@ -3174,9 +4430,52 @@ msgstr "管理匯出樣板"
msgid "Export With Debug"
msgstr "以偵錯模式匯出"
+msgid "Disable FBX & Restart"
+msgstr "不啟用FBX並重新啟動"
+
+msgid ""
+"Canceling this dialog will disable the FBX importer.\n"
+"You can re-enable it in the Project Settings under Filesystem > Import > FBX "
+"> Enabled.\n"
+"\n"
+"The editor will restart as importers are registered when the editor starts."
+msgstr ""
+"關掉這個對話框會不啟用FBX匯入器。\n"
+"你可以重新在專案設定的 Filesystem > Import > FBX > Enabled 這樣重新啟用\n"
+"\n"
+"這個編輯器會重啟,因為導入器已經在編輯器開啟時註冊。"
+
+msgid "Path to FBX2glTF executable is empty."
+msgstr "FBX2glTF執行檔的路徑是空的。"
+
+msgid "Path to FBX2glTF executable is invalid."
+msgstr "至 FBX2glTF執行檔的路徑無效。"
+
+msgid "Error executing this file (wrong version or architecture)."
+msgstr "執行這個檔案時發生錯誤(錯誤版本或架構)。"
+
+msgid "FBX2glTF executable is valid."
+msgstr "無效的FBX2glTF執行檔。"
+
+msgid "Configure FBX Importer"
+msgstr "設定FBX匯入"
+
+msgid ""
+"FBX2glTF is required for importing FBX files.\n"
+"Please download it and provide a valid path to the binary:"
+msgstr ""
+"需要FBX2glTF來導入FBX檔案。\n"
+"請下載並提供有效的執行檔路徑:"
+
+msgid "Click this link to download FBX2glTF"
+msgstr "點擊這個連結以下載FBX2glTF"
+
msgid "Browse"
msgstr "瀏覽"
+msgid "Confirm Path"
+msgstr "確認路徑"
+
msgid "Favorites"
msgstr "我的最愛"
@@ -3205,10 +4504,23 @@ msgstr "移動時發生錯誤:"
msgid "Error duplicating:"
msgstr "複製時發生錯誤:"
+msgid "Failed to save resource at %s: %s"
+msgstr "儲存「%s」資源失敗:%s"
+
+msgid "Failed to load resource at %s: %s"
+msgstr "加載「%s」資源失敗:%s"
+
msgid "Unable to update dependencies:"
msgstr "無法更新相依性:"
msgid ""
+"This filename begins with a dot rendering the file invisible to the editor.\n"
+"If you want to rename it anyway, use your operating system's file manager."
+msgstr ""
+"這個命名用.(dot)作為檔案開頭,該檔案不會在編輯器中顯示。\n"
+"如果你確定要重新命名,請使用系統的檔案管理員。"
+
+msgid ""
"This file extension is not recognized by the editor.\n"
"If you want to rename it anyway, use your operating system's file manager.\n"
"After renaming to an unknown extension, the file won't be shown in the "
@@ -3221,6 +4533,17 @@ msgstr ""
msgid "A file or folder with this name already exists."
msgstr "已有相同名稱的檔案或資料夾存在。"
+msgid ""
+"The following files or folders conflict with items in the target location "
+"'%s':"
+msgstr "以下檔案或資料夾與目標路徑「%s」中的項目衝突:"
+
+msgid "Do you wish to overwrite them or rename the copied files?"
+msgstr "你希望覆蓋這些檔案或重新命名複製出的檔案嗎?"
+
+msgid "Do you wish to overwrite them or rename the moved files?"
+msgstr "你希望覆蓋這些檔案或重新命名移動完的檔案嗎?"
+
msgid "Duplicating file:"
msgstr "複製檔案:"
@@ -3236,12 +4559,45 @@ msgstr "設為主場景"
msgid "Open Scenes"
msgstr "開啟場景"
+msgid "Instantiate"
+msgstr "Instantiate"
+
msgid "Edit Dependencies..."
msgstr "編輯相依性..."
msgid "View Owners..."
msgstr "檢視擁有者..."
+msgid "Create New"
+msgstr "建立新的"
+
+msgid "Folder..."
+msgstr "資料夾..."
+
+msgid "Scene..."
+msgstr "場景..."
+
+msgid "Script..."
+msgstr "腳本..."
+
+msgid "Resource..."
+msgstr "資源..."
+
+msgid "TextFile..."
+msgstr "文字檔案..."
+
+msgid "Expand Folder"
+msgstr "擴展資料夾"
+
+msgid "Expand Hierarchy"
+msgstr "擴展繼承樹狀圖"
+
+msgid "Collapse Hierarchy"
+msgstr "摺疊繼承樹狀圖"
+
+msgid "Move/Duplicate To..."
+msgstr "移動/重複到..."
+
msgid "Add to Favorites"
msgstr "新增到我的最愛"
@@ -3263,6 +4619,12 @@ msgstr "新增腳本..."
msgid "New Resource..."
msgstr "新增資源..."
+msgid "New TextFile..."
+msgstr "新增文字檔..."
+
+msgid "Sort Files"
+msgstr "檔案排序"
+
msgid "Sort by Name (Ascending)"
msgstr "按名稱排序(升冪)"
@@ -3284,18 +4646,33 @@ msgstr "按最早修改時間排序"
msgid "Copy Path"
msgstr "複製路徑"
+msgid "Copy UID"
+msgstr "複製UID"
+
msgid "Duplicate..."
msgstr "重複..."
msgid "Rename..."
msgstr "重新命名..."
+msgid "Open in External Program"
+msgstr "在外部程式中開啟"
+
+msgid "Go to previous selected folder/file."
+msgstr "前往上一個選擇的資料夾/檔案。"
+
+msgid "Go to next selected folder/file."
+msgstr "前往下一個選擇的資料夾/檔案。"
+
msgid "Re-Scan Filesystem"
msgstr "重新掃描檔案系統"
msgid "Toggle Split Mode"
msgstr "開啟/關閉分割模式"
+msgid "Filter Files"
+msgstr "篩選檔案"
+
msgid ""
"Scanning Files,\n"
"Please Wait..."
@@ -3306,6 +4683,9 @@ msgstr ""
msgid "Overwrite"
msgstr "複寫"
+msgid "Keep Both"
+msgstr "兩者都保留"
+
msgid "Create Script"
msgstr "建立腳本"
@@ -3338,9 +4718,21 @@ msgstr "取代..."
msgid "Replace in Files"
msgstr "在檔案中取代"
+msgid "Replace all (no undo)"
+msgstr "取代全部(不可復原)"
+
msgid "Searching..."
msgstr "正在搜尋..."
+msgid "%d match in %d file"
+msgstr "%d 件相符合的結果(於 %d 個檔案內)"
+
+msgid "%d matches in %d file"
+msgstr "%d 件相符合結果(於 %d 個檔案內)"
+
+msgid "%d matches in %d files"
+msgstr "%d 件符合的結果(於 %d 個檔案內)"
+
msgid "Add to Group"
msgstr "新增到群組"
@@ -3383,15 +4775,34 @@ msgstr "移動"
msgid "Please select a base directory first."
msgstr "請先選擇基礎資料夾。"
+msgid "Could not create folder. File with that name already exists."
+msgstr "無法建立資料夾,已有相同名稱的檔案或資料夾存在。"
+
msgid "Choose a Directory"
msgstr "選擇資料夾"
+msgid "Copy File(s)"
+msgstr "複製檔案"
+
msgid "Network"
msgstr "網路"
msgid "Select Current Folder"
msgstr "選擇目前資料夾"
+msgid "Cannot save file with an empty filename."
+msgstr "無法保存空檔案名的檔案。"
+
+msgid "Cannot save file with a name starting with a dot."
+msgstr "無法保存檔案名開頭是句點的檔案。"
+
+msgid ""
+"File \"%s\" already exists.\n"
+"Do you want to overwrite it?"
+msgstr ""
+"檔案「%s」已存在。\n"
+"你希望覆寫嗎?"
+
msgid "Select This Folder"
msgstr "選擇此資料夾"
@@ -3416,6 +4827,9 @@ msgstr "開啟檔案或資料夾"
msgid "Save a File"
msgstr "儲存檔案"
+msgid "Favorited folder does not exist anymore and will be removed."
+msgstr "最愛資料夾將不存在或會被移除。"
+
msgid "Go Back"
msgstr "上一頁"
@@ -3470,6 +4884,16 @@ msgstr "預覽:"
msgid "File:"
msgstr "檔案:"
+msgid ""
+"Remove the selected files? For safety only files and empty directories can "
+"be deleted from here. (Cannot be undone.)\n"
+"Depending on your filesystem configuration, the files will either be moved "
+"to the system trash or deleted permanently."
+msgstr ""
+"確定要將所選檔案自專案中移除嗎?為了安全只有檔案和空資料夾可以從這邊刪除(無"
+"法復原)\n"
+"取決於您的檔案系統設定,檔案將移至系統資源回收桶或是永久刪除。"
+
msgid "No sub-resources found."
msgstr "未找到子資源。"
@@ -3482,12 +4906,86 @@ msgstr "執行該專案。"
msgid "Play the edited scene."
msgstr "執行已編輯的場景。"
+msgid "Play a custom scene."
+msgstr "執行自定義場景。"
+
+msgid "Reload the played scene."
+msgstr "重新載入播放場景。"
+
msgid "Quick Run Scene..."
msgstr "快速執行場景…"
+msgid ""
+"Movie Maker mode is enabled, but no movie file path has been specified.\n"
+"A default movie file path can be specified in the project settings under the "
+"Editor > Movie Writer category.\n"
+"Alternatively, for running single scenes, a `movie_file` string metadata can "
+"be added to the root node,\n"
+"specifying the path to a movie file that will be used when recording that "
+"scene."
+msgstr ""
+"電影製作模式已啟用,但未指定影片文件路徑。\n"
+"可以在 編輯器>電影製作 類別下的項目設置中指定默認電影文件路徑。\n"
+"或者,為了運行單個場景,可以將「movie_file」字符串元數據添加到根節點,\n"
+"指定錄製該場景時將使用的影片文件的路徑。"
+
+msgid "Could not start subprocess(es)!"
+msgstr "無法啟動子處理程序!"
+
+msgid "Run the project's default scene."
+msgstr "執行專案預設場景。"
+
msgid "Run Project"
msgstr "執行專案"
+msgid "Pause the running project's execution for debugging."
+msgstr "暫停場景以進行除錯。"
+
+msgid "Pause Running Project"
+msgstr "暫停執行中專案"
+
+msgid "Stop the currently running project."
+msgstr "停止目前執行的專案。"
+
+msgid "Stop Running Project"
+msgstr "停止執行的專案"
+
+msgid "Run the currently edited scene."
+msgstr "執行目前編輯的場景。"
+
+msgid "Run Current Scene"
+msgstr "執行目前場景"
+
+msgid "Run a specific scene."
+msgstr "執行特定的場景。"
+
+msgid "Run Specific Scene"
+msgstr "執行特定場景"
+
+msgid ""
+"Enable Movie Maker mode.\n"
+"The project will run at stable FPS and the visual and audio output will be "
+"recorded to a video file."
+msgstr ""
+"啟用電影製作模式。\n"
+"該項目將以穩定的 FPS 運行,畫面和音訊輸出將記錄到影片檔案中。"
+
+msgid ""
+"Hold %s to round to integers.\n"
+"Hold Shift for more precise changes."
+msgstr ""
+"按住 %s 以取整數。\n"
+"按住 Shift 以進行更精確的更動。"
+
+msgid "No notifications."
+msgstr "沒有通知。"
+
+msgid "Show notifications."
+msgstr "顯示通知。"
+
+msgid "Silence the notifications."
+msgstr "靜音通知。"
+
msgid "Toggle Visible"
msgstr "切換可見/隱藏"
@@ -3514,9 +5012,26 @@ msgstr ""
"該節點可在此場景中的任何地方通過在節點路徑前方加上「%s」前置詞來存取。\n"
"點擊以禁用。"
+msgid "Node has one connection."
+msgid_plural "Node has {num} connections."
+msgstr[0] "節點有 {num} 個連結。"
+
+msgid "Node is in this group:"
+msgid_plural "Node is in the following groups:"
+msgstr[0] "節點在這些群組中:"
+
+msgid "Click to show signals dock."
+msgstr "點擊以顯示訊號 Dock。"
+
msgid "Open in Editor"
msgstr "在編輯器中開啟"
+msgid "This script is currently running in the editor."
+msgstr "這個腳本當前正在編輯器中執行。"
+
+msgid "This script is a custom type."
+msgstr "這個腳本是一個自訂型態。"
+
msgid "Open Script:"
msgstr "開啟腳本:"
@@ -3528,12 +5043,22 @@ msgstr ""
"點擊以解鎖。"
msgid ""
+"Children are not selectable.\n"
+"Click to make them selectable."
+msgstr ""
+"子節點不可選擇。\n"
+"點擊以令其可被選擇。"
+
+msgid ""
"AnimationPlayer is pinned.\n"
"Click to unpin."
msgstr ""
"已固定 AnimationPlayer。\n"
"點擊以取消固定。"
+msgid "\"%s\" is not a known filter."
+msgstr "「%s」不是一個已知的篩選。"
+
msgid "Invalid node name, the following characters are not allowed:"
msgstr "無效的節點名稱,名稱不可包含下列字元:"
@@ -3549,24 +5074,173 @@ msgstr "節點組態設定警告!"
msgid "Select a Node"
msgstr "選擇一個節點"
+msgid "The Beginning"
+msgstr "剛開始"
+
+msgid "Global"
+msgstr "全域"
+
+msgid "Audio Stream Importer: %s"
+msgstr "音訊流匯入:%s"
+
msgid "Reimport"
msgstr "重新匯入"
+msgid "Enable looping."
+msgstr "啟用循環模式。"
+
msgid "Offset:"
msgstr "偏移:"
+msgid ""
+"Loop offset (from beginning). Note that if BPM is set, this setting will be "
+"ignored."
+msgstr "循環偏移(從開始處開始)。 請注意,如果設置了 BPM,則該設置將被忽略。"
+
msgid "Loop:"
msgstr "循環:"
+msgid "BPM:"
+msgstr "BPM:"
+
+msgid ""
+"Configure the Beats Per Measure (tempo) used for the interactive streams.\n"
+"This is required in order to configure beat information."
+msgstr ""
+"配置用於交互流的每小節節拍(Beats Per Measure,節奏)。\n"
+"這是設定節拍信息所必需的。"
+
msgid "Beat Count:"
msgstr "節拍數:"
+msgid ""
+"Configure the amount of Beats used for music-aware looping. If zero, it will "
+"be autodetected from the length.\n"
+"It is recommended to set this value (either manually or by clicking on a "
+"beat number in the preview) to ensure looping works properly."
+msgstr ""
+"配置用於音樂感知循環的節拍量。 如果為零,它將根據長度自動檢測。\n"
+"建議設置此值(手動或通過單擊預覽中的節拍編號)以確保循環正常工作。"
+
+msgid "Bar Beats:"
+msgstr "每小節節拍:"
+
+msgid ""
+"Configure the Beats Per Bar. This used for music-aware transitions between "
+"AudioStreams."
+msgstr "配置每小節節拍。 這用於音訊流之間的音樂感知轉換。"
+
msgid "Music Playback:"
msgstr "音樂播放:"
+msgid "New Configuration"
+msgstr "新配置"
+
+msgid "Remove Variation"
+msgstr "刪除變異"
+
+msgid "Preloaded glyphs: %d"
+msgstr "預加載字形:%d"
+
+msgid ""
+"Warning: There are no configurations specified, no glyphs will be pre-"
+"rendered."
+msgstr "警告:沒有指定配置,不會預渲染任何字形。"
+
+msgid ""
+"Warning: Multiple configurations have identical settings. Duplicates will be "
+"ignored."
+msgstr "警告:多個配置具有相同的設定。 重複項將被忽略。"
+
+msgid ""
+"Note: LCD Subpixel antialiasing is selected, each of the glyphs will be pre-"
+"rendered for all supported subpixel layouts (5x)."
+msgstr ""
+"注意:選擇了 LCD 子像素抗鋸齒,每個字形都將為所有支持的子像素佈局 (5x) 進行預"
+"渲染。"
+
+msgid ""
+"Note: Subpixel positioning is selected, each of the glyphs might be pre-"
+"rendered for multiple subpixel offsets (up to 4x)."
+msgstr ""
+"注意:選擇子像素定位,每個字形可能會針對多個子像素偏移(最多 4x)進行預渲染。"
+
+msgid "Advanced Import Settings for '%s'"
+msgstr "“%s”的進階導入設定"
+
+msgid "Rendering Options"
+msgstr "渲染選項"
+
+msgid "Select font rendering options, fallback font, and metadata override:"
+msgstr "選擇字體渲染選項、後備字體和metadata覆蓋:"
+
+msgid "Pre-render Configurations"
+msgstr "預渲染配置"
+
+msgid ""
+"Add font size, and variation coordinates, and select glyphs to pre-render:"
+msgstr "添加字體大小和變化坐標,並選擇要預渲染的字形:"
+
msgid "Configuration:"
msgstr "設定:"
+msgid "Add configuration"
+msgstr "添加配置"
+
+msgid "Clear Glyph List"
+msgstr "清除字形列表"
+
+msgid "Glyphs from the Translations"
+msgstr "翻譯中的字形"
+
+msgid "Select translations to add all required glyphs to pre-render list:"
+msgstr "選擇翻譯以將所有必需的字形添加到預渲染列表:"
+
+msgid "Shape all Strings in the Translations and Add Glyphs"
+msgstr "修改翻譯中的所有字符串並添加字形"
+
+msgid "Glyphs from the Text"
+msgstr "文本中的字形"
+
+msgid ""
+"Enter a text and select OpenType features to shape and add all required "
+"glyphs to pre-render list:"
+msgstr "輸入文本並選擇 OpenType 功能來修改並將所有必需的字形添加到預渲染列表:"
+
+msgid "Shape Text and Add Glyphs"
+msgstr "修改文本並添加字形"
+
+msgid "Glyphs from the Character Map"
+msgstr "字符映射表中的字形"
+
+msgid ""
+"Add or remove glyphs from the character map to pre-render list:\n"
+"Note: Some stylistic alternatives and glyph variants do not have one-to-one "
+"correspondence to character, and not shown in this map, use \"Glyphs from "
+"the text\" tab to add these."
+msgstr ""
+"從字符映射表中添加或刪除字形到預渲染列表:\n"
+"注意:一些文體替代方案和字形變體與字符沒有一一對應,並且未在此圖中顯示,請使"
+"用“文本中的字形”選項卡添加這些。"
+
+msgid "Dynamically rendered TrueType/OpenType font"
+msgstr "動態渲染的 TrueType/OpenType 字體"
+
+msgid "Prerendered multichannel(+true) signed distance field"
+msgstr "預渲染的multichannel(+true)signed distance field"
+
+msgid "Can't load font texture:"
+msgstr "無法加載字體貼圖:"
+
+msgid "Image margin too big."
+msgstr "圖像邊距太大。"
+
+msgid "Character margin too bit."
+msgstr "字符邊距太大了。"
+
+msgid "Pre-Import Scene"
+msgstr "預導入場景"
+
msgid "Importing Scene..."
msgstr "正在匯入場景..."
@@ -3585,25 +5259,144 @@ msgstr "Post-Import 腳本無效或損毀(請檢查主控台):"
msgid "Error running post-import script:"
msgstr "執行 Post-Import 腳本時發生錯誤:"
+msgid "Did you return a Node-derived object in the `_post_import()` method?"
+msgstr "您是否在「_post_import()」方法中返回了 Node 派生的對象?"
+
msgid "Saving..."
msgstr "正在保存..."
msgid ""
+"Error importing GLSL shader file: '%s'. Open the file in the filesystem dock "
+"in order to see the reason."
+msgstr ""
+"導入 GLSL 著色器文件時出錯:“%s”。 打開文件系統面板中的文件以查看原因。"
+
+msgid ""
"%s: Texture detected as used as a normal map in 3D. Enabling red-green "
"texture compression to reduce memory usage (blue channel is discarded)."
msgstr ""
"%s: 偵測到使用在3D上的法線貼圖。啟用紅-綠材質壓縮來減少記憶體用量(藍色通道已"
"被捨棄)。"
+msgid ""
+"%s: Texture detected as used as a roughness map in 3D. Enabling roughness "
+"limiter based on the detected associated normal map at %s."
+msgstr ""
+"%s: 偵測到使用在3D上的roughness map。根據在 %s 處檢測到的相關法線貼圖啟用"
+"roughness limiter。"
+
+msgid ""
+"%s: Texture detected as used in 3D. Enabling mipmap generation and setting "
+"the texture compression mode to %s."
+msgstr ""
+"%s:檢測到在 3D 中使用的貼圖。 啟用 mipmap 生成並將貼圖壓縮模式設置為 %s。"
+
+msgid "2D/3D (Auto-Detect)"
+msgstr "2D/3D(自動檢測)"
+
msgid "2D"
msgstr "2D"
msgid "3D"
msgstr "3D"
+msgid "<Unnamed Material>"
+msgstr "<未命名材質>"
+
+msgid "Import ID: %s"
+msgstr "導入 ID:%s"
+
+msgid ""
+"Type: %s\n"
+"Import ID: %s"
+msgstr ""
+"類型:%s\n"
+"導入 ID:%s"
+
+msgid "Error opening scene"
+msgstr "打開場景時出錯"
+
+msgid "Advanced Import Settings for AnimationLibrary '%s'"
+msgstr "動畫庫「%s」的進階導入設置"
+
+msgid "Advanced Import Settings for Scene '%s'"
+msgstr "場景「%s」的進階導入設置"
+
msgid "Select folder to extract material resources"
msgstr "選擇資料夾以擷取材質資源"
+msgid "Select folder where mesh resources will save on import"
+msgstr "選擇導入時保存網格資源的文件夾"
+
+msgid "Select folder where animations will save on import"
+msgstr "選擇導入時保存動畫的文件夾"
+
+msgid "Warning: File exists"
+msgstr "警告:文件存在"
+
+msgid "Existing file with the same name will be replaced."
+msgstr "現有的同名文件將被替換。"
+
+msgid "Will create new file"
+msgstr "將創建新文件"
+
+msgid "Already External"
+msgstr "已經是外部的"
+
+msgid ""
+"This material already references an external file, no action will be taken.\n"
+"Disable the external property for it to be extracted again."
+msgstr ""
+"該材料已引用成外部文件,不會採取任何操作。\n"
+"禁用外部屬性以便再次提取它。"
+
+msgid "No import ID"
+msgstr "無導入 ID"
+
+msgid ""
+"Material has no name nor any other way to identify on re-import.\n"
+"Please name it or ensure it is exported with an unique ID."
+msgstr ""
+"材質在重新導入時沒有名稱或任何其他識別方式。\n"
+"請為其命名或確保使用唯一 ID 導出。"
+
+msgid "Extract Materials to Resource Files"
+msgstr "取出材質到資源文件"
+
+msgid "Extract"
+msgstr "取出"
+
+msgid "Already Saving"
+msgstr "已經在保存中"
+
+msgid ""
+"This mesh already saves to an external resource, no action will be taken."
+msgstr "該網格已保存到外部資源,不會採取任何操作。"
+
+msgid "Existing file with the same name will be replaced on import."
+msgstr "導入時將替換現有的同名文件。"
+
+msgid "Will save to new file"
+msgstr "將保存到新文件"
+
+msgid ""
+"Mesh has no name nor any other way to identify on re-import.\n"
+"Please name it or ensure it is exported with an unique ID."
+msgstr ""
+"網格沒有名稱,也沒有任何其他方式可以在重新導入時進行識別。\n"
+"請為其命名或確保使用唯一 ID 導出。"
+
+msgid "Set paths to save meshes as resource files on Reimport"
+msgstr "設置路徑以在重新導入時將網格保存為資源文件"
+
+msgid "Set Paths"
+msgstr "設置路徑"
+
+msgid ""
+"This animation already saves to an external resource, no action will be "
+"taken."
+msgstr "該動畫已保存到外部資源,不會採取任何操作。"
+
msgid "Set paths to save animations as resource files on Reimport"
msgstr "設定路徑將動畫另存為可導入的資源檔案"
@@ -3677,6 +5470,9 @@ msgstr "匯入為:"
msgid "Preset"
msgstr "預設設定"
+msgid "Advanced..."
+msgstr "進階..."
+
msgid "Save Scenes, Re-Import, and Restart"
msgstr "儲存場景、重新匯入、並重新啟動"
@@ -3692,12 +5488,70 @@ msgid ""
"import settings."
msgstr "從檔案系統中選擇資源檔,或是在面板上調整匯入設定。"
+msgid "No Event Configured"
+msgstr "未配置事件"
+
+msgid "Keyboard Keys"
+msgstr "鍵盤按鍵"
+
+msgid "Mouse Buttons"
+msgstr "滑鼠按鈕"
+
+msgid "Joypad Buttons"
+msgstr "控制器按鈕"
+
+msgid "Joypad Axes"
+msgstr "控制器軸"
+
+msgid "Event Configuration"
+msgstr "事件配置"
+
+msgid "Manual Selection"
+msgstr "手動選擇"
+
+msgid "Filter Inputs"
+msgstr "篩選輸入"
+
+msgid "Additional Options"
+msgstr "其他選項"
+
msgid "Device:"
msgstr "設備:"
+msgid "Command / Control (auto)"
+msgstr "命令/控制(自動)"
+
+msgid ""
+"Automatically remaps between 'Meta' ('Command') and 'Control' depending on "
+"current platform."
+msgstr "根據當前平台自動在\"Meta\"(\"命令\")和\"控制\"之間重新映射。"
+
+msgid "Keycode (Latin Equivalent)"
+msgstr "鍵碼(拉丁語等效)"
+
+msgid "Physical Keycode (Position on US QWERTY Keyboard)"
+msgstr "物理鍵碼(美國 QWERTY 鍵盤上的位置)"
+
+msgid "Key Label (Unicode, Case-Insensitive)"
+msgstr "鍵標籤(Unicode,不區分大小寫)"
+
+msgid ""
+"The following resources will be duplicated and embedded within this resource/"
+"object."
+msgstr "以下資源將被複製並嵌入到該資源/對象中。"
+
+msgid "This object has no resources."
+msgstr "該對象沒有資源。"
+
msgid "Failed to load resource."
msgstr "加載資源失敗。"
+msgid "(Current)"
+msgstr "(當前)"
+
+msgid "Expand Non-Default"
+msgstr "展開非預設"
+
msgid "Property Name Style"
msgstr "屬性名稱樣式"
@@ -3746,15 +5600,27 @@ msgstr "複製資源"
msgid "Make Resource Built-In"
msgstr "轉為內建資源"
+msgid "Go to previous edited object in history."
+msgstr "跳到歷史記錄中上一個編輯的物件。"
+
+msgid "Go to next edited object in history."
+msgstr "跳至歷史記錄中下一個編輯的物件。"
+
msgid "History of recently edited objects."
msgstr "最近編輯的物件歷史記錄。"
msgid "Open documentation for this object."
msgstr "開啟該物件之說明文件。"
+msgid "Filter Properties"
+msgstr "篩選屬性s"
+
msgid "Manage object properties."
msgstr "管理物件屬性。"
+msgid "This cannot be undone. Are you sure?"
+msgstr "這不能反悔。 你確定嗎?"
+
msgid "Add %d Translations"
msgstr "新增%d項翻譯"
@@ -3776,6 +5642,18 @@ msgstr "移除資源重映射"
msgid "Remove Resource Remap Option"
msgstr "移除資源重映射選項"
+msgid "Add %d file(s) for POT generation"
+msgstr "添加 %d 個文件以生成 POT"
+
+msgid "Remove file from POT generation"
+msgstr "從 POT 生成中刪除文件"
+
+msgid "Removed"
+msgstr "已刪除"
+
+msgid "%s cannot be found."
+msgstr "找不到 %s。"
+
msgid "Translations"
msgstr "翻譯"
@@ -3794,9 +5672,36 @@ msgstr "依地區設定重映射:"
msgid "Locale"
msgstr "地區"
+msgid "POT Generation"
+msgstr "POT生成"
+
+msgid "Files with translation strings:"
+msgstr "帶有翻譯字串的文件:"
+
+msgid "Generate POT"
+msgstr "生成POT"
+
+msgid "Set %s on %d nodes"
+msgstr "設置 %s在 %d 個節點上"
+
+msgid "%s (%d Selected)"
+msgstr "%s(已選擇 %d)"
+
msgid "Select a single node to edit its signals and groups."
msgstr "選擇單一節點以編輯其訊號與群組。"
+msgid "Plugin name cannot be blank."
+msgstr "插件名稱不能為空。"
+
+msgid "Script extension must match chosen language extension (.%s)."
+msgstr "腳本擴展必須與所選語言擴展(.%s) 相同。"
+
+msgid "Subfolder name is not a valid folder name."
+msgstr "子文件夾名稱不是有效的文件夾名稱。"
+
+msgid "Subfolder cannot be one which already exists."
+msgstr "子文件夾不能是已存在的文件夾。"
+
msgid "Edit a Plugin"
msgstr "編輯外掛"
@@ -3866,9 +5771,15 @@ msgstr "載入..."
msgid "Move Node Point"
msgstr "移動節點頂點"
+msgid "Change BlendSpace1D Config"
+msgstr "更改 BlendSpace1D 配置"
+
msgid "Change BlendSpace1D Labels"
msgstr "修改 BlendSpace1D 標籤"
+msgid "This type of node can't be used. Only animation nodes are allowed."
+msgstr "不能使用這種類型的節點。 僅允許動畫節點。"
+
msgid "This type of node can't be used. Only root nodes are allowed."
msgstr "無法使用該類型的節點。僅允許根節點。"
@@ -3900,6 +5811,9 @@ msgstr "選擇並移動頂點,使用滑鼠右鍵建立頂點。"
msgid "Enable snap and show grid."
msgstr "啟用吸附並顯示網格。"
+msgid "Sync:"
+msgstr "同步:"
+
msgid "Blend:"
msgstr "混合:"
@@ -3918,6 +5832,9 @@ msgstr "已存在三角形。"
msgid "Add Triangle"
msgstr "新增三角形"
+msgid "Change BlendSpace2D Config"
+msgstr "更改 BlendSpace2D 配置"
+
msgid "Change BlendSpace2D Labels"
msgstr "修改 BlendSpace2D 標籤"
@@ -3945,6 +5862,9 @@ msgstr "自動產生混合三角形(而非手動)"
msgid "Parameter Changed:"
msgstr "已更改參數:"
+msgid "Inspect Filters"
+msgstr "檢視篩選器"
+
msgid "Output node can't be added to the blend tree."
msgstr "輸出節點無法被新增至混合樹。"
@@ -3998,6 +5918,9 @@ msgstr "音訊片段"
msgid "Functions"
msgstr "函式"
+msgid "Inspect Filtered Tracks:"
+msgstr "檢視已篩選的軌道:"
+
msgid "Edit Filtered Tracks:"
msgstr "編輯已篩選的軌道:"
@@ -4010,18 +5933,167 @@ msgstr "新增節點..."
msgid "Enable Filtering"
msgstr "啟用條件篩選"
+msgid "Library Name:"
+msgstr "函式庫名稱:"
+
+msgid "Animation name can't be empty."
+msgstr "動畫名稱不能為空。"
+
+msgid "Animation name contains invalid characters: '/', ':', ',' or '['."
+msgstr "動畫名稱包含無效字符:\"/\"、\":\"、\",\"或\"[\"。"
+
+msgid "Animation with the same name already exists."
+msgstr "同名動畫已存在。"
+
+msgid "Enter a library name."
+msgstr "輸入函式庫名稱。"
+
+msgid "Library name contains invalid characters: '/', ':', ',' or '['."
+msgstr "函式庫名稱包含無效字符:\"/\"、\":\"、\",\"或\"[\"。"
+
+msgid "Library with the same name already exists."
+msgstr "同名函式庫已存在。"
+
+msgid "Animation name is valid."
+msgstr "動畫名稱合法。"
+
+msgid "Global library will be created."
+msgstr "將創建全域函式庫。"
+
+msgid "Library name is valid."
+msgstr "函式庫名稱有效。"
+
+msgid "Add Animation to Library: %s"
+msgstr "將動畫添加到函式庫:%s"
+
+msgid "Add Animation Library: %s"
+msgstr "添加動畫庫:%s"
+
msgid "Load Animation"
msgstr "載入動畫"
+msgid ""
+"This animation library can't be saved because it does not belong to the "
+"edited scene. Make it unique first."
+msgstr "該動畫庫無法保存,因為它不屬於編輯的場景。 首先讓它獨立化。"
+
+msgid ""
+"This animation library can't be saved because it was imported from another "
+"file. Make it unique first."
+msgstr "無法保存該動畫庫,因為它是從另一個文件導入的。 請先讓它獨立化。"
+
+msgid "Save Library"
+msgstr "儲存庫"
+
+msgid "Make Animation Library Unique: %s"
+msgstr "讓動畫庫獨立化:%s"
+
+msgid ""
+"This animation can't be saved because it does not belong to the edited "
+"scene. Make it unique first."
+msgstr "該動畫無法保存,因為它不屬於編輯的場景。請先讓它獨立化。"
+
+msgid ""
+"This animation can't be saved because it was imported from another file. "
+"Make it unique first."
+msgstr "該動畫無法保存,因為它是從另一個文件導入的。 請先使其獨立化。"
+
+msgid "Save Animation"
+msgstr "儲存動畫"
+
+msgid "Make Animation Unique: %s"
+msgstr "動畫獨立化:%s"
+
+msgid "Invalid AnimationLibrary file."
+msgstr "無效動畫庫文件。"
+
+msgid "This library is already added to the player."
+msgstr "該庫早已添加到播放器中。"
+
+msgid "Invalid Animation file."
+msgstr "無效動畫文件。"
+
+msgid "This animation is already added to the library."
+msgstr "該動畫已添加到庫中。"
+
+msgid "Load Animation into Library: %s"
+msgstr "將動畫加載到庫中:%s"
+
+msgid "Save Animation library to File: %s"
+msgstr "將動畫庫保存到文件:%s"
+
+msgid "Save Animation to File: %s"
+msgstr "將動畫保存到文件:%s"
+
+msgid "Rename Animation Library: %s"
+msgstr "重命名動畫庫:%s"
+
+msgid "[Global]"
+msgstr "[全域]"
+
+msgid "Rename Animation: %s"
+msgstr "重命名動畫:%s"
+
msgid "Animation Name:"
msgstr "動畫名稱:"
+msgid "No animation resource in clipboard!"
+msgstr "剪貼板中沒有動畫資源!"
+
msgid "Pasted Animation"
msgstr "已貼上的動畫"
msgid "Open in Inspector"
msgstr "在屬性面板中開啟"
+msgid "Remove Animation Library: %s"
+msgstr "刪除動畫庫:%s"
+
+msgid "Remove Animation from Library: %s"
+msgstr "從庫中刪除動畫:%s"
+
+msgid "[built-in]"
+msgstr "[內置]"
+
+msgid "[foreign]"
+msgstr "[外部]"
+
+msgid "[imported]"
+msgstr "[匯入]"
+
+msgid "Add Animation to Library"
+msgstr "將動畫添加到庫中"
+
+msgid "Load animation from file and add to library"
+msgstr "從文件加載動畫並添加到庫中"
+
+msgid "Paste Animation to Library from clipboard"
+msgstr "將動畫從剪貼板貼上到庫"
+
+msgid "Save animation library to resource on disk"
+msgstr "將動畫庫保存到硬碟上的資源"
+
+msgid "Remove animation library"
+msgstr "刪除動畫庫"
+
+msgid "Copy animation to clipboard"
+msgstr "將動畫複製到剪貼板"
+
+msgid "Save animation to resource on disk"
+msgstr "將動畫保存到硬碟上的資源"
+
+msgid "Remove animation from Library"
+msgstr "從庫中刪除動畫"
+
+msgid "Edit Animation Libraries"
+msgstr "編輯動畫庫"
+
+msgid "Add Library"
+msgstr "添加庫"
+
+msgid "Load Library"
+msgstr "載入庫"
+
msgid "Storage"
msgstr "儲存"
@@ -4040,12 +6112,18 @@ msgstr "重新命名動畫"
msgid "Change Animation Name:"
msgstr "更改動畫名稱:"
+msgid "Delete Animation '%s'?"
+msgstr "是否刪除動畫「%s」?"
+
msgid "Remove Animation"
msgstr "移除動畫"
msgid "Invalid animation name!"
msgstr "無效的動畫名稱!"
+msgid "Animation '%s' already exists!"
+msgstr "動畫「%s」已經存在!"
+
msgid "Duplicate Animation"
msgstr "重複動畫"
@@ -4055,12 +6133,21 @@ msgstr "混合下一個更改"
msgid "Change Blend Time"
msgstr "修改混合時間"
+msgid "[Global] (create)"
+msgstr "[全局](創建)"
+
+msgid "Duplicated Animation Name:"
+msgstr "重複的動畫名稱:"
+
msgid "Play selected animation backwards from current pos. (A)"
msgstr "自目前位置開始倒放所選的動畫。 (A)"
msgid "Play selected animation backwards from end. (Shift+A)"
msgstr "自結尾倒放所選動畫。(Shift+A)"
+msgid "Pause/stop animation playback. (S)"
+msgstr "暫停/停止動畫播放。 (S)"
+
msgid "Play selected animation from start. (Shift+D)"
msgstr "從頭播放所選動畫。(Shift+D)"
@@ -4079,6 +6166,9 @@ msgstr "動畫工具"
msgid "Animation"
msgstr "動畫"
+msgid "Manage Animations..."
+msgstr "管理動畫..."
+
msgid "Edit Transitions..."
msgstr "編輯轉場..."
@@ -4124,6 +6214,9 @@ msgstr "強制使用白色調變"
msgid "Include Gizmos (3D)"
msgstr "包含 Gizmo (3D)"
+msgid "Onion Skinning temporarily disabled due to rendering bug."
+msgstr "由於渲染錯誤,洋蔥皮暫時禁用。"
+
msgid "Pin AnimationPlayer"
msgstr "固定 AnimationPlayer"
@@ -4145,6 +6238,9 @@ msgstr "移動節點"
msgid "Transition exists!"
msgstr "轉場已存在!"
+msgid "Add Node and Transition"
+msgstr "添加節點和轉換"
+
msgid "Add Transition"
msgstr "新增轉場"
@@ -4169,6 +6265,17 @@ msgstr "已刪除節點"
msgid "Transition Removed"
msgstr "已刪除轉場"
+msgid ""
+"Select and move nodes.\n"
+"RMB: Add node at position clicked.\n"
+"Shift+LMB+Drag: Connects the selected node with another node or creates a "
+"new node if you select an area without nodes."
+msgstr ""
+"選擇並移動節點。\n"
+"滑鼠右鍵:在點擊的位置添加節點。\n"
+"Shift+滑鼠左鍵+拖動:將選定的節點與另一個節點連接,或者如果選擇沒有節點的區"
+"域,則創建一個新節點。"
+
msgid "Create new nodes."
msgstr "建立新節點。"
@@ -4181,12 +6288,21 @@ msgstr "移除所選的節點或轉場。"
msgid "Transition:"
msgstr "轉場效果:"
+msgid "New Transitions Should Auto Advance"
+msgstr "新的轉場應該自動推進"
+
msgid "Play Mode:"
msgstr "播放模式:"
msgid "Delete Selected"
msgstr "刪除所選"
+msgid "Delete All"
+msgstr "刪除全部"
+
+msgid "Root"
+msgstr "根結點"
+
msgid "AnimationTree"
msgstr "動畫樹"
@@ -4259,6 +6375,9 @@ msgstr "SHA-256 雜湊檢查失敗"
msgid "Asset Download Error:"
msgstr "素材下載錯誤:"
+msgid "Ready to install!"
+msgstr "準備安裝!"
+
msgid "Downloading (%s / %s)..."
msgstr "正在下載 (%s / %s)…"
@@ -4329,6 +6448,23 @@ msgstr "最後一個"
msgid "All"
msgstr "全部"
+msgid "No results for \"%s\" for support level(s): %s."
+msgstr "找不到「%s」的結果給support level(s):%s 。"
+
+msgid ""
+"No results compatible with %s %s for support level(s): %s.\n"
+"Check the enabled support levels using the 'Support' button in the top-right "
+"corner."
+msgstr ""
+"沒有與 %s %s 兼容的 support level(s)結果:%s。\n"
+"使用右上角的「支持」按鈕檢查啟用的支持級別。"
+
+msgid "Search Templates, Projects, and Demos"
+msgstr "搜尋樣板、專案以及範例"
+
+msgid "Search Assets (Excluding Templates, Projects, and Demos)"
+msgstr "搜尋素材(不包含樣板、專案以及範例)"
+
msgid "Import..."
msgstr "匯入..."
@@ -4356,6 +6492,12 @@ msgstr "素材 ZIP 檔"
msgid "Audio Preview Play/Pause"
msgstr "音訊預先播放/暫停"
+msgid "Bone Picker:"
+msgstr "骨頭挑選器:"
+
+msgid "Clear mappings in current group."
+msgstr "清除當前組中的映射。"
+
msgid "Preview"
msgstr "預覽"
@@ -4383,6 +6525,9 @@ msgstr "旋轉步長:"
msgid "Scale Step:"
msgstr "縮放步長:"
+msgid "Move Node(s) to Position"
+msgstr "將節點移動到位置"
+
msgid "Move Vertical Guide"
msgstr "移動垂直參考線"
@@ -4411,7 +6556,7 @@ msgid "Rotate %d CanvasItems"
msgstr "旋轉 %d 個 CanvasItem"
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "旋轉 CanvasItem「%d」為 %d 度"
+msgstr "旋轉 CanvasItem「%s」為 %d 度"
msgid "Move CanvasItem \"%s\" Anchor"
msgstr "移動 CanvasItem「%s」的錨點"
@@ -4443,6 +6588,27 @@ msgstr "已組成群組"
msgid "Add Node Here"
msgstr "在此新增節點"
+msgid "Instantiate Scene Here"
+msgstr "在這裡實例化場景"
+
+msgid "Paste Node(s) Here"
+msgstr "將節點貼上到此處"
+
+msgid "Move Node(s) Here"
+msgstr "將節點移至此處"
+
+msgid "px"
+msgstr "像素"
+
+msgid "units"
+msgstr "單位"
+
+msgid "Moving:"
+msgstr "移動中:"
+
+msgid "Rotating:"
+msgstr "旋轉中:"
+
msgid "Scaling:"
msgstr "縮放:"
@@ -4479,6 +6645,9 @@ msgstr "貼上姿勢"
msgid "Clear Guides"
msgstr "清除參考線"
+msgid "Create Custom Bone2D(s) from Node(s)"
+msgstr "從節點創建自定義 Bone2D"
+
msgid "Zoom to 3.125%"
msgstr "縮放至3.125%"
@@ -4509,6 +6678,9 @@ msgstr "縮放至800%"
msgid "Zoom to 1600%"
msgstr "縮放至1600%"
+msgid "Center View"
+msgstr "中間視角"
+
msgid "Select Mode"
msgstr "選擇模式"
@@ -4542,12 +6714,19 @@ msgstr "縮放模式"
msgid "Shift: Scale proportionally."
msgstr "Shift:按比例縮放。"
+msgid "Show list of selectable nodes at position clicked."
+msgstr "在單擊的位置顯示可選節點的列表。"
+
msgid "Click to change object's rotation pivot."
msgstr "點擊以更改物件的旋轉樞紐。"
msgid "Pan Mode"
msgstr "平移模式"
+msgid ""
+"You can also use Pan View shortcut (Space by default) to pan in any mode."
+msgstr "您還可以使用“平移視圖”快捷方式(默認為“空格”)在任何模式下進行平移。"
+
msgid "Ruler Mode"
msgstr "尺規模式"
@@ -4602,15 +6781,27 @@ msgstr "吸附至其他節點"
msgid "Snap to Guides"
msgstr "吸附至參考線"
+msgid "Lock selected node, preventing selection and movement."
+msgstr "鎖定選定的節點,防止選擇和移動。"
+
msgid "Lock Selected Node(s)"
msgstr "鎖定所選的節點"
+msgid "Unlock selected node, allowing selection and movement."
+msgstr "解鎖選定的節點,允許選擇和移動。"
+
msgid "Unlock Selected Node(s)"
msgstr "取消鎖定所選的節點"
+msgid "Make selected node's children not selectable."
+msgstr "使選定節點的子節點不可選擇。"
+
msgid "Group Selected Node(s)"
msgstr "為所選的節點建立群組"
+msgid "Make selected node's children selectable."
+msgstr "使選定節點的子節點可選擇。"
+
msgid "Ungroup Selected Node(s)"
msgstr "取消所選節點的群組"
@@ -4620,6 +6811,9 @@ msgstr "骨架選項"
msgid "Show Bones"
msgstr "顯示骨骼"
+msgid "Make Bone2D Node(s) from Node(s)"
+msgstr "從節點創建 Bone2D 節點"
+
msgid "View"
msgstr "檢視"
@@ -4656,6 +6850,9 @@ msgstr "顯示檢視區"
msgid "Show Group And Lock Icons"
msgstr "顯示群組與鎖定圖示"
+msgid "Show Transformation Gizmos"
+msgstr "顯示變形控制器"
+
msgid "Center Selection"
msgstr "置中所選"
@@ -4711,18 +6908,83 @@ msgstr "將網格步數除以 2"
msgid "Adding %s..."
msgstr "正在新增 %s…"
+msgid "Drag and drop to add as child of current scene's root node."
+msgstr "拖放以添加為當前場景根節點的子節點。"
+
+msgid "Hold Ctrl when dropping to add as child of selected node."
+msgstr "拖放時按住 Ctrl 鍵可添加為所選節點的子節點。"
+
+msgid "Hold Shift when dropping to add as sibling of selected node."
+msgstr "拖放時按住 Shift 鍵可將其添加為所選節點的同級節點。"
+
+msgid "Hold Alt when dropping to add as a different node type."
+msgstr "拖放時按住 Alt 可添加為不同的節點類型。"
+
msgid "Cannot instantiate multiple nodes without root."
msgstr "沒有根節點無法實體化多個節點。"
msgid "Create Node"
msgstr "建立節點"
+msgid "Error instantiating scene from %s"
+msgstr "從 %s 實例化場景時出錯"
+
msgid "Change Default Type"
msgstr "更改預設型別"
+msgid "Set Target Position"
+msgstr "設定目標位置"
+
msgid "Set Handle"
msgstr "設定處理程式"
+msgid "This node doesn't have a control parent."
+msgstr "該節點沒有控制母節點。"
+
+msgid ""
+"Use the appropriate layout properties depending on where you are going to "
+"put it."
+msgstr "根據要放置的位置使用適當的佈局屬性。"
+
+msgid "This node is a child of a container."
+msgstr "該節點是容器的子節點。"
+
+msgid "Use container properties for positioning."
+msgstr "使用容器屬性進行定位。"
+
+msgid "This node is a child of a regular control."
+msgstr "該節點是常規控制的子節點。"
+
+msgid "Use anchors and the rectangle for positioning."
+msgstr "使用錨點和矩形進行定位。"
+
+msgid "Collapse positioning hint."
+msgstr "折疊定位提示。"
+
+msgid "Expand positioning hint."
+msgstr "展開定位提示。"
+
+msgid "Container Default"
+msgstr "容器默認值"
+
+msgid "Fill"
+msgstr "填滿"
+
+msgid "Shrink Begin"
+msgstr "收縮開始"
+
+msgid "Shrink Center"
+msgstr "收縮中心"
+
+msgid "Shrink End"
+msgstr "收縮結尾"
+
+msgid "Custom"
+msgstr "自訂"
+
+msgid "Expand"
+msgstr "展開"
+
msgid "Top Left"
msgstr "左上"
@@ -4771,9 +7033,63 @@ msgstr "右延展"
msgid "Full Rect"
msgstr "全矩形"
+msgid ""
+"Enable to also set the Expand flag.\n"
+"Disable to only set Shrink/Fill flags."
+msgstr ""
+"啟用還可以設定展開旗標。\n"
+"禁用以僅設定收縮/填充旗標。"
+
+msgid "Some parents of the selected nodes do not support the Expand flag."
+msgstr "所選節點的某些父節點不支持擴展旗標。"
+
+msgid "Align with Expand"
+msgstr "與展開對齊"
+
+msgid "Change Anchors, Offsets, Grow Direction"
+msgstr "更改錨點、偏移、生長方向"
+
+msgid "Change Anchors, Offsets (Keep Ratio)"
+msgstr "更改錨點、偏移(保持比例)"
+
+msgid "Change Vertical Size Flags"
+msgstr "更改垂直尺寸旗標"
+
+msgid "Change Horizontal Size Flags"
+msgstr "更改水平尺寸旗標"
+
+msgid "Presets for the anchor and offset values of a Control node."
+msgstr "控制節點的錨點和偏移值的預設。"
+
+msgid "Anchor preset"
+msgstr "錨點預設"
+
+msgid "Set to Current Ratio"
+msgstr "設置為當前比率"
+
+msgid "Adjust anchors and offsets to match the current rect size."
+msgstr "調整錨點和偏移量以匹配當前的矩形大小。"
+
+msgid ""
+"When active, moving Control nodes changes their anchors instead of their "
+"offsets."
+msgstr "啟用後,移動控制節點將修改錨點而非外邊距。"
+
+msgid "Sizing settings for children of a Container node."
+msgstr "容器節點子節點的大小設置。"
+
+msgid "Horizontal alignment"
+msgstr "對齊水平"
+
+msgid "Vertical alignment"
+msgstr "對齊垂直"
+
msgid "Load Emission Mask"
msgstr "載入發射遮罩"
+msgid "CPUParticles2D"
+msgstr "CPU粒子2D"
+
msgid "Generated Point Count:"
msgstr "已產生的頂點數量:"
@@ -4795,18 +7111,36 @@ msgstr "自像素中捕捉"
msgid "Emission Colors"
msgstr "發射色彩"
+msgid "CPUParticles3D"
+msgstr "CPU粒子3D"
+
msgid "Create Emission Points From Node"
msgstr "自節點建立發射點"
msgid "Load Curve Preset"
msgstr "加載曲線預設設定"
+msgid "Add Curve Point"
+msgstr "添加曲線點"
+
msgid "Remove Curve Point"
msgstr "移除曲線控制點"
msgid "Modify Curve Point"
msgstr "修改曲線控制點"
+msgid "Modify Curve Point's Tangents"
+msgstr "修改曲線點的切線"
+
+msgid "Modify Curve Point's Left Tangent"
+msgstr "修改曲線點的左切線"
+
+msgid "Modify Curve Point's Right Tangent"
+msgstr "修改曲線點的右切線"
+
+msgid "Toggle Linear Curve Point's Tangent"
+msgstr "開啟/關閉線性曲線點的切線"
+
msgid "Hold Shift to edit tangents individually"
msgstr "按住 Shift 鍵以單獨編輯切線"
@@ -4865,6 +7199,14 @@ msgid ""
"3D) will be visible in the running project."
msgstr "開啟該選項後,碰撞區域與射線節點(2D 與 3D)會在專案執行時可見。"
+msgid "Visible Paths"
+msgstr "可見路徑"
+
+msgid ""
+"When this option is enabled, curve resources used by path nodes will be "
+"visible in the running project."
+msgstr "啟用此選項後,路徑節點使用的曲線資源將在專案運行中可見。"
+
msgid "Visible Navigation"
msgstr "顯示導航"
@@ -4873,6 +7215,14 @@ msgid ""
"in the running project."
msgstr "開啟該選項後,導航網格與多邊形將在專案執行時可見。"
+msgid "Visible Avoidance"
+msgstr "可見迴避"
+
+msgid ""
+"When this option is enabled, avoidance objects shapes, radius and velocities "
+"will be visible in the running project."
+msgstr "啟用此選項後,迴避對象的形狀、半徑和速度將在專案運行中可見。"
+
msgid "Synchronize Scene Changes"
msgstr "同步常見更改"
@@ -4897,6 +7247,57 @@ msgstr ""
"開啟該選項後,儲存腳本時會於執行中的遊戲內重新載入腳本。\n"
"若在遠端裝置上使用,可使用網路檔案系統 NFS 以獲得最佳效能。"
+msgid "Keep Debug Server Open"
+msgstr "保持開啟除錯工具"
+
+msgid ""
+"When this option is enabled, the editor debug server will stay open and "
+"listen for new sessions started outside of the editor itself."
+msgstr ""
+"啟用此選項後,編輯器除錯服務器將保持打開狀態並監聽在編輯器本身外部啟動的新階"
+"段。"
+
+msgid "Run Multiple Instances"
+msgstr "運行多個實例"
+
+msgid "Run %d Instance"
+msgid_plural "Run %d Instances"
+msgstr[0] "運行 %d 個實例"
+
+msgid "Size: %s"
+msgstr "大小:%s"
+
+msgid "Type: %s"
+msgstr "型別:%s"
+
+msgid "Overrides (%d)"
+msgstr "覆寫 (%d)"
+
+msgctxt "Locale"
+msgid "Add Script"
+msgstr "新增腳本"
+
+msgid "Add Locale"
+msgstr "新增地區"
+
+msgid "Variation Coordinates (%d)"
+msgstr "變化坐標 (%d)"
+
+msgid "No supported features"
+msgstr "沒有支持的功能"
+
+msgid "Features (%d of %d set)"
+msgstr "功能(%d 組,共 %d 組)"
+
+msgid "Add Feature"
+msgstr "新增功能"
+
+msgid " - Variation"
+msgstr " - 變化"
+
+msgid "Unable to preview font"
+msgstr "無法預覽字體"
+
msgid "Change AudioStreamPlayer3D Emission Angle"
msgstr "更改 AudioStreamPlayer3D 發射角"
@@ -4909,6 +7310,9 @@ msgstr "更改相機尺寸"
msgid "Change Sphere Shape Radius"
msgstr "更改球形半徑"
+msgid "Change Box Shape Size"
+msgstr "改變盒子形狀尺寸"
+
msgid "Change Capsule Shape Radius"
msgstr "更改楕圓形半徑"
@@ -4921,24 +7325,60 @@ msgstr "更改圓柱形半徑"
msgid "Change Cylinder Shape Height"
msgstr "更改圓柱形高度"
+msgid "Change Separation Ray Shape Length"
+msgstr "更改分離射線形狀長度"
+
+msgid "Change Decal Size"
+msgstr "更改貼花尺寸"
+
+msgid "Change Fog Volume Size"
+msgstr "更改霧體積大小"
+
msgid "Change Particles AABB"
msgstr "更改粒子 AABB"
+msgid "Change Radius"
+msgstr "更改半徑"
+
msgid "Change Light Radius"
msgstr "更改光照半徑"
+msgid "Start Location"
+msgstr "起始位置"
+
+msgid "End Location"
+msgstr "結束位置"
+
+msgid "Change Start Position"
+msgstr "更改起始位置"
+
+msgid "Change End Position"
+msgstr "更改結束位置"
+
+msgid "Change Probe Size"
+msgstr "更改探查大小"
+
msgid "Change Notifier AABB"
msgstr "更改通知器 AABB"
msgid "Convert to CPUParticles2D"
msgstr "轉換為 CPUParticles2D"
+msgid "Generating Visibility Rect (Waiting for Particle Simulation)"
+msgstr "生成可見性矩形(等待粒子模擬)"
+
msgid "Generate Visibility Rect"
msgstr "產生矩形可見性"
+msgid "Can only set point into a ParticleProcessMaterial process material"
+msgstr "僅可設為指向 ProticlesMaterial 處理材料"
+
msgid "Clear Emission Mask"
msgstr "清除發射遮罩"
+msgid "GPUParticles2D"
+msgstr "GPUParticles2D"
+
msgid "Generation Time (sec):"
msgstr "產生時間(秒):"
@@ -4948,6 +7388,9 @@ msgstr "幾何體的面未包含任何區域。"
msgid "The geometry doesn't contain any faces."
msgstr "幾何體未包含任何面。"
+msgid "\"%s\" doesn't inherit from Node3D."
+msgstr "“%s”不繼承自 Node3D。"
+
msgid "\"%s\" doesn't contain geometry."
msgstr "「%s」未包含幾何體。"
@@ -4972,18 +7415,74 @@ msgstr "體積"
msgid "Emission Source:"
msgstr "發射源:"
+msgid "A processor material of type 'ParticleProcessMaterial' is required."
+msgstr "需「ParticlesMaterial」型別的處理器材質。"
+
+msgid "Convert to CPUParticles3D"
+msgstr "轉換為 CPUParticles3D"
+
+msgid "Generating Visibility AABB (Waiting for Particle Simulation)"
+msgstr "生成可見性 AABB(等待粒子模擬)"
+
msgid "Generate Visibility AABB"
msgstr "產生可見性 AABB"
+msgid "GPUParticles3D"
+msgstr "GPUParticles3D"
+
+msgid "Generate AABB"
+msgstr "產生 AABB"
+
+msgid "Low"
+msgstr "低"
+
+msgid "Moderate"
+msgstr "中"
+
+msgid "High"
+msgstr "高"
+
+msgid "Subdivisions: %s"
+msgstr "細分:%s"
+
+msgid "Cell size: %s"
+msgstr "區格大小:%s"
+
+msgid "Video RAM size: %s MB (%s)"
+msgstr "VRAM 大小:%s MB (%s)"
+
+msgid "Bake SDF"
+msgstr "烘焙SDF"
+
+msgid ""
+"No faces detected during GPUParticlesCollisionSDF3D bake.\n"
+"Check whether there are visible meshes matching the bake mask within its "
+"extents."
+msgstr ""
+"GPUParticlesCollisionSDF3D 烘焙期間未檢測到人臉。\n"
+"檢查其範圍內是否存在與烘焙蒙版相匹配的可見網格。"
+
+msgid "Select path for SDF Texture"
+msgstr "選擇 SDF 紋理的路徑"
+
msgid "Gradient Edited"
msgstr "漸層編輯"
+msgid "Reverse/mirror gradient."
+msgstr "反向/鏡像漸變。"
+
+msgid "Move GradientTexture2D Fill Point"
+msgstr "移動 GradientTexture2D 的填充點"
+
msgid "Swap GradientTexture2D Fill Points"
msgstr "交換 GradientTexture2D 的填充點"
msgid "Swap Gradient Fill Points"
msgstr "交換 Gradient 填充點"
+msgid "Configure"
+msgstr "設定選項"
+
msgid "Create Occluder Polygon"
msgstr "建立遮光多邊形"
@@ -4994,9 +7493,21 @@ msgstr ""
"無法判斷光照圖的儲存路徑。\n"
"請儲存場景並重試。"
+msgid ""
+"No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake "
+"Light' flag is on."
+msgstr ""
+"沒有要烘烤的網格。 確保它們包含 UV2 通道並且「Bake Light」標誌處於打開狀態。"
+
msgid "Failed creating lightmap images, make sure path is writable."
msgstr "建立光照圖失敗,請確保該路徑可寫入。"
+msgid "No editor scene root found."
+msgstr "未找到編輯器場景根。"
+
+msgid "Lightmap data is not local to the scene."
+msgstr "光照貼圖數據不是場景本地的。"
+
msgid "Bake Lightmaps"
msgstr "烘焙光照圖"
@@ -5045,18 +7556,52 @@ msgstr "建立多個凸面形狀"
msgid "Create Navigation Mesh"
msgstr "建立導航網格"
+msgid "Create Debug Tangents"
+msgstr "產生除錯切線"
+
msgid "Contained Mesh is not of type ArrayMesh."
msgstr "包含之 Mesh 並非 ArrayMesh 型別。"
+msgid ""
+"Mesh cannot unwrap UVs because it does not belong to the edited scene. Make "
+"it unique first."
+msgstr "網格無法展開 UV,因為它不屬於已編輯的場景。請先使其獨立化。"
+
+msgid ""
+"Mesh cannot unwrap UVs because it belongs to another resource which was "
+"imported from another file type. Make it unique first."
+msgstr ""
+"網格無法展開 UV,因為它屬於從其他文件類型導入的另一個資源。 首先讓它獨立化。"
+
+msgid ""
+"Mesh cannot unwrap UVs because it was imported from another file type. Make "
+"it unique first."
+msgstr "網格無法展開 UV,因為它是從其他文件類型導入的。請先使其獨立化。"
+
msgid "UV Unwrap failed, mesh may not be manifold?"
msgstr "UV 展開失敗,該網格可能並非流形?"
+msgid "Unwrap UV2"
+msgstr "展開 UV2"
+
msgid "No mesh to debug."
msgstr "沒有可進行偵錯之網格。"
msgid "Mesh has no UV in layer %d."
msgstr "模型在%d圖層上無UV。"
+msgid "MeshInstance3D lacks a Mesh."
+msgstr "MeshInstance 未包含 Mesh。"
+
+msgid "Mesh has no surface to create outlines from."
+msgstr "網格沒有可用來創建輪廓的表面。"
+
+msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES."
+msgstr "Mesh 的原始類型並非 PRIMITIVE_TRIANGLES。"
+
+msgid "Could not create outline."
+msgstr "無法建立輪廓。"
+
msgid "Create Outline"
msgstr "建立輪廓"
@@ -5066,6 +7611,14 @@ msgstr "網格"
msgid "Create Trimesh Static Body"
msgstr "建立三角網格靜態形體"
+msgid ""
+"Creates a StaticBody3D and assigns a polygon-based collision shape to it "
+"automatically.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+"建立 StaticBody 並自動指派一個基於多邊形的碰撞形體。\n"
+"對於碰撞偵測,該選項為最精確(但最慢)的選項。"
+
msgid "Create Trimesh Collision Sibling"
msgstr "建立三角網格碰撞同級"
@@ -5111,6 +7664,15 @@ msgstr ""
msgid "Create Outline Mesh..."
msgstr "建立輪廓網格..."
+msgid ""
+"Creates a static outline mesh. The outline mesh will have its normals "
+"flipped automatically.\n"
+"This can be used instead of the StandardMaterial Grow property when using "
+"that property isn't possible."
+msgstr ""
+"建立靜態輪廓網格。輪廓網格的法線會自動翻轉。\n"
+"當無法使用 SpatialMetarial 的 Grow 屬性時,可以使用該屬性來代替該屬性。"
+
msgid "View UV1"
msgstr "檢視 UV1"
@@ -5172,6 +7734,9 @@ msgstr "未指定網格來源(且 MultiMesh 未包含 Mesh)。"
msgid "Mesh source is invalid (invalid path)."
msgstr "網格來源無效(無效的路徑)。"
+msgid "Mesh source is invalid (not a MeshInstance3D)."
+msgstr "網格來源無效(非 MeshInstance3D)。"
+
msgid "Mesh source is invalid (contains no Mesh resource)."
msgstr "網格來源無效(未包含 Mesh 資源)。"
@@ -5232,6 +7797,18 @@ msgstr "數量:"
msgid "Populate"
msgstr "填充"
+msgid "Set start_position"
+msgstr "設置起始位置"
+
+msgid "Set end_position"
+msgstr "設置結束位置"
+
+msgid "Set NavigationObstacle3D Vertices"
+msgstr "設置 NavigationObstacle3D 頂點"
+
+msgid "Edit Vertices"
+msgstr "編輯頂點"
+
msgid "Edit Poly"
msgstr "編輯多邊形"
@@ -5304,12 +7881,51 @@ msgstr "Z 軸變換。"
msgid "View Plane Transform."
msgstr "檢視平面轉換。"
+msgid "YZ-Plane Transform."
+msgstr "YZ 平面變換。"
+
+msgid "XZ-Plane Transform."
+msgstr "XZ-平面變換。"
+
+msgid "XY-Plane Transform."
+msgstr "XY-平面變換。"
+
msgid "Keying is disabled (no key inserted)."
msgstr "鍵已被禁用(未插入鍵)。"
msgid "Animation Key Inserted."
msgstr "已插入動畫鍵。"
+msgid "X: %s\n"
+msgstr "X:%s\n"
+
+msgid "Y: %s\n"
+msgstr "Y:%s\n"
+
+msgid "Z: %s\n"
+msgstr "Z:%s\n"
+
+msgid "Size: %s (%.1fMP)\n"
+msgstr "大小:%s (%.1fMP)\n"
+
+msgid "Objects: %d\n"
+msgstr "物件ID:%d\n"
+
+msgid "Primitives: %d\n"
+msgstr "Primitives:%d\n"
+
+msgid "Draw Calls: %d"
+msgstr "繪製呼叫:%d"
+
+msgid "CPU Time: %s ms"
+msgstr "CPU 時間:%s 毫秒"
+
+msgid "GPU Time: %s ms"
+msgstr "GPU 時間:%s 毫秒"
+
+msgid "FPS: %d"
+msgstr "FPS: %d"
+
msgid "Top View."
msgstr "俯視圖。"
@@ -5334,6 +7950,15 @@ msgstr "將變換與視圖對齊"
msgid "Align Rotation with View"
msgstr "將旋轉與視圖對齊"
+msgid "Set Surface %d Override Material"
+msgstr "設置表面 %d 覆蓋材質"
+
+msgid "Set Material Override"
+msgstr "設置材質覆蓋"
+
+msgid "Cannot drag and drop into multiple selected nodes."
+msgstr "無法拖放到多個選定節點中。"
+
msgid "None"
msgstr "無"
@@ -5364,9 +7989,78 @@ msgstr "顯示線框"
msgid "Display Overdraw"
msgstr "顯示過度繪圖"
+msgid "Display Lighting"
+msgstr "展示照明"
+
msgid "Display Unshaded"
msgstr "顯示無陰影"
+msgid "Directional Shadow Splits"
+msgstr "定向陰影分割"
+
+msgid "Normal Buffer"
+msgstr "法線緩衝"
+
+msgid "Shadow Atlas"
+msgstr "陰影合集"
+
+msgid "Directional Shadow Map"
+msgstr "定向陰影貼圖"
+
+msgid "Decal Atlas"
+msgstr "貼花圖集"
+
+msgid "VoxelGI Lighting"
+msgstr "VoxelGI 光照"
+
+msgid "VoxelGI Albedo"
+msgstr "VoxelGI 反照率"
+
+msgid "VoxelGI Emission"
+msgstr "VoxelGI 發光"
+
+msgid "SDFGI Cascades"
+msgstr "SDFGI 瀑布(Cascades)"
+
+msgid "SDFGI Probes"
+msgstr "SDFGI 探針"
+
+msgid "Scene Luminance"
+msgstr "場景亮度"
+
+msgid "SSAO"
+msgstr "SSAO(螢幕空間環境光遮蔽)"
+
+msgid "SSIL"
+msgstr "SSIL(螢幕空間間接照明)"
+
+msgid "VoxelGI/SDFGI Buffer"
+msgstr "VoxelGI/SDFGI 緩衝"
+
+msgid "Disable Mesh LOD"
+msgstr "禁用網格 LOD"
+
+msgid "OmniLight3D Cluster"
+msgstr "OmniLight3D 集群"
+
+msgid "SpotLight3D Cluster"
+msgstr "SpotLight3D 集群"
+
+msgid "Decal Cluster"
+msgstr "貼花(Decal) 集群"
+
+msgid "ReflectionProbe Cluster"
+msgstr "ReflectionProbe集群"
+
+msgid "Occlusion Culling Buffer"
+msgstr "遮擋剔除緩衝"
+
+msgid "Motion Vectors"
+msgstr "運動向量"
+
+msgid "Display Advanced..."
+msgstr "顯示進階..."
+
msgid "View Environment"
msgstr "檢視環境"
@@ -5376,6 +8070,9 @@ msgstr "檢視 Gizmo"
msgid "View Information"
msgstr "檢視資訊"
+msgid "View Frame Time"
+msgstr "查看幀時間"
+
msgid "Half Resolution"
msgstr "半解析度"
@@ -5388,6 +8085,9 @@ msgstr "啟用都卜勒效應"
msgid "Cinematic Preview"
msgstr "效果預覽"
+msgid "Not available when using the OpenGL renderer."
+msgstr "使用 OpenGL 渲染器時不可用。"
+
msgid "Freelook Left"
msgstr "自由觀看 左"
@@ -5412,6 +8112,36 @@ msgstr "自由觀看速度調整"
msgid "Freelook Slow Modifier"
msgstr "自由觀看減速調整"
+msgid "Lock Transformation to X axis"
+msgstr "將變換鎖定到 X 軸"
+
+msgid "Lock Transformation to Y axis"
+msgstr "將變換鎖定到 Y 軸"
+
+msgid "Lock Transformation to Z axis"
+msgstr "將變換鎖定到 Z 軸"
+
+msgid "Lock Transformation to YZ plane"
+msgstr "將變換鎖定到YZ 平面"
+
+msgid "Lock Transformation to XZ plane"
+msgstr "將變換鎖定到 XZ 平面"
+
+msgid "Lock Transformation to XY plane"
+msgstr "將變換鎖定到 XY 平面"
+
+msgid "Cancel Transformation"
+msgstr "取消變換"
+
+msgid "Begin Translate Transformation"
+msgstr "開始翻譯轉換"
+
+msgid "Begin Rotate Transformation"
+msgstr "開始旋轉變換"
+
+msgid "Begin Scale Transformation"
+msgstr "開始大小變換"
+
msgid "Toggle Camera Preview"
msgstr "開啟/關閉相機預覽"
@@ -5422,6 +8152,16 @@ msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr "若要再繼續放大,請至 [檢視] -> [設定...] 修改攝影機的剪裁平面"
+msgid "Overriding material..."
+msgstr "覆寫材質..."
+
+msgid ""
+"Drag and drop to override the material of any geometry node.\n"
+"Hold Ctrl when dropping to override a specific surface."
+msgstr ""
+"拖放以覆蓋任何幾何節點的材質。\n"
+"放下時按住 Ctrl 鍵可覆蓋特定表面。"
+
msgid "XForm Dialog"
msgstr "XForm 對話框"
@@ -5444,12 +8184,58 @@ msgstr "移動節點至地面"
msgid "Couldn't find a solid floor to snap the selection to."
msgstr "找不到可吸附所選項目的堅固地板 (Solid Floor)。"
+msgid "Add Preview Sun to Scene"
+msgstr "將預覽太陽添加到場景中"
+
+msgid "Add Preview Environment to Scene"
+msgstr "將預覽環境添加到場景"
+
+msgid ""
+"Scene contains\n"
+"DirectionalLight3D.\n"
+"Preview disabled."
+msgstr ""
+"場景包含\n"
+"DirectionalLight3D。\n"
+"預覽已禁用。"
+
+msgid "Preview disabled."
+msgstr "禁用預覽。"
+
+msgid ""
+"Scene contains\n"
+"WorldEnvironment.\n"
+"Preview disabled."
+msgstr ""
+"場景包含\n"
+"WorldEnvironment。\n"
+"預覽已禁用。"
+
msgid "Use Local Space"
msgstr "使用本機空間"
msgid "Use Snap"
msgstr "使用吸附"
+msgid ""
+"Toggle preview sunlight.\n"
+"If a DirectionalLight3D node is added to the scene, preview sunlight is "
+"disabled."
+msgstr ""
+"切換預覽陽光。\n"
+"如果將 DirectionalLight3D 節點添加到場景中,預覽陽光將被禁用。"
+
+msgid ""
+"Toggle preview environment.\n"
+"If a WorldEnvironment node is added to the scene, preview environment is "
+"disabled."
+msgstr ""
+"切換預覽環境。\n"
+"如果將 WorldEnvironment 節點添加到場景中,預覽環境將被禁用。"
+
+msgid "Edit Sun and Environment settings."
+msgstr "編輯太陽和環境設置。"
+
msgid "Bottom View"
msgstr "仰視圖"
@@ -5591,9 +8377,102 @@ msgstr "前置"
msgid "Post"
msgstr "後置"
+msgid "Preview Sun"
+msgstr "預覽太陽"
+
+msgid "Sun Direction"
+msgstr "太陽方向"
+
+msgid "Angular Altitude"
+msgstr "角高度"
+
+msgid "Azimuth"
+msgstr "方位角"
+
msgid "Sun Color"
msgstr "太陽顏色"
+msgid "Sun Energy"
+msgstr "太陽能量"
+
+msgid "Shadow Max Distance"
+msgstr "陰影最大距離"
+
+msgid "Add Sun to Scene"
+msgstr "將太陽添加到場景中"
+
+msgid ""
+"Adds a DirectionalLight3D node matching the preview sun settings to the "
+"current scene.\n"
+"Hold Shift while clicking to also add the preview environment to the current "
+"scene."
+msgstr ""
+"將與預覽太陽設置匹配的 DirectionalLight3D 節點添加到當前場景。\n"
+"按住 Shift 鍵同時單擊也可將預覽環境添加到當前場景。"
+
+msgid "Preview Environment"
+msgstr "預覽環境"
+
+msgid "Sky Color"
+msgstr "天空顏色"
+
+msgid "Ground Color"
+msgstr "地面顏色"
+
+msgid "Sky Energy"
+msgstr "天空能量"
+
+msgid "AO"
+msgstr "AO(環境光遮蔽)"
+
+msgid "Glow"
+msgstr "發光"
+
+msgid "Tonemap"
+msgstr "色調圖"
+
+msgid "GI"
+msgstr "GI"
+
+msgid "Post Process"
+msgstr "後處理(Post Process)"
+
+msgid "Add Environment to Scene"
+msgstr "將環境添加到場景"
+
+msgid ""
+"Adds a WorldEnvironment node matching the preview environment settings to "
+"the current scene.\n"
+"Hold Shift while clicking to also add the preview sun to the current scene."
+msgstr ""
+"將與預覽環境設置匹配的 WorldEnvironment 節點添加到當前場景。\n"
+"按住 Shift 鍵同時單擊也可將預覽太陽添加到當前場景。"
+
+msgid ""
+"Can't determine a save path for the occluder.\n"
+"Save your scene and try again."
+msgstr ""
+"無法判斷遮擋物的儲存路徑。\n"
+"請儲存場景並重試。"
+
+msgid ""
+"No meshes to bake.\n"
+"Make sure there is at least one MeshInstance3D node in the scene whose "
+"visual layers are part of the OccluderInstance3D's Bake Mask property."
+msgstr ""
+"沒有要烘烤的網格。\n"
+"確保場景中至少有一個 MeshInstance3D 節點,其視覺層是 OcclusionrInstance3D 的 "
+"Bake Mask 屬性的一部分。"
+
+msgid "Could not save the new occluder at the specified path:"
+msgstr "無法在指定路徑保存新遮擋物:"
+
+msgid "Bake Occluders"
+msgstr "烘焙遮擋物"
+
+msgid "Select occluder bake file:"
+msgstr "選擇遮擋器烘焙文件:"
+
msgid "Remove Point from Curve"
msgstr "自曲線中刪除控制點"
@@ -5894,6 +8773,12 @@ msgstr "無法載入檔案於:"
msgid "Save File As..."
msgstr "另存檔案為..."
+msgid "Can't obtain the script for reloading."
+msgstr "無法取得重新加載的腳本。"
+
+msgid "Reload only takes effect on tool scripts."
+msgstr "Reload僅對工具腳本生效。"
+
msgid "Can't obtain the script for running."
msgstr "無法取得要執行的腳本。"
@@ -5919,6 +8804,9 @@ msgstr "保存錯誤"
msgid "Save Theme As..."
msgstr "儲存主題為..."
+msgid "Unsaved file."
+msgstr "未保存的文件。"
+
msgid "%s Class Reference"
msgstr "%s 類別參照"
@@ -5928,6 +8816,9 @@ msgstr "尋找下一個"
msgid "Find Previous"
msgstr "尋找上一個"
+msgid "Filter Scripts"
+msgstr "篩選腳本s"
+
msgid "Toggle alphabetical sorting of the method list."
msgstr "開啟/關閉按照字母順序排列方法列表。"
@@ -5952,6 +8843,9 @@ msgstr "重新打開關閉的腳本"
msgid "Save All"
msgstr "全部儲存"
+msgid "Soft Reload Tool Script"
+msgstr "軟重啟工具腳本"
+
msgid "Copy Script Path"
msgstr "複製腳本路徑"
@@ -6000,6 +8894,9 @@ msgstr "跳至上一個編輯的文件。"
msgid "Go to next edited document."
msgstr "跳至下一個編輯的文件。"
+msgid "Make the script editor floating."
+msgstr "使腳本編輯器浮動。"
+
msgid "Discard"
msgstr "放棄"
@@ -6019,6 +8916,12 @@ msgstr "清除最近開啟的腳本"
msgid "Standard"
msgstr "標準"
+msgid "Plain Text"
+msgstr "純文本"
+
+msgid "JSON"
+msgstr "JSON"
+
msgid "Connections to method:"
msgstr "連接至方法:"
@@ -6028,6 +8931,9 @@ msgstr "來源"
msgid "Target"
msgstr "目標"
+msgid "Error at (%d, %d):"
+msgstr "錯誤位於(%d,%d):"
+
msgid ""
"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
msgstr "找不到方法「%s」(自訊號「%s」),節點「%s」至「%s」的連接已中斷。"
@@ -6044,6 +8950,9 @@ msgstr "跳至函式"
msgid "Only resources from filesystem can be dropped."
msgstr "只可拖放來自檔案系統的資源。"
+msgid "Can't drop nodes without an open scene."
+msgstr "在沒有開放場景的情況下無法刪除節點。"
+
msgid "Can't drop nodes because script '%s' is not used in this scene."
msgstr "無法放置節點,由於腳本「%s」並未在該場景中使用。"
@@ -6053,6 +8962,12 @@ msgstr "搜尋符號"
msgid "Pick Color"
msgstr "選擇顏色"
+msgid "Folding"
+msgstr "折疊"
+
+msgid "Indentation"
+msgstr "縮 排"
+
msgid "Uppercase"
msgstr "大寫"
@@ -6077,6 +8992,9 @@ msgstr "跳至"
msgid "Delete Line"
msgstr "删除行"
+msgid "Unindent"
+msgstr "不縮 排"
+
msgid "Toggle Comment"
msgstr "註解/取消註解"
@@ -6092,6 +9010,9 @@ msgstr "展開所有行"
msgid "Evaluate Selection"
msgstr "取值所選內容"
+msgid "Toggle Word Wrap"
+msgstr "切換自動換行"
+
msgid "Trim Trailing Whitespace"
msgstr "移除後方空白字元"
@@ -6143,6 +9064,49 @@ msgstr "跳至下一個中斷點"
msgid "Go to Previous Breakpoint"
msgstr "跳至上一個中斷點"
+msgid "Shader Editor"
+msgstr "著色器編輯器"
+
+msgid "New Shader Include"
+msgstr "新著色器包含"
+
+msgid "Load Shader File"
+msgstr "載入著色器文件"
+
+msgid "Load Shader Include File"
+msgstr "加載包含著色器文件"
+
+msgid "Save File"
+msgstr "儲存 檔案"
+
+msgid "Save File As"
+msgstr "另存檔案為"
+
+msgid "Open File in Inspector"
+msgstr "在檢視面板中開啟檔案"
+
+msgid "Close File"
+msgstr "關閉檔案"
+
+msgid "Make the shader editor floating."
+msgstr "使著色器編輯器浮動。"
+
+msgid "No valid shader stages found."
+msgstr "未找到有效的著色器階段。"
+
+msgid "Shader stage compiled without errors."
+msgstr "著色器階段編譯沒有錯誤。"
+
+msgid ""
+"File structure for '%s' contains unrecoverable errors:\n"
+"\n"
+msgstr ""
+"“%s”的文件結構包含不可恢復的錯誤:\n"
+"\n"
+
+msgid "ShaderFile"
+msgstr "著色器檔案"
+
msgid "This skeleton has no bones, create some children Bone2D nodes."
msgstr "此骨架未包含骨骼,請建立一些子 Bone2D 節點。"
@@ -6152,18 +9116,85 @@ msgstr "設定靜止姿勢至骨骼"
msgid "Create Rest Pose from Bones"
msgstr "自骨骼建立靜止姿勢"
+msgid "Skeleton2D"
+msgstr "Skeleton 2D"
+
msgid "Reset to Rest Pose"
msgstr "重新設定為靜止姿勢"
msgid "Overwrite Rest Pose"
msgstr "覆蓋靜止姿勢"
+msgid "Set Bone Transform"
+msgstr "設置骨骼變換"
+
+msgid "Set Bone Rest"
+msgstr "設置骨頭休息姿勢"
+
+msgid "Cannot create a physical skeleton for a Skeleton3D node with no bones."
+msgstr "無法為沒有骨骼的 Skeleton3D 節點創建物理骨架。"
+
msgid "Create physical bones"
msgstr "建立物理骨骼"
+msgid "Cannot export a SkeletonProfile for a Skeleton3D node with no bones."
+msgstr "無法導出沒有骨骼的 Skeleton3D 節點的 SkeletonProfile。"
+
+msgid "Export Skeleton Profile As..."
+msgstr "將骨架設定檔導出為..."
+
+msgid "Set Bone Parentage"
+msgstr "設置骨骼繼承"
+
+msgid "Skeleton3D"
+msgstr "Skeleton 3D"
+
+msgid "Reset All Bone Poses"
+msgstr "重置所有骨骼姿勢"
+
+msgid "Reset Selected Poses"
+msgstr "重置選定的骨頭姿勢"
+
+msgid "Apply All Poses to Rests"
+msgstr "將所有姿勢變休息"
+
+msgid "Apply Selected Poses to Rests"
+msgstr "將選定的姿勢變休息"
+
+msgid "Create Physical Skeleton"
+msgstr "建立物理骨架"
+
+msgid "Export Skeleton Profile"
+msgstr "匯出骨骼設定檔"
+
+msgid ""
+"Edit Mode\n"
+"Show buttons on joints."
+msgstr ""
+"編輯模式\n"
+"在關節上顯示按鈕。"
+
+msgid "Insert key of bone poses already exist track."
+msgstr "插入骨骼姿勢的關鍵幀已經存在軌道。"
+
+msgid "Insert key of all bone poses."
+msgstr "插入所有骨骼姿勢的關鍵幀。"
+
+msgid "Insert Key (All Bones)"
+msgstr "插入關鍵幀(所有骨骼)"
+
+msgid "Bone Transform"
+msgstr "骨骼變換"
+
msgid "Play IK"
msgstr "執行 IK"
+msgid "Create MeshInstance2D"
+msgstr "產生 MeshInstance2D"
+
+msgid "MeshInstance2D Preview"
+msgstr "MeshInstance2D 預覽"
+
msgid "Create Polygon2D"
msgstr "建立 Polygon2D"
@@ -6182,6 +9213,12 @@ msgstr "建立 LightOccluder2D"
msgid "LightOccluder2D Preview"
msgstr "LightOccluder2D 預覽"
+msgid "Can't convert a Sprite2D from a foreign scene."
+msgstr "無法對外部場景的節點進行操作。"
+
+msgid "Sprite2D is empty!"
+msgstr "Sprite2D 為空!"
+
msgid "Can't convert a sprite using animation frames to mesh."
msgstr "無法使用動畫影格將 Sprite 轉換為網格。"
@@ -6209,6 +9246,9 @@ msgstr "無效的幾何圖形,無法建立遮光。"
msgid "Create LightOccluder2D Sibling"
msgstr "建立 LightOccluder2D 同級"
+msgid "Sprite2D"
+msgstr "Sprite 2D"
+
msgid "Simplification:"
msgstr "簡化:"
@@ -6263,24 +9303,114 @@ msgstr "(空)"
msgid "Animations:"
msgstr "動畫:"
+msgid "Animation Speed"
+msgstr "動畫速度"
+
+msgid "Filter Animations"
+msgstr "篩選 動畫"
+
+msgid "Delete Animation"
+msgstr "刪除動畫"
+
+msgid "This resource does not have any animations."
+msgstr "該資源沒有任何動畫。"
+
msgid "Animation Frames:"
msgstr "動畫幀:"
msgid "Zoom Reset"
msgstr "重設縮放"
+msgid "Add frames from sprite sheet"
+msgstr "自 Sprite 表新增影格"
+
+msgid "Delete Frame"
+msgstr "刪除影格"
+
+msgid "Copy Frame"
+msgstr "複製影格"
+
+msgid "Insert Empty (Before Selected)"
+msgstr "在選擇前面插入空白"
+
+msgid "Insert Empty (After Selected)"
+msgstr "在選擇後面插入空白"
+
+msgid "Move Frame Left"
+msgstr "向左移動影格"
+
+msgid "Move Frame Right"
+msgstr "向右移動影格"
+
msgid "Select Frames"
msgstr "選擇影格"
+msgid "Frame Order"
+msgstr "影格順序"
+
+msgid "By Row"
+msgstr "按照行"
+
+msgid "Left to Right, Top to Bottom"
+msgstr "從左到右,從上到下"
+
+msgid "Left to Right, Bottom to Top"
+msgstr "從左到右,從下到上"
+
+msgid "Right to Left, Top to Bottom"
+msgstr "從右到左,從上到下"
+
+msgid "Right to Left, Bottom to Top"
+msgstr "從右到左,從下到上"
+
+msgid "By Column"
+msgstr "按照列"
+
+msgid "Top to Bottom, Left to Right"
+msgstr "從上到下,從左到右"
+
+msgid "Top to Bottom, Right to Left"
+msgstr "從上到下,從右到左"
+
+msgid "Bottom to Top, Left to Right"
+msgstr "從下到上,從左到右"
+
+msgid "Bottom to Top, Right to Left"
+msgstr "從下到上,從右到左"
+
+msgid "Horizontal"
+msgstr "水平方向"
+
+msgid "Vertical"
+msgstr "垂直方向"
+
msgid "Size"
msgstr "大小"
+msgid "Separation"
+msgstr "分隔方向"
+
+msgid "Offset"
+msgstr "偏移量"
+
msgid "Create Frames from Sprite Sheet"
msgstr "自 Sprite 表建立幀"
msgid "SpriteFrames"
msgstr "SpriteFrame"
+msgid "Warnings should be fixed to prevent errors."
+msgstr "應修復警告以防止錯誤。"
+
+msgid "%s Mipmaps"
+msgstr "%s Mipmap"
+
+msgid "Memory: %s"
+msgstr "記憶體:%s"
+
+msgid "No Mipmaps"
+msgstr "沒有Mipmap"
+
msgid "Set Region Rect"
msgstr "設定區域矩形 (Region Rect)"
@@ -6305,24 +9435,57 @@ msgstr "步驟:"
msgid "Separation:"
msgstr "分隔:"
+msgid "Region Editor"
+msgstr "區域編輯器"
+
+msgid "Edit Region"
+msgstr "編輯區域"
+
msgid "Styleboxes"
msgstr "樣式盒"
+msgid "1 color"
+msgid_plural "{num} colors"
+msgstr[0] "{num} 顏色"
+
msgid "No colors found."
msgstr "未找到任何顏色。"
+msgid "1 constant"
+msgid_plural "{num} constants"
+msgstr[0] "{num} 常數"
+
msgid "No constants found."
msgstr "未發現任何常數。"
+msgid "1 font"
+msgid_plural "{num} fonts"
+msgstr[0] "{num} 種字體"
+
msgid "No fonts found."
msgstr "未發現任何字體。"
+msgid "1 font size"
+msgid_plural "{num} font sizes"
+msgstr[0] "{num} 字體大小"
+
+msgid "No font sizes found."
+msgstr "未發現任何字體大小。"
+
+msgid "1 icon"
+msgid_plural "{num} icons"
+msgstr[0] "{num} 個圖標"
+
msgid "No icons found."
msgstr "未發現任何圖示。"
msgid "No styleboxes found."
msgstr "未發現樣式盒。"
+msgid "{num} currently selected"
+msgid_plural "{num} currently selected"
+msgstr[0] "目前已選擇{num}個"
+
msgid "Nothing was selected for the import."
msgstr "未選擇任何項目以匯入。"
@@ -6338,6 +9501,9 @@ msgstr "正在更新編輯器"
msgid "Finalizing"
msgstr "正在完成"
+msgid "Filter Items"
+msgstr "篩選物件"
+
msgid "With Data"
msgstr "包含數據"
@@ -6371,6 +9537,9 @@ msgstr "選擇所有可見字體項目及其資料。"
msgid "Deselect all visible font items."
msgstr "取消選擇所有可見字體項目。"
+msgid "Font sizes"
+msgstr "字型大小"
+
msgid "Select all visible icon items."
msgstr "選擇所有可見圖示項目。"
@@ -6448,6 +9617,9 @@ msgstr "移除所有常數項目"
msgid "Remove All Font Items"
msgstr "移除所有字體項目"
+msgid "Remove All Font Size Items"
+msgstr "移除所有字體大小物件"
+
msgid "Remove All Icon Items"
msgstr "移除所有圖示項目"
@@ -6461,12 +9633,21 @@ msgstr ""
"該主題類別無內容。\n"
"手動加入更多項目於其中或從另一個主題匯入。"
+msgid "Remove Theme Item"
+msgstr "移除主題物件"
+
msgid "Add Theme Type"
msgstr "新增主題型別"
+msgid "Create Theme Item"
+msgstr "新增主題物件"
+
msgid "Remove Theme Type"
msgstr "移除主題型別"
+msgid "Remove Data Type Items From Theme"
+msgstr "自主集移除所選的資料型態物件"
+
msgid "Add Color Item"
msgstr "新增顏色項目"
@@ -6593,6 +9774,15 @@ msgstr "新增項目類型"
msgid "Add Type"
msgstr "新增類別"
+msgid "Override All Default Theme Items"
+msgstr "複寫所有預設主題物件"
+
+msgid "Set Font Size Item in Theme"
+msgstr "主題中設置字體大小項目"
+
+msgid "Set Icon Item in Theme"
+msgstr "在主題中設置圖標項"
+
msgid "Set Variation Base Type"
msgstr "設定變化基礎型別"
@@ -6720,6 +9910,72 @@ msgstr "檔案無效,並非PackedScene資源。"
msgid "Reload the scene to reflect its most actual state."
msgstr "重新載入場景以反映其最新狀態。"
+msgid "Merge TileSetAtlasSource"
+msgstr "合併 TileSetAtlasSource"
+
+msgid "%s (ID: %d)"
+msgstr "%s(ID:%d)"
+
+msgid "Merge (Keep original Atlases)"
+msgstr "合併(保留原始圖集)"
+
+msgid "Next Line After Column"
+msgstr "列後下一行"
+
+msgid ""
+"Source: %d\n"
+"Atlas coordinates: %s\n"
+"Alternative: 0"
+msgstr ""
+"來源:%d\n"
+"圖集坐標:%s\n"
+"替代:0"
+
+msgid ""
+"Source: %d\n"
+"Atlas coordinates: %s\n"
+"Alternative: %d"
+msgstr ""
+"來源:%d\n"
+"圖集坐標:%s\n"
+"替代:%d"
+
+msgid "No atlas source with a valid texture selected."
+msgstr "沒有選擇有效貼圖的圖集。"
+
+msgid "Base Tiles"
+msgstr "基礎Tile"
+
+msgid "Alternative Tiles"
+msgstr "替換Tile"
+
+msgid "Reset Polygons"
+msgstr "重設多邊形"
+
+msgid "Clear Polygons"
+msgstr "清除多邊形"
+
+msgid "Rotate Polygons Right"
+msgstr "往右旋轉多邊形"
+
+msgid "Rotate Polygons Left"
+msgstr "往左旋轉多邊形"
+
+msgid "Flip Polygons Horizontally"
+msgstr "水平翻轉多邊形"
+
+msgid "Flip Polygons Vertically"
+msgstr "垂直翻轉多邊形"
+
+msgid "Edit Polygons"
+msgstr "編輯多邊形"
+
+msgid "Add polygon tool"
+msgstr "新增多邊形工具"
+
+msgid "Edit points tool"
+msgstr "編輯點工具"
+
msgid "Rotate Right"
msgstr "向右旋轉"
@@ -6732,9 +9988,60 @@ msgstr "水平翻轉"
msgid "Flip Vertically"
msgstr "垂直翻轉"
+msgid "Disable Snap"
+msgstr "禁用吸附"
+
+msgid "Half-Pixel Snap"
+msgstr "半像素吸附"
+
+msgid "Picker"
+msgstr "選擇器"
+
+msgid "No terrains"
+msgstr "沒有地形"
+
+msgid "No terrain"
+msgstr "沒地形"
+
+msgid "Painting Terrain Set"
+msgstr "繪製地形集"
+
+msgid "Painting Terrain"
+msgstr "繪製地形"
+
+msgid "No Texture Atlas Source (ID: %d)"
+msgstr "無紋理圖集源(ID:%d)"
+
+msgid "Scene Collection Source (ID: %d)"
+msgstr "場景集合源(ID:%d)"
+
+msgid "Shift+Ctrl: Draw rectangle."
+msgstr "Shift+Ctrl:畫長方形。"
+
+msgid "Toggle grid visibility."
+msgstr "檢視/隱藏網格。"
+
+msgid "Physics Layer %d"
+msgstr "物理層 %d"
+
+msgid "Navigation Layer %d"
+msgstr "導航層 %d"
+
+msgid "Custom Data %d"
+msgstr "自訂數值 %d"
+
+msgid "Select tiles."
+msgstr "所選圖塊。"
+
+msgid "No tiles selected."
+msgstr "未選擇圖塊。"
+
msgid "Yes"
msgstr "是"
+msgid "Add a Scene Tile"
+msgstr "新增場景圖塊"
+
msgid "TileSet"
msgstr "圖塊集"
@@ -6802,6 +10109,9 @@ msgstr "偵測新改動"
msgid "Discard all changes"
msgstr "捨棄所有變更"
+msgid "Permanentally delete my changes"
+msgstr "是否要永久刪除改動"
+
msgid "Stage all changes"
msgstr "預存所有變更"
@@ -6937,12 +10247,21 @@ msgstr "設定輸入預設埠口"
msgid "Add Node to Visual Shader"
msgstr "將節點新增至視覺著色器"
+msgid "Add Varying to Visual Shader: %s"
+msgstr "增加變化至視覺著色器:%s"
+
msgid "Node(s) Moved"
msgstr "已移動節點"
msgid "Visual Shader Input Type Changed"
msgstr "已修改視覺著色器輸入類型"
+msgid "Set Constant: %s"
+msgstr "設定常數:%s"
+
+msgid "Varying with that name is already exist."
+msgstr "已有名稱的操作。"
+
msgid "Vertex"
msgstr "頂點"
@@ -7438,6 +10757,9 @@ msgstr "最好幫你的專案起個名字。"
msgid "Invalid project path (changed anything?)."
msgstr "不正確的專案路徑(有修改了什麼嗎?)。"
+msgid "Couldn't save project at '%s' (error %d)."
+msgstr "無法將專案保存在“%s”(錯誤 %d)。"
+
msgid "Couldn't create project.godot in project path."
msgstr "無法在項目路徑中建立 project.godot。"
@@ -7502,6 +10824,60 @@ msgid "Can't open project at '%s'."
msgstr "無法於「%s」打開專案。"
msgid ""
+"The selected project \"%s\" does not specify its supported Godot version in "
+"its configuration file (\"project.godot\").\n"
+"\n"
+"Project path: %s\n"
+"\n"
+"If you proceed with opening it, it will be converted to Godot's current "
+"configuration file format.\n"
+"\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+"下列專案設定檔未指定建立其之 Godot 版本。\n"
+"\n"
+"%s\n"
+"\n"
+"若您繼續開啟,會將其轉換為目前 Godot 版本的組態設定檔案格式。\n"
+"\n"
+"警告:您將不再可使用舊版的 Godot 開啟該專案。"
+
+msgid ""
+"The selected project \"%s\" was generated by an older engine version, and "
+"needs to be converted for this version.\n"
+"\n"
+"Project path: %s\n"
+"\n"
+"Do you want to convert it?\n"
+"\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+"下列專案設定「%s」」是由較舊版本的 Godot 產生,需進行轉換以適用於目前版本的 "
+"Godot:\n"
+"\n"
+"%s\n"
+"\n"
+"要進行轉換嗎?\n"
+"\n"
+"警告:您將不再可使用舊版的 Godot 開啟該專案。"
+
+msgid ""
+"Can't open project \"%s\" at the following path:\n"
+"\n"
+"%s\n"
+"\n"
+"The project settings were created by a newer engine version, whose settings "
+"are not compatible with this version."
+msgstr ""
+"無法開啟專案「%s」在下列路徑:\n"
+"\n"
+"%s\n"
+"\n"
+"該專案設定是由新版本的 Godot 所建立,其設定無法相容於這個版本。"
+
+msgid ""
"Can't run project: no main scene defined.\n"
"Please edit the project and set the main scene in the Project Settings under "
"the \"Application\" category."
@@ -7658,6 +11034,15 @@ msgstr "進階選項"
msgid "Substitute"
msgstr "取代"
+msgid "Node type."
+msgstr "節點型別。"
+
+msgid "Current scene name."
+msgstr "目前場景名稱。"
+
+msgid "Root node name."
+msgstr "根節點名稱。"
+
msgid ""
"Sequential integer counter.\n"
"Compare counter options."
@@ -7671,9 +11056,15 @@ msgstr "各級別分別計數器"
msgid "If set, the counter restarts for each group of child nodes."
msgstr "若啟用則計數器將依據每組子節點重新啟動。"
+msgid "Initial value for the counter."
+msgstr "計數器起始值。"
+
msgid "Step"
msgstr "步長"
+msgid "Amount by which counter is incremented for each node."
+msgstr "各節點的計數器的增加量。"
+
msgid "Padding"
msgstr "填充"
@@ -7723,6 +11114,12 @@ msgstr "保持全域變換"
msgid "Reparent"
msgstr "重設母節點"
+msgid "File name invalid."
+msgstr "檔案名稱無效。"
+
+msgid "Root node valid."
+msgstr "根節點有效。"
+
msgid "2D Scene"
msgstr "2D 場景"
@@ -7766,7 +11163,7 @@ msgid "Make node as Root"
msgstr "將節點設為根節點"
msgid "Delete %d nodes and any children?"
-msgstr "確定要刪除節點「%s」與其子節點嗎?"
+msgstr "確定要刪除%d個節點與其子節點嗎?"
msgid "Delete %d nodes?"
msgstr "刪除 %d 個節點?"
@@ -7966,6 +11363,9 @@ msgstr "開啟腳本/選擇位置"
msgid "Open Script"
msgstr "開啟腳本"
+msgid "Inherit %s"
+msgstr "繼承 %s"
+
msgid "File exists, it will be reused."
msgstr "檔案已存在,將被重複使用。"
@@ -8063,6 +11463,9 @@ msgstr "無效的實體字典格式(位於 @path 的腳本無效)"
msgid "Invalid instance dictionary (invalid subclasses)"
msgstr "無效的實體字典(無效的子類型)"
+msgid "Path to Blender installation is valid."
+msgstr "至 Blender 安裝的路徑有效。"
+
msgid "Next Plane"
msgstr "下一個平面"
@@ -8156,12 +11559,18 @@ msgstr "開始烘焙"
msgid "Class name can't be a reserved keyword"
msgstr "類別名稱不能為保留關鍵字"
+msgid "Class name must be a valid identifier"
+msgstr "方法名稱必須為有效識別項"
+
msgid "Build Solution"
msgstr "建構解決方案"
msgid "Not enough bytes for decoding bytes, or invalid format."
msgstr "位元組長度不足以進行解碼或或格式無效。"
+msgid "Failed to load .NET runtime"
+msgstr "無法載入 .NET runtime"
+
msgid "%s/s"
msgstr "%s/秒"
@@ -8180,6 +11589,9 @@ msgstr "數量"
msgid "Network Profiler"
msgstr "網路分析工具"
+msgid "Watch"
+msgstr "觀看"
+
msgid "A NavigationMesh resource must be set or created for this node to work."
msgstr "必須先為該節點建立 NavigationMesh 資源才可運作。"
@@ -8189,6 +11601,9 @@ msgstr "製作 NavMesh"
msgid "Clear the navigation mesh."
msgstr "清除導航網格。"
+msgid "Error loading %s: %s."
+msgstr "載入 %s 時發生錯誤:%s。"
+
msgid "Package name is missing."
msgstr "缺少套件名稱。"
@@ -8225,7 +11640,7 @@ msgid "Select device from the list"
msgstr "自清單中選擇裝置"
msgid "Running on %s"
-msgstr "目前執行進度:%d"
+msgstr "目前執行:%s"
msgid "Exporting APK..."
msgstr "正在匯出APK……"
@@ -8313,6 +11728,13 @@ msgstr "無法啟動 apksigner 可執行檔案。"
msgid "'apksigner' returned with error #%d"
msgstr "「apksigner」回傳錯誤 #%d"
+msgid ""
+"output: \n"
+"%s"
+msgstr ""
+"輸出:\n"
+"%s"
+
msgid "Verifying %s..."
msgstr "正在驗證 %s…"
@@ -8387,7 +11809,7 @@ msgstr ""
"預設設定中取消勾選遺失的架構。"
msgid "Adding files..."
-msgstr "正在加入檔案 %s……"
+msgstr "正在加入檔案..."
msgid "Could not export project files."
msgstr "無法匯出專案檔。"
@@ -8410,6 +11832,12 @@ msgstr "缺少識別符。"
msgid "The character '%s' is not allowed in Identifier."
msgstr "字元「%s」不可用於識別符中。"
+msgid "Failed to open executable file \"%s\"."
+msgstr "無法打開執行檔「%s」。"
+
+msgid "Failed to create \"%s\" subfolder."
+msgstr "無法新增「%s」子資料夾。"
+
msgid "Invalid executable file."
msgstr "無效的執行檔。"
@@ -8512,6 +11940,12 @@ msgstr "資源修改"
msgid "Failed to rename temporary file \"%s\"."
msgstr "無法重新命名模板檔案 「%s」。"
+msgid "Invalid file version."
+msgstr "無效的檔案版本。"
+
+msgid "Invalid product version."
+msgstr "無效的產品版本。"
+
msgid "Invalid identity type."
msgstr "身份類型無效。"
@@ -8613,6 +12047,26 @@ msgid ""
"This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."
msgstr "該骨骼缺少適當的「靜止姿勢」。請跳至 Skeleton2D 節點並進行設定。"
+msgid ""
+"CollisionPolygon3D only serves to provide a collision shape to a "
+"CollisionObject3D derived node.\n"
+"Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, "
+"CharacterBody3D, etc. to give them a shape."
+msgstr ""
+"CollisionPolygon3D 僅可為 CollisionObject3D 衍生的節點提供碰撞形狀資訊。\n"
+"請僅於 Area3D, StaticBody3D, RigidBody3D, CharacterBody3D…等節點下作為子節點"
+"使用。"
+
+msgid ""
+"CollisionShape3D only serves to provide a collision shape to a "
+"CollisionObject3D derived node.\n"
+"Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, "
+"CharacterBody3D, etc. to give them a shape."
+msgstr ""
+"CollisionShape3D 僅可為 CollisionObject3D 衍生的節點提供碰撞形狀資訊。\n"
+"請僅於 Area3D, StaticBody3D, RigidBody3D, CharacterBody3D…等節點下作為子節點"
+"使用以提供形狀。"
+
msgid "Nothing is visible because no mesh has been assigned."
msgstr "由於尚未指定網格,未顯示任何東西。"
@@ -8663,6 +12117,13 @@ msgstr "連接至 AnimationPlayer 的路徑並未連接至 AnimationPlayer 節
msgid "The AnimationPlayer root node is not a valid node."
msgstr "AnimationPlayer 的根節點並非有效節點。"
+msgid ""
+"Color: #%s\n"
+"LMB: Apply color"
+msgstr ""
+"色彩: #%s\n"
+"左鍵點擊:設定色彩"
+
msgid "Switch between hexadecimal and code values."
msgstr "在 16 進位與代碼值之間切換。"
@@ -8725,6 +12186,13 @@ msgid ""
msgstr "Viewport長與寬必須皆大於或等於2像素才可進行算繪。"
msgid ""
+"Shader keywords cannot be used as parameter names.\n"
+"Choose another name."
+msgstr ""
+"不可使用Shader關鍵字作為參數名稱。\n"
+"挑點別的名字吧"
+
+msgid ""
"The sampler port is connected but not used. Consider changing the source to "
"'SamplerPort'."
msgstr "已連線至取樣器連結埠但並未使用。建議將來源設為「SamplerPort」。"
@@ -8756,6 +12224,12 @@ msgstr "指派至均勻。"
msgid "Constants cannot be modified."
msgstr "不可修改常數。"
+msgid "No matching constructor found for: '%s'."
+msgstr "未找到符合的建立子:「%s」。"
+
+msgid "No matching function found for: '%s'."
+msgstr "未找到符合的函式:「%s」。"
+
msgid "Invalid constant type (samplers are not allowed)."
msgstr "無效的常數型別 (不可使用取樣器)。"
diff --git a/editor/translations/properties/de.po b/editor/translations/properties/de.po
index f9dfbe3739..fd424c0e21 100644
--- a/editor/translations/properties/de.po
+++ b/editor/translations/properties/de.po
@@ -100,8 +100,8 @@ msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-26 17:31+0000\n"
-"Last-Translator: Least Significant Bite <leastsignificantbite@proton.me>\n"
+"PO-Revision-Date: 2023-07-05 13:49+0000\n"
+"Last-Translator: ‎ <artism90@googlemail.com>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot-properties/de/>\n"
"Language: de\n"
@@ -109,7 +109,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Application"
msgstr "Anwendung"
@@ -732,6 +732,9 @@ msgstr "Einstellungen übersetzen"
msgid "Scene Tabs"
msgstr "Szenen-Tabs"
+msgid "Restore Scenes on Load"
+msgstr "Szenen beim Laden wiederherstellen"
+
msgid "Inspector"
msgstr "Inspektor"
@@ -771,6 +774,12 @@ msgstr "Editorsprache"
msgid "Display Scale"
msgstr "Anzeigeskalierung"
+msgid "Editor Screen"
+msgstr "Bildschirm Editor"
+
+msgid "Project Manager Screen"
+msgstr "Bildschirm Projektverwaltung"
+
msgid "Enable Pseudolocalization"
msgstr "Aktiviere Pseudo-Lokalisierung"
@@ -783,9 +792,6 @@ msgstr "Hauptschriftgröße"
msgid "Code Font Size"
msgstr "Quellcodeschriftgröße"
-msgid "Font Hinting"
-msgstr "Font-Hinting"
-
msgid "Main Font"
msgstr "Hauptschriftart"
@@ -849,9 +855,18 @@ msgstr "Maximalbreite"
msgid "Show Script Button"
msgstr "Skriptknopf anzeigen"
+msgid "Multi Window"
+msgstr "Mehrfenster"
+
msgid "Enable"
msgstr "Aktivieren"
+msgid "Restore Windows on Load"
+msgstr "Fenster beim Laden wiederherstellen"
+
+msgid "Maximize Window"
+msgstr "Fenster maximieren"
+
msgid "Directories"
msgstr "Verzeichnisse"
@@ -972,11 +987,17 @@ msgstr "Verhalten"
msgid "Navigation"
msgstr "Navigation"
+msgid "Move Caret on Right Click"
+msgstr "Textcursor bei Rechtsklick bewegen"
+
msgid "Smooth Scrolling"
-msgstr "Glattes Skrollen"
+msgstr "Flüssiges Scrollen"
msgid "V Scroll Speed"
-msgstr "Vertikale Skrollgeschwindigkeit"
+msgstr "Vertikale Scrollgeschwindigkeit"
+
+msgid "Stay in Script Editor on Node Selected"
+msgstr "Im Skript-Editor bleiben bei Node-Selektion"
msgid "Indent"
msgstr "Einrücken"
@@ -990,6 +1011,9 @@ msgstr "Dateien"
msgid "Autosave Interval Secs"
msgstr "Autospeicherinterval (s)"
+msgid "Restore Scripts on Load"
+msgstr "Skripte beim Laden wiederherstellen"
+
msgid "Script List"
msgstr "Skriptliste"
@@ -1233,6 +1257,9 @@ msgstr "Zwiebelebenenfarbe vorher"
msgid "Onion Layers Future Color"
msgstr "Zwiebelebenenfarbe nächste"
+msgid "Restore Shaders on Load"
+msgstr "Shader beim Laden wiederherstellen"
+
msgid "Visual Editors"
msgstr "Visuelle Editoren"
@@ -5173,7 +5200,7 @@ msgid "Completion Scroll Width"
msgstr "Vervollständigung Scrollbreite"
msgid "Scroll Focus"
-msgstr "Skrollen Fokus"
+msgstr "Scrollen Fokus"
msgid "Grabber"
msgstr "Greifer"
diff --git a/editor/translations/properties/es.po b/editor/translations/properties/es.po
index e17e587157..0142497986 100644
--- a/editor/translations/properties/es.po
+++ b/editor/translations/properties/es.po
@@ -94,13 +94,15 @@
# Daniel Miranda <danmiranda@gmail.com>, 2023.
# Sebas Echazú <sebastianechazu@outlook.com>, 2023.
# Pedro Zebenzui Ortega Diaz <pipo.tf@gmail.com>, 2023.
+# Braulio León Madrid Escobar <brauliomadrid.developer@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-05-17 00:52+0000\n"
-"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
+"PO-Revision-Date: 2023-07-05 13:49+0000\n"
+"Last-Translator: Braulio León Madrid Escobar <brauliomadrid.developer@gmail."
+"com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot-properties/es/>\n"
"Language: es\n"
@@ -108,7 +110,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.18-dev\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Application"
msgstr "Aplicación"
@@ -227,6 +229,9 @@ msgstr "Esquema de bus por defecto"
msgid "General"
msgstr "General"
+msgid "Text to Speech"
+msgstr "Texto a Voz"
+
msgid "2D Panning Strength"
msgstr "Fuerza de panoramización 2D"
@@ -242,6 +247,12 @@ msgstr "Script"
msgid "Search in File Extensions"
msgstr "Buscar en Extensiones de Archivos"
+msgid "Subwindows"
+msgstr "Subventanas"
+
+msgid "Embed Subwindows"
+msgstr "Incrustar Subventanas"
+
msgid "Physics"
msgstr "Físicas"
@@ -269,6 +280,9 @@ msgstr "Depurar"
msgid "Settings"
msgstr "Configuración"
+msgid "Profiler"
+msgstr "Perfilador"
+
msgid "Max Functions"
msgstr "Funciones Máximas"
@@ -281,6 +295,9 @@ msgstr "Formatos"
msgid "Zstd"
msgstr "Zstd"
+msgid "Long Distance Matching"
+msgstr "Coincidencia de larga distancia"
+
msgid "Compression Level"
msgstr "Nivel de Compresión"
@@ -311,6 +328,12 @@ msgstr "Servidor Multihilo"
msgid "Internationalization"
msgstr "Internacionalización"
+msgid "Force Right to Left Layout Direction"
+msgstr "Forzar dirección de diseño de derecha a izquierda"
+
+msgid "Root Node Layout Direction"
+msgstr "Dirección de diseño del nodo raíz"
+
msgid "GUI"
msgstr "GUI"
@@ -341,12 +364,24 @@ msgstr "Tamaño del Bloque (KB)"
msgid "Max Size (MB)"
msgstr "Tamaño Máximo (MB)"
+msgid "Texture Upload Region Size Px"
+msgstr "Tamaño de región de carga de textura en píxeles"
+
msgid "Vulkan"
msgstr "Vulkan"
+msgid "Max Descriptors per Pool"
+msgstr "Descriptores Máximos por Grupo"
+
msgid "Textures"
msgstr "Texturas"
+msgid "Canvas Textures"
+msgstr "Textura del lienzo"
+
+msgid "Default Texture Filter"
+msgstr "Filtro de Textura Predeterminado"
+
msgid "Low Processor Usage Mode"
msgstr "Modo de Bajo Uso del Procesador"
@@ -356,6 +391,9 @@ msgstr "Modo de Bajo Uso del Procesador en Reposo (µseg)"
msgid "Print Error Messages"
msgstr "Imprimir Mensajes de Error"
+msgid "Physics Ticks per Second"
+msgstr "Ticks de física por segundo"
+
msgid "Max FPS"
msgstr "FPS Máximos"
@@ -374,12 +412,45 @@ msgstr "Usar entrada acumulada"
msgid "Input Devices"
msgstr "Dispositivos de Entrada"
+msgid "Compatibility"
+msgstr "Compatibilidad"
+
+msgid "Legacy Just Pressed Behavior"
+msgstr "Comportamiento heredado recién presionado"
+
msgid "Device"
msgstr "Dispositivo"
+msgid "Window ID"
+msgstr "ID de Ventana"
+
+msgid "Command or Control Autoremap"
+msgstr "Comando o Control de Autoremapeo"
+
+msgid "Alt Pressed"
+msgstr "Alt Presionado"
+
+msgid "Shift Pressed"
+msgstr "Shift Presionado"
+
+msgid "Ctrl Pressed"
+msgstr "Ctrl Presionado"
+
+msgid "Meta Pressed"
+msgstr "Meta Presionado"
+
msgid "Pressed"
msgstr "Presionado"
+msgid "Keycode"
+msgstr "Código de tecla"
+
+msgid "Physical Keycode"
+msgstr "Código de Tecla Física"
+
+msgid "Key Label"
+msgstr "Etiqueta de tecla"
+
msgid "Unicode"
msgstr "Unicode"
@@ -401,6 +472,9 @@ msgstr "Factor"
msgid "Button Index"
msgstr "Índice de Botones"
+msgid "Canceled"
+msgstr "Cancelado"
+
msgid "Double Click"
msgstr "Doble Clic"
@@ -428,6 +502,9 @@ msgstr "Valor de los Ejes"
msgid "Index"
msgstr "Índice"
+msgid "Double Tap"
+msgstr "Doble Toque"
+
msgid "Action"
msgstr "Acción"
@@ -455,6 +532,15 @@ msgstr "Valor del Controlador"
msgid "Shortcut"
msgstr "Atajo"
+msgid "Events"
+msgstr "Eventos"
+
+msgid "Include Navigational"
+msgstr "Incluir Navegación"
+
+msgid "Include Hidden"
+msgstr "Incluir Oculto"
+
msgid "Big Endian"
msgstr "Big Endian"
@@ -482,6 +568,9 @@ msgstr "Tamaño Máximo del Buffer de Salida"
msgid "Resource"
msgstr "Recursos"
+msgid "Local to Scene"
+msgstr "Local a Escena"
+
msgid "Path"
msgstr "Ruta"
@@ -495,11 +584,17 @@ msgid "Region"
msgstr "Región"
msgid "Offset"
-msgstr "Offset"
+msgstr "Desplazamiento"
msgid "Cell Size"
msgstr "Tamaño de la casilla"
+msgid "Jumping Enabled"
+msgstr "Salto Habilitado"
+
+msgid "Default Compute Heuristic"
+msgstr "Cálculo Heurístico Predeterminado"
+
msgid "Seed"
msgstr "Semilla"
@@ -4326,7 +4421,7 @@ msgid "Snap Distance"
msgstr "Ajustar Distancia"
msgid "Use Snap"
-msgstr "Usar Snap"
+msgstr "Usar Ajuste"
msgid "Zoom Min"
msgstr "Zoom Mínimo"
diff --git a/editor/translations/properties/ko.po b/editor/translations/properties/ko.po
index b497c52707..95d8ae237b 100644
--- a/editor/translations/properties/ko.po
+++ b/editor/translations/properties/ko.po
@@ -44,13 +44,14 @@
# 오지훈 <jule1130@naver.com>, 2023.
# coolkid <newtype20050831@gmail.com>, 2023.
# Overdue - <kaameo12@gmail.com>, 2023.
+# nulta <un5450@naver.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-12 12:27+0000\n"
-"Last-Translator: Overdue - <kaameo12@gmail.com>\n"
+"PO-Revision-Date: 2023-07-05 13:49+0000\n"
+"Last-Translator: nulta <un5450@naver.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot-properties/ko/>\n"
"Language: ko\n"
@@ -58,7 +59,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.18-dev\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Application"
msgstr "어플리케이션"
@@ -147,6 +148,9 @@ msgstr "항상 맨 위에"
msgid "Transparent"
msgstr "투명"
+msgid "Extend to Title"
+msgstr "제목 표시줄로 확장"
+
msgid "No Focus"
msgstr "포커스 없음"
@@ -174,6 +178,9 @@ msgstr "기본 버스 레이아웃"
msgid "General"
msgstr "일반"
+msgid "Text to Speech"
+msgstr "텍스트 음성 변환"
+
msgid "2D Panning Strength"
msgstr "2D 패닝 강도"
@@ -189,12 +196,21 @@ msgstr "스크립트"
msgid "Search in File Extensions"
msgstr "파일 확장자로 찾기"
+msgid "Subwindows"
+msgstr "보조 창"
+
+msgid "Embed Subwindows"
+msgstr "보조 창 내장"
+
msgid "Physics"
msgstr "물리"
msgid "2D"
msgstr "2D"
+msgid "Run on Separate Thread"
+msgstr "다른 스레드에서 실행"
+
msgid "3D"
msgstr "3D"
@@ -225,15 +241,24 @@ msgstr "압축"
msgid "Formats"
msgstr "형식"
+msgid "Zstd"
+msgstr "Zstd"
+
msgid "Long Distance Matching"
msgstr "원거리 매칭"
msgid "Compression Level"
msgstr "압축률"
+msgid "Window Log Size"
+msgstr "창 로그 크기"
+
msgid "Zlib"
msgstr "Zlib"
+msgid "Gzip"
+msgstr "Gzip"
+
msgid "Crash Handler"
msgstr "충돌 처리기"
@@ -246,6 +271,9 @@ msgstr "렌더링"
msgid "Occlusion Culling"
msgstr "오클루전 컬링"
+msgid "BVH Build Quality"
+msgstr "BVH 빌드 품질"
+
msgid "Memory"
msgstr "메모리"
@@ -255,18 +283,33 @@ msgstr "제한"
msgid "Multithreaded Server"
msgstr "다중 스레드 서버"
+msgid "RID Pool Prealloc"
+msgstr "RID 풀 선할당"
+
msgid "Internationalization"
msgstr "국제화"
+msgid "Force Right to Left Layout Direction"
+msgstr "레이아웃 방향을 오른쪽에서 왼쪽으로 강제"
+
+msgid "Root Node Layout Direction"
+msgstr "루트 노드 레이아웃 방향"
+
msgid "GUI"
msgstr "GUI"
msgid "Timers"
msgstr "타이머"
+msgid "Incremental Search Max Interval Msec"
+msgstr "증분 검색의 최대 간격 밀리초"
+
msgid "Common"
msgstr "일반"
+msgid "Snap Controls to Pixels"
+msgstr "픽셀에 컨트롤 스냅"
+
msgid "Fonts"
msgstr "글꼴"
@@ -276,27 +319,66 @@ msgstr "동적 글꼴"
msgid "Use Oversampling"
msgstr "오버샘플링 사용"
+msgid "Rendering Device"
+msgstr "렌더링 디바이스"
+
+msgid "Staging Buffer"
+msgstr "스테이지 버퍼"
+
msgid "Block Size (KB)"
msgstr "블록 크기 (KB)"
msgid "Max Size (MB)"
msgstr "최대 크기(MB)"
+msgid "Texture Upload Region Size Px"
+msgstr "텍스쳐 업로드 영역 크기 px"
+
+msgid "Pipeline Cache"
+msgstr "파이프라인 캐시"
+
+msgid "Save Chunk Size (MB)"
+msgstr "저장 청크 크기 (MB)"
+
msgid "Vulkan"
-msgstr "벌칸"
+msgstr "Vulkan"
+
+msgid "Max Descriptors per Pool"
+msgstr "풀 당 최대 디스크립터"
msgid "Textures"
msgstr "텍스처"
+msgid "Canvas Textures"
+msgstr "캔버스 텍스처"
+
+msgid "Default Texture Filter"
+msgstr "기본 텍스처 필터"
+
+msgid "Default Texture Repeat"
+msgstr "기본 텍스처 반복"
+
msgid "Low Processor Usage Mode"
msgstr "저사양 모드"
msgid "Low Processor Usage Mode Sleep (µsec)"
msgstr "저사양 모드 슬립 (마이크로초 단위)"
+msgid "Delta Smoothing"
+msgstr "델타 스무딩"
+
msgid "Print Error Messages"
msgstr "에러 메시지 출력"
+msgid "Physics Ticks per Second"
+msgstr "초당 물리 틱"
+
+msgid "Max Physics Steps per Frame"
+msgstr "프레임당 최대 물리 스텝"
+
+msgid "Max FPS"
+msgstr "최대 FPS"
+
msgid "Time Scale"
msgstr "시간 스케일"
@@ -312,12 +394,33 @@ msgstr "누적 입력 사용"
msgid "Input Devices"
msgstr "입력 장치"
+msgid "Compatibility"
+msgstr "호환성"
+
+msgid "Legacy Just Pressed Behavior"
+msgstr "오래된 just_pressed 동작"
+
msgid "Device"
msgstr "기기"
msgid "Window ID"
msgstr "창 ID"
+msgid "Command or Control Autoremap"
+msgstr "Command와 Ctrl 자동 리매핑"
+
+msgid "Alt Pressed"
+msgstr "Alt 눌림"
+
+msgid "Shift Pressed"
+msgstr "Shift 눌림"
+
+msgid "Ctrl Pressed"
+msgstr "Ctrl 눌림"
+
+msgid "Meta Pressed"
+msgstr "Meta 눌림"
+
msgid "Pressed"
msgstr "눌림"
@@ -351,6 +454,9 @@ msgstr "공식"
msgid "Button Index"
msgstr "버튼 인덱스"
+msgid "Canceled"
+msgstr "취소됨"
+
msgid "Double Click"
msgstr "더블 클릭"
@@ -411,6 +517,9 @@ msgstr "단축키"
msgid "Events"
msgstr "이벤트"
+msgid "Include Navigational"
+msgstr "내비게이셔널 포함"
+
msgid "Include Hidden"
msgstr "숨김 파일 보이기"
@@ -462,6 +571,18 @@ msgstr "오프셋"
msgid "Cell Size"
msgstr "셀 크기"
+msgid "Jumping Enabled"
+msgstr "점핑 활성화"
+
+msgid "Default Compute Heuristic"
+msgstr "기본 연산 휴리스틱"
+
+msgid "Default Estimate Heuristic"
+msgstr "기본 추정 휴리스틱"
+
+msgid "Diagonal Mode"
+msgstr "대각선 모드"
+
msgid "Seed"
msgstr "시드"
@@ -477,6 +598,15 @@ msgstr "네트워크"
msgid "TCP"
msgstr "TCP"
+msgid "Connect Timeout Seconds"
+msgstr "연결 타임아웃 초"
+
+msgid "Packet Peer Stream"
+msgstr "패킷 피어 스트림"
+
+msgid "Max Buffer (Power of 2)"
+msgstr "최대 버퍼 (2의 제곱수 단위)"
+
msgid "TLS"
msgstr "TLS"
@@ -486,11 +616,20 @@ msgstr "인증서 번들 오버라이드"
msgid "Threading"
msgstr "스레딩"
+msgid "Worker Pool"
+msgstr "워커 풀"
+
msgid "Max Threads"
msgstr "최대 스레드"
+msgid "Use System Threads for Low Priority Tasks"
+msgstr "저 우선순위 작업에 시스템 스레드 사용"
+
+msgid "Low Priority Thread Ratio"
+msgstr "저 우선순위 스레드 비율"
+
msgid "Locale"
-msgstr "위치"
+msgstr "로케일"
msgid "Test"
msgstr "테스트"
@@ -498,9 +637,36 @@ msgstr "테스트"
msgid "Fallback"
msgstr "폴백"
+msgid "Pseudolocalization"
+msgstr "가짜 현지화"
+
+msgid "Use Pseudolocalization"
+msgstr "가짜 현지화 사용"
+
+msgid "Replace With Accents"
+msgstr "악센트 부호 붙이기"
+
+msgid "Double Vowels"
+msgstr "모음 두 번 작성"
+
+msgid "Fake BiDi"
+msgstr "가짜 BiDi"
+
msgid "Override"
msgstr "오버라이드"
+msgid "Expansion Ratio"
+msgstr "확장 비율"
+
+msgid "Prefix"
+msgstr "접두사"
+
+msgid "Suffix"
+msgstr "접미사"
+
+msgid "Skip Placeholders"
+msgstr "자리 표시자 건너뛰기"
+
msgid "Rotation"
msgstr "회전"
@@ -522,6 +688,9 @@ msgstr "입력 핸들"
msgid "Out Handle"
msgstr "출력 핸들"
+msgid "Handle Mode"
+msgstr "핸들 모드"
+
msgid "Stream"
msgstr "스트림"
@@ -537,9 +706,18 @@ msgstr "애니메이션"
msgid "Easing"
msgstr "속도 완화"
+msgid "Debug Adapter"
+msgstr "디버그 어댑터"
+
msgid "Remote Port"
msgstr "원격 포트"
+msgid "Request Timeout"
+msgstr "요청 타임아웃"
+
+msgid "Sync Breakpoints"
+msgstr "중단점 동기화"
+
msgid "FileSystem"
msgstr "파일시스템"
@@ -555,6 +733,12 @@ msgstr "비밀번호"
msgid "Default Feature Profile"
msgstr "기본 기능 프로필"
+msgid "Version Hash"
+msgstr "버전 해시"
+
+msgid "Classes"
+msgstr "클래스"
+
msgid "Text Editor"
msgstr "텍스트 에디터"
@@ -576,6 +760,9 @@ msgstr "확인 가능"
msgid "Checked"
msgstr "확인됨"
+msgid "Draw Warning"
+msgstr "경고 그리기"
+
msgid "Keying"
msgstr "키 값 생성"
@@ -585,9 +772,15 @@ msgstr "삭제 가능"
msgid "Distraction Free Mode"
msgstr "집중 모드"
+msgid "Movie Maker Enabled"
+msgstr "무비 메이커 활성화됨"
+
msgid "Interface"
msgstr "인터페이스"
+msgid "Save on Focus Loss"
+msgstr "포커스를 잃을 때 저장"
+
msgid "Show Update Spinner"
msgstr "업데이트 스피너 표시"
@@ -600,6 +793,9 @@ msgstr "현지화 설정"
msgid "Scene Tabs"
msgstr "씬 탭"
+msgid "Restore Scenes on Load"
+msgstr "불러오기 시 씬 복원"
+
msgid "Inspector"
msgstr "인스펙터"
@@ -621,8 +817,17 @@ msgstr "수평 2차원 벡터 변경"
msgid "Horizontal Vector Types Editing"
msgstr "수평 벡터 타입 변경"
+msgid "Open Resources in Current Inspector"
+msgstr "현재 인스펙터에서 리소스 열기"
+
+msgid "Resources to Open in New Inspector"
+msgstr "새로운 인스펙터에서 열 리소스"
+
msgid "Default Color Picker Mode"
-msgstr "기본 색 고르기 모드"
+msgstr "기본 색상 선택기 모드"
+
+msgid "Default Color Picker Shape"
+msgstr "기본 색상 선택기 모양"
msgid "Base Type"
msgstr "기본 타입"
@@ -639,6 +844,21 @@ msgstr "에디터 언어"
msgid "Display Scale"
msgstr "화면 크기"
+msgid "Editor Screen"
+msgstr "에디터 화면"
+
+msgid "Project Manager Screen"
+msgstr "프로젝트 매니저 화면"
+
+msgid "Enable Pseudolocalization"
+msgstr "가짜 현지화 사용"
+
+msgid "Use Embedded Menu"
+msgstr "내장된 메뉴 사용"
+
+msgid "Expand to Title"
+msgstr "제목 표시줄로 확장"
+
msgid "Custom Display Scale"
msgstr "사용자 지정 화면 크기"
@@ -648,8 +868,23 @@ msgstr "기본 글꼴 크기"
msgid "Code Font Size"
msgstr "코드 글꼴 크기"
+msgid "Code Font Contextual Ligatures"
+msgstr "코드 글꼴에 합자 사용"
+
+msgid "Code Font Custom OpenType Features"
+msgstr "코드 글꼴 커스텀 OpenType 기능"
+
+msgid "Code Font Custom Variations"
+msgstr "코드 글꼴 커스텀 바리에이션"
+
+msgid "Font Antialiasing"
+msgstr "글꼴 안티앨리어싱"
+
msgid "Font Hinting"
-msgstr "폰트 힌팅"
+msgstr "글꼴 힌팅"
+
+msgid "Font Subpixel Positioning"
+msgstr "글꼴 서브픽셀 포지셔닝"
msgid "Main Font"
msgstr "기본 글꼴"
@@ -672,9 +907,30 @@ msgstr "분리 방해 모드"
msgid "Automatically Open Screenshots"
msgstr "자동으로 스크린샷 열기"
+msgid "Single Window Mode"
+msgstr "단일 창 모드"
+
msgid "Mouse Extra Buttons Navigate History"
msgstr "마우스 부가 버튼으로 히스토리 둘러보기"
+msgid "Save Each Scene on Quit"
+msgstr "종료 시 각 씬 저장"
+
+msgid "Accept Dialog Cancel OK Buttons"
+msgstr "확인 창의 취소 확인 버튼"
+
+msgid "Show Internal Errors in Toast Notifications"
+msgstr "내부적인 오류를 토스트 알림에 표시"
+
+msgid "Max Array Dictionary Items per Page"
+msgstr "페이지 당 최대 딕셔너리 아이템 배열 크기"
+
+msgid "Show Low Level OpenType Features"
+msgstr "저수준 OpenType 기능 보이기"
+
+msgid "Float Drag Speed"
+msgstr "플로트 드래그 속도"
+
msgid "Theme"
msgstr "테마"
@@ -693,6 +949,9 @@ msgstr "강조 색"
msgid "Contrast"
msgstr "대비"
+msgid "Draw Extra Borders"
+msgstr "추가적인 외곽선 그리기"
+
msgid "Icon Saturation"
msgstr "아이콘 채도"
@@ -702,21 +961,54 @@ msgstr "관계선 불투명도"
msgid "Border Size"
msgstr "테두리 크기"
+msgid "Corner Radius"
+msgstr "모서리 둥글기"
+
msgid "Additional Spacing"
msgstr "추가적인 공간 확보"
msgid "Custom Theme"
msgstr "사용자 지정 테마"
+msgid "Touchscreen"
+msgstr "터치스크린"
+
+msgid "Increase Scrollbar Touch Area"
+msgstr "스크롤바 터치 영역 늘리기"
+
+msgid "Enable Long Press as Right Click"
+msgstr "길게 누를 시 우클릭하기 활성화"
+
+msgid "Enable Pan and Scale Gestures"
+msgstr "이동 및 확대 제스처 활성화"
+
+msgid "Scale Gizmo Handles"
+msgstr "기즈모 핸들 스케일"
+
+msgid "Display Close Button"
+msgstr "닫기 버튼 표시"
+
+msgid "Show Thumbnail on Hover"
+msgstr "마우스 오버 시 썸네일 표시"
+
msgid "Maximum Width"
msgstr "최대 너비"
msgid "Show Script Button"
msgstr "스크립트 버튼 보이기"
+msgid "Multi Window"
+msgstr "다중 창"
+
msgid "Enable"
msgstr "활성화"
+msgid "Restore Windows on Load"
+msgstr "불러오기 시 창 복원"
+
+msgid "Maximize Window"
+msgstr "창 최대화"
+
msgid "External Programs"
msgstr "외부 프로그램"
@@ -771,9 +1063,15 @@ msgstr "씬 트리"
msgid "Start Create Dialog Fully Expanded"
msgstr "완전히 확장된 대화 상자 생성 시작"
+msgid "Auto Expand to Selected"
+msgstr "선택으로 자동 확장"
+
msgid "Always Show Folders"
msgstr "폴더 항상 보이기"
+msgid "TextFile Extensions"
+msgstr "텍스트 파일 확장자"
+
msgid "Property Editor"
msgstr "속성 에디터"
@@ -795,12 +1093,18 @@ msgstr "탈자 기호"
msgid "Caret Blink"
msgstr "탈자 기호 깜빡임"
+msgid "Caret Blink Interval"
+msgstr "탈자 기호 깜빡임 간격"
+
msgid "Highlight Current Line"
msgstr "현재 줄 강조"
msgid "Highlight All Occurrences"
msgstr "모든 발생 강조"
+msgid "Guidelines"
+msgstr "가이드라인"
+
msgid "Show Line Length Guidelines"
msgstr "줄 길이 가이드라인 보이기"
@@ -810,6 +1114,9 @@ msgstr "줄 길이 가이드라인 소프트 열"
msgid "Line Length Guideline Hard Column"
msgstr "줄 길이 가이드라인 하드 열"
+msgid "Gutters"
+msgstr "거터"
+
msgid "Show Line Numbers"
msgstr "줄 번호 보이기"
@@ -822,6 +1129,9 @@ msgstr "타입 안전 줄 강조"
msgid "Show Info Gutter"
msgstr "정보 여백 보이기"
+msgid "Minimap"
+msgstr "미니맵"
+
msgid "Show Minimap"
msgstr "미니맵 보이기"
@@ -837,6 +1147,9 @@ msgstr "코드 접기"
msgid "Word Wrap"
msgstr "단어 감싸기"
+msgid "Autowrap Mode"
+msgstr "자동 줄바꿈 모드"
+
msgid "Whitespace"
msgstr "공백"
@@ -849,9 +1162,15 @@ msgstr "공백 사용"
msgid "Line Spacing"
msgstr "라인 간격"
+msgid "Behavior"
+msgstr "행동"
+
msgid "Navigation"
msgstr "네비게이션"
+msgid "Move Caret on Right Click"
+msgstr "우클릭 시 텍스트 커서 이동"
+
msgid "Scroll Past End of File"
msgstr "파일 끝을 넘어서도 스크롤"
@@ -861,6 +1180,12 @@ msgstr "부드러운 스크롤링"
msgid "V Scroll Speed"
msgstr "수직 스크롤 속도"
+msgid "Drag and Drop Selection"
+msgstr "선택된 항목을 드래그 & 드롭"
+
+msgid "Stay in Script Editor on Node Selected"
+msgstr "선택한 노드에서 스크립트 에디터 유지"
+
msgid "Indent"
msgstr "들여쓰기"
@@ -994,10 +1319,10 @@ msgid "Default FOV"
msgstr "기본 시야각"
msgid "Default Z Near"
-msgstr "기본 Z Near"
+msgstr "기본 Z 근경"
msgid "Default Z Far"
-msgstr "기본 Z Far"
+msgstr "기본 Z 원경"
msgid "Invert X Axis"
msgstr "X축 반전"
@@ -1101,9 +1426,21 @@ msgstr "표시 영역 테두리 색상"
msgid "Panning"
msgstr "패닝"
+msgid "2D Editor Panning Scheme"
+msgstr "2D 에디터 패닝 방식"
+
+msgid "Sub Editors Panning Scheme"
+msgstr "보조 에디터 패닝 방식"
+
+msgid "Animation Editors Panning Scheme"
+msgstr "애니메이션 에디터 패닝 방식"
+
msgid "Simple Panning"
msgstr "간단한 패닝"
+msgid "2D Editor Pan Speed"
+msgstr "2D 에디터 패닝 속도"
+
msgid "Tiles Editor"
msgstr "타일 에디터"
@@ -1137,15 +1474,27 @@ msgstr "양파 레이어 과거 색상"
msgid "Onion Layers Future Color"
msgstr "양파 레이어 미래 색상"
+msgid "Shader Editor"
+msgstr "셰이더 에디터"
+
+msgid "Restore Shaders on Load"
+msgstr "불러오기 시 셰이더 복원"
+
msgid "Visual Editors"
-msgstr "비주얼 편집기"
+msgstr "비주얼 에디터"
msgid "Minimap Opacity"
msgstr "미니맵 불투명도"
+msgid "Lines Curvature"
+msgstr "선 곡률"
+
msgid "Visual Shader"
msgstr "비주얼 셰이더"
+msgid "Port Preview Size"
+msgstr "포트 미리보기 크기"
+
msgid "Window Placement"
msgstr "창 배치"
@@ -1158,6 +1507,9 @@ msgstr "직사각형 사용자 정의 위치"
msgid "Screen"
msgstr "화면"
+msgid "Android Window"
+msgstr "Android 창"
+
msgid "Auto Save"
msgstr "자동 저장"
@@ -1170,6 +1522,15 @@ msgstr "출력"
msgid "Font Size"
msgstr "폰트 크기"
+msgid "Always Clear Output on Play"
+msgstr "실행 시 항상 출력 지우기"
+
+msgid "Always Open Output on Play"
+msgstr "실행 시 항상 출력 열기"
+
+msgid "Always Close Output on Stop"
+msgstr "정지 시 항상 출력 닫기"
+
msgid "Remote Host"
msgstr "원격 호스트"
@@ -1179,6 +1540,9 @@ msgstr "에디터 TLS 인증서"
msgid "Debugger"
msgstr "디버거"
+msgid "Auto Switch to Remote Scene Tree"
+msgstr "원격 씬 트리로 자동 전환"
+
msgid "Profiler Frame History Size"
msgstr "프로파일러 프레임 기록 크기"
@@ -1210,61 +1574,64 @@ msgid "Highlighting"
msgstr "강조"
msgid "Symbol Color"
-msgstr "상징 색"
+msgstr "심볼 색상"
msgid "Keyword Color"
msgstr "키워드 색상"
msgid "Control Flow Keyword Color"
-msgstr "플로우 키워드 색상 제어"
+msgstr "흐름 제어 키워드 색상"
msgid "Base Type Color"
-msgstr "기본 유형 색상"
+msgstr "기본 타입 색상"
msgid "Engine Type Color"
-msgstr "엔진 유형 색상"
+msgstr "엔진 타입 색상"
msgid "User Type Color"
-msgstr "사용자 유형 색상"
+msgstr "사용자 타입 색상"
msgid "Comment Color"
-msgstr "댓글 색상"
+msgstr "주석 색상"
msgid "String Color"
-msgstr "문자열 색"
+msgstr "문자열 색상"
msgid "Background Color"
-msgstr "배경 색"
+msgstr "배경 색상"
msgid "Completion Background Color"
-msgstr "완성 배경 색"
+msgstr "자동완성 창 배경 색상"
msgid "Completion Selected Color"
-msgstr "선택 색상 완료"
+msgstr "자동완성 창 선택 색상"
msgid "Completion Existing Color"
-msgstr "기존 색상 완성"
+msgstr "자동완성 창 텍스트 강조 색상"
msgid "Completion Scroll Color"
-msgstr "스크롤 색상 완료"
+msgstr "자동완성 창 스크롤 색상"
+
+msgid "Completion Scroll Hovered Color"
+msgstr "자동완성 창 스크롤 호버 시 색상"
msgid "Completion Font Color"
-msgstr "글꼴 색상 완료"
+msgstr "자동완성 창 글자 색상"
msgid "Text Color"
-msgstr "글자색"
+msgstr "글자 색상"
msgid "Line Number Color"
-msgstr "행 번호의 색"
+msgstr "행 번호 색상"
msgid "Safe Line Number Color"
msgstr "안전 라인 번호 색상"
msgid "Caret Color"
-msgstr "탈자 기호 색"
+msgstr "탈자 기호 색상"
msgid "Caret Background Color"
-msgstr "탈자 기호 배경 색"
+msgstr "탈자 기호 배경 색상"
msgid "Text Selected Color"
msgstr "선택한 텍스트 색상"
@@ -1303,10 +1670,10 @@ msgid "Breakpoint Color"
msgstr "중단점 색상"
msgid "Executing Line Color"
-msgstr "라인 색상 실행"
+msgstr "실행 중인 줄 색상"
msgid "Code Folding Color"
-msgstr "코드 폴딩 색상"
+msgstr "코드 접기 색상"
msgid "Search Result Color"
msgstr "검색 결과 색상"
@@ -1320,6 +1687,9 @@ msgstr "커스텀 템플릿"
msgid "Release"
msgstr "출시"
+msgid "Export Console Wrapper"
+msgstr "콘솔 래퍼 내보내기"
+
msgid "Binary Format"
msgstr "바이너리 포맷"
@@ -1351,11 +1721,14 @@ msgid "SCP"
msgstr "SCP"
msgid "Export Path"
-msgstr "경로 내보내기"
+msgstr "내보낼 경로"
msgid "Access"
msgstr "액세스"
+msgid "File Mode"
+msgstr "파일 모드"
+
msgid "Filters"
msgstr "필터"
@@ -1371,18 +1744,72 @@ msgstr "슬라이더 숨기기"
msgid "Zoom"
msgstr "줌"
+msgid "Antialiasing"
+msgstr "안티앨리어싱"
+
+msgid "Generate Mipmaps"
+msgstr "밉맵 생성"
+
+msgid "Multichannel Signed Distance Field"
+msgstr "다중 채널 부호 있는 거리 필드 (MSDF)"
+
+msgid "MSDF Pixel Range"
+msgstr "MSDF 픽셀 범위"
+
+msgid "MSDF Size"
+msgstr "MSDF 크기"
+
+msgid "Allow System Fallback"
+msgstr "시스템 폴백 허용"
+
+msgid "Force Autohinter"
+msgstr "오토힌터 강제"
+
msgid "Hinting"
msgstr "힌팅"
+msgid "Subpixel Positioning"
+msgstr "서브픽셀 포지셔닝"
+
msgid "Oversampling"
msgstr "오버샘플링"
+msgid "Metadata Overrides"
+msgstr "메타데이터 오버라이드"
+
+msgid "Language Support"
+msgstr "언어 지원"
+
+msgid "Script Support"
+msgstr "스크립트 지원"
+
+msgid "OpenType Features"
+msgstr "OpenType 기능"
+
+msgid "Fallbacks"
+msgstr "폴백"
+
msgid "Compress"
msgstr "컴프레스"
msgid "Language"
msgstr "언어"
+msgid "Outline Size"
+msgstr "윤곽선 크기"
+
+msgid "Variation"
+msgstr "바리에이션"
+
+msgid "OpenType"
+msgstr "OpenType"
+
+msgid "Embolden"
+msgstr "굵게 하기"
+
+msgid "Face Index"
+msgstr "면 인덱스"
+
msgid "Transform"
msgstr "변형"
@@ -1392,14 +1819,59 @@ msgstr "COLLADA"
msgid "Use Ambient"
msgstr "주변광 사용"
+msgid "Retarget"
+msgstr "리타겟"
+
+msgid "Bone Renamer"
+msgstr "본 리네이머"
+
+msgid "Rename Bones"
+msgstr "본 이름 바꾸기"
+
+msgid "Unique Node"
+msgstr "고유 노드"
+
msgid "Make Unique"
msgstr "유일하게 만들기"
+msgid "Skeleton Name"
+msgstr "스켈레톤 이름"
+
+msgid "Rest Fixer"
+msgstr "레스트 픽서"
+
+msgid "Apply Node Transforms"
+msgstr "노드 변환 적용"
+
+msgid "Normalize Position Tracks"
+msgstr "위치 트랙 정규화"
+
+msgid "Overwrite Axis"
+msgstr "축 덮어쓰기"
+
+msgid "Fix Silhouette"
+msgstr "실루엣 픽스"
+
msgid "Filter"
msgstr "필터"
msgid "Threshold"
-msgstr "스레숄드"
+msgstr "역치값"
+
+msgid "Base Height Adjustment"
+msgstr "기본 높이 조정"
+
+msgid "Remove Tracks"
+msgstr "트랙 제거"
+
+msgid "Except Bone Transform"
+msgstr "본 변형 제외"
+
+msgid "Unimportant Positions"
+msgstr "중요하지 않은 위치"
+
+msgid "Unmapped Bones"
+msgstr "매핑되지 않은 본"
msgid "Create From"
msgstr "다음에서 만들기"
@@ -1407,12 +1879,42 @@ msgstr "다음에서 만들기"
msgid "Delimiter"
msgstr "디리미터"
+msgid "Character Ranges"
+msgstr "문자 범위"
+
+msgid "Columns"
+msgstr "열"
+
+msgid "Rows"
+msgstr "행"
+
+msgid "Image Margin"
+msgstr "이미지 여백"
+
+msgid "Character Margin"
+msgstr "글자 여백"
+
+msgid "High Quality"
+msgstr "고품질"
+
msgid "Lossy Quality"
msgstr "손실 품질"
+msgid "HDR Compression"
+msgstr "HDR 압축"
+
+msgid "Channel Pack"
+msgstr "채널 팩"
+
msgid "Mipmaps"
msgstr "밉맵"
+msgid "Generate"
+msgstr "생성"
+
+msgid "Limit"
+msgstr "제한"
+
msgid "Slices"
msgstr "슬라이스"
@@ -1422,6 +1924,9 @@ msgstr "수평"
msgid "Vertical"
msgstr "수직"
+msgid "Arrangement"
+msgstr "어레인지먼트"
+
msgid "Layout"
msgstr "레이아웃"
@@ -1437,12 +1942,72 @@ msgstr "스케일 메쉬"
msgid "Offset Mesh"
msgstr "오프셋 메시"
+msgid "Optimize Mesh"
+msgstr "메시 최적화"
+
msgid "Import"
msgstr "가져오기"
+msgid "Skip Import"
+msgstr "가져오기 건너뛰기"
+
+msgid "NavMesh"
+msgstr "NavMesh"
+
+msgid "Body Type"
+msgstr "바디 타입"
+
+msgid "Shape Type"
+msgstr "모양 타입"
+
+msgid "Decomposition"
+msgstr "해체"
+
msgid "Advanced"
msgstr "고급"
+msgid "Precision"
+msgstr "정밀도"
+
+msgid "Max Concavity"
+msgstr "최대 오목성"
+
+msgid "Symmetry Planes Clipping Bias"
+msgstr "대칭 평면 클리핑 바이어스"
+
+msgid "Revolution Axes Clipping Bias"
+msgstr "회전축 클리핑 바이어스"
+
+msgid "Min Volume per Convex Hull"
+msgstr "컨벡스 헐 당 최소 부피"
+
+msgid "Resolution"
+msgstr "해상도"
+
+msgid "Max Num Vertices per Convex Hull"
+msgstr "컨벡스 헐 당 최대 꼭지점 수"
+
+msgid "Plane Downsampling"
+msgstr "평면 다운샘플링"
+
+msgid "Convexhull Downsampling"
+msgstr "컨벡스 헐 다운샘플링"
+
+msgid "Normalize Mesh"
+msgstr "메시 정규화"
+
+msgid "Convexhull Approximation"
+msgstr "컨벡스 헐 근사"
+
+msgid "Max Convex Hulls"
+msgstr "최대 컨벡스 헐"
+
+msgid "Project Hull Vertices"
+msgstr "프로젝트 헐 꼭지점"
+
+msgid "Primitive"
+msgstr "프리미티브"
+
msgid "Height"
msgstr "높이"
@@ -1452,11 +2017,35 @@ msgstr "반지름"
msgid "Occluder"
msgstr "오클루더"
+msgid "Simplification Distance"
+msgstr "단순화 거리"
+
+msgid "Save to File"
+msgstr "파일로 저장"
+
msgid "Enabled"
msgstr "활성화됨"
+msgid "Make Streamable"
+msgstr "스트림 가능하게 하기"
+
+msgid "Shadow Meshes"
+msgstr "그림자 메시"
+
+msgid "Lightmap UV"
+msgstr "라이트맵 UV"
+
+msgid "LODs"
+msgstr "LOD"
+
+msgid "Normal Split Angle"
+msgstr "노멀 스플릿 각도"
+
msgid "Normal Merge Angle"
-msgstr "정상적인 병합 각도"
+msgstr "노멀 머지 각도"
+
+msgid "Use External"
+msgstr "외부 것 사용"
msgid "Loop Mode"
msgstr "루프 모드"
@@ -1467,12 +2056,24 @@ msgstr "맞춤 트랙 유지"
msgid "Optimizer"
msgstr "최적화 도구"
+msgid "Max Velocity Error"
+msgstr "최대 속도 오차"
+
msgid "Max Angular Error"
-msgstr "최대 각도 오류"
+msgstr "최대 각도 오차"
+
+msgid "Max Precision Error"
+msgstr "최대 정밀도 오차"
msgid "Page Size"
msgstr "페이지 크기"
+msgid "Import Tracks"
+msgstr "트랙 가져오기"
+
+msgid "Bone Map"
+msgstr "본 맵"
+
msgid "Nodes"
msgstr "노드"
@@ -1482,6 +2083,9 @@ msgstr "루트 유형"
msgid "Root Name"
msgstr "루트 이름"
+msgid "Apply Root Scale"
+msgstr "루트 스케일 적용"
+
msgid "Root Scale"
msgstr "루트 스케일"
@@ -1491,6 +2095,12 @@ msgstr "메쉬"
msgid "Ensure Tangents"
msgstr "접선 확인"
+msgid "Generate LODs"
+msgstr "LOD 생성"
+
+msgid "Create Shadow Meshes"
+msgstr "그림자 메시 생성"
+
msgid "Light Baking"
msgstr "라이트 베이킹"
@@ -1506,9 +2116,24 @@ msgstr "네임드 스킨 사용"
msgid "FPS"
msgstr "초당 프레임"
+msgid "Trimming"
+msgstr "트리밍"
+
+msgid "Remove Immutable Tracks"
+msgstr "변경 불가한 트랙 제거"
+
+msgid "Import Script"
+msgstr "스크립트 가져오기"
+
msgid "Normal Map"
msgstr "일반 맵"
+msgid "Roughness"
+msgstr "굵기"
+
+msgid "Src Normal"
+msgstr "소스 노멀"
+
msgid "Process"
msgstr "프로세스"
@@ -1521,21 +2146,39 @@ msgstr "프리멀트 알파"
msgid "Normal Map Invert Y"
msgstr "노멀 맵 Y축 반전"
+msgid "HDR as sRGB"
+msgstr "HDR을 sRGB로"
+
+msgid "HDR Clamp Exposure"
+msgstr "HDR 클램프 노출"
+
msgid "Size Limit"
msgstr "크기 제한"
msgid "Detect 3D"
msgstr "3D 감지"
+msgid "Compress To"
+msgstr "압축:"
+
msgid "SVG"
msgstr "SVG"
+msgid "Scale With Editor Scale"
+msgstr "에디터 스케일과 함께 스케일"
+
+msgid "Convert Colors With Editor Theme"
+msgstr "색상을 에디터 테마로 변환"
+
msgid "Atlas File"
msgstr "아틀라스 파일"
msgid "Import Mode"
msgstr "가져오기 모드"
+msgid "Crop to Region"
+msgstr "영역으로 자르기"
+
msgid "Trim Alpha Border From Region"
msgstr "영역에서 알파 테두리 자르기"
@@ -1570,7 +2213,7 @@ msgid "Loop End"
msgstr "루프 종료"
msgid "Asset Library"
-msgstr "애셋 라이브러리"
+msgstr "에셋 라이브러리"
msgid "Use Threads"
msgstr "스레드 사용"
@@ -1578,9 +2221,27 @@ msgstr "스레드 사용"
msgid "Available URLs"
msgstr "사용 가능한 URL"
+msgid "Current Group Idx"
+msgstr "현재 그룹 인덱스"
+
+msgid "Current Bone Idx"
+msgstr "현재 본 인덱스"
+
+msgid "Bone Mapper"
+msgstr "본 매퍼"
+
+msgid "Handle Colors"
+msgstr "핸들 색상"
+
msgid "Unset"
msgstr "설정 해제"
+msgid "Set"
+msgstr "설정"
+
+msgid "Missing"
+msgstr "알 수 없음"
+
msgid "Error"
msgstr "오류"
@@ -1593,21 +2254,39 @@ msgstr "카메라"
msgid "Decal"
msgstr "데칼"
+msgid "Fog Volume"
+msgstr "포그 볼륨"
+
msgid "Particles"
msgstr "파티클"
+msgid "Particle Attractor"
+msgstr "파티클 어트랙터"
+
+msgid "Particle Collision"
+msgstr "파티클 충돌"
+
msgid "Joint Body A"
msgstr "조인트 바디 A"
msgid "Joint Body B"
msgstr "조인트 바디 B"
+msgid "Lightmap Lines"
+msgstr "라이트맵 라인"
+
+msgid "Lightprobe Lines"
+msgstr "라이트프로브 라인"
+
msgid "Reflection Probe"
msgstr "반사 프로브"
msgid "Visibility Notifier"
msgstr "가시성 알리미"
+msgid "Voxel GI"
+msgstr "Voxel GI"
+
msgid "Manipulator Gizmo Size"
msgstr "조작기 기즈모 크기"
@@ -1617,6 +2296,15 @@ msgstr "조작기 기즈모 불투명도"
msgid "Show Viewport Rotation Gizmo"
msgstr "뷰포트 회전 기즈모 표시"
+msgid "Show Viewport Navigation Gizmo"
+msgstr "뷰포트 네비게이션 기즈모 표시"
+
+msgid "Auto Reload and Parse Scripts on Save"
+msgstr "저장 시 스크립트 자동 리로드 및 파싱"
+
+msgid "Open Dominant Script on Scene Change"
+msgstr "씬 변경 시 주요 스크립트 열기"
+
msgid "External"
msgstr "외부"
@@ -1647,18 +2335,54 @@ msgstr "실행 플래그"
msgid "Skeleton"
msgstr "스켈레톤"
+msgid "Selected Bone"
+msgstr "선택된 본"
+
+msgid "Gizmo Settings"
+msgstr "기즈모 설정"
+
+msgid "Bone Axis Length"
+msgstr "본 축 길이"
+
+msgid "Bone Shape"
+msgstr "본 모양"
+
msgid "ID"
msgstr "ID"
msgid "Texture"
msgstr "텍스쳐"
+msgid "Margins"
+msgstr "여백"
+
msgid "Separation"
-msgstr "분리"
+msgstr "간격"
+
+msgid "Texture Region Size"
+msgstr "텍스처 영역 크기"
+
+msgid "Use Texture Padding"
+msgstr "텍스쳐 패딩 사용"
+
+msgid "Atlas Coords"
+msgstr "아틀라스 좌표"
+
+msgid "Size in Atlas"
+msgstr "아틀라스 내 크기"
+
+msgid "Alternative ID"
+msgstr "다른 ID"
msgid "Speed"
msgstr "속력"
+msgid "Frames Count"
+msgstr "프레임 카운트"
+
+msgid "Duration"
+msgstr "지속 시간"
+
msgid "Version Control"
msgstr "버전 컨트롤"
@@ -1674,15 +2398,63 @@ msgstr "SSH 개인 키 경로"
msgid "Main Run Args"
msgstr "메인 실행 인자"
+msgid "Templates Search Path"
+msgstr "템플릿 탐색 경로"
+
+msgid "Naming"
+msgstr "이름짓기"
+
+msgid "Default Signal Callback Name"
+msgstr "신호 콜백 기본 이름"
+
+msgid "Default Signal Callback to Self Name"
+msgstr "자신으로의 신호 콜백 기본 이름"
+
+msgid "Scene Name Casing"
+msgstr "씬 이름 대소문자"
+
msgid "Reimport Missing Imported Files"
msgstr "누락된 가져온 파일 다시 가져오기"
+msgid "Use Multiple Threads"
+msgstr "다중 스레드 사용"
+
+msgid "Convert Text Resources to Binary"
+msgstr "텍스트 리소스를 바이너리로 변환"
+
+msgid "Plugin Name"
+msgstr "플러그인 이름"
+
+msgid "Autoload on Startup"
+msgstr "시작 시 오토로드"
+
msgid "Show Scene Tree Root Selection"
msgstr "장면 트리 루트 선택 표시"
+msgid "Derive Script Globals by Name"
+msgstr "스크립트 글로벌을 이름으로 상속"
+
+msgid "Ask Before Deleting Related Animation Tracks"
+msgstr "연관 애니메이션 트랙을 지우기 전 물어보기"
+
msgid "Use Favorites Root Selection"
msgstr "즐겨찾기 루트 선택 사용"
+msgid "Flush stdout on Print"
+msgstr "출력 시 stdout 플러시"
+
+msgid "Max Chars per Second"
+msgstr "초당 최대 글자수"
+
+msgid "Max Queued Messages"
+msgstr "큐 내 최대 메시지 수"
+
+msgid "Max Errors per Second"
+msgstr "초당 최대 오류 수"
+
+msgid "Max Warnings per Second"
+msgstr "초당 최대 경고 수"
+
msgid "File Logging"
msgstr "파일 로깅"
@@ -1692,9 +2464,27 @@ msgstr "파일 로깅 활성화"
msgid "Log Path"
msgstr "로그 경로"
+msgid "Max Log Files"
+msgstr "최대 로그 파일 수"
+
msgid "Driver"
msgstr "드라이버"
+msgid "GL Compatibility"
+msgstr "GL 호환성"
+
+msgid "Nvidia Disable Threaded Optimization"
+msgstr "NVidia 스레드 최적화 사용 안함"
+
+msgid "Renderer"
+msgstr "렌더러"
+
+msgid "Rendering Method"
+msgstr "렌더링 방식"
+
+msgid "Include Text Server Data"
+msgstr "텍스트 서버 데이터 포함"
+
msgid "DPI"
msgstr "DPI"
@@ -1722,33 +2512,78 @@ msgstr "오리엔테이션"
msgid "V-Sync"
msgstr "수직동기화"
+msgid "V-Sync Mode"
+msgstr "수직동기화 모드"
+
msgid "stdout"
msgstr "표준 출력"
msgid "Print FPS"
msgstr "FPS 인쇄"
+msgid "Print GPU Profile"
+msgstr "GPU 프로필 출력"
+
msgid "Verbose stdout"
msgstr "자세한 표준 출력"
+msgid "Frame Delay Msec"
+msgstr "프레임 딜레이 밀리초"
+
msgid "Low Processor Mode"
msgstr "낮은 프로세서 모드"
msgid "iOS"
msgstr "iOS"
+msgid "Allow High Refresh Rate"
+msgstr "높은 주사율 허용"
+
msgid "Hide Home Indicator"
msgstr "홈 표시기 숨기기"
+msgid "Hide Status Bar"
+msgstr "상태 표시줄 숨기기"
+
+msgid "Suppress UI Gesture"
+msgstr "UI 제스쳐 막기"
+
msgid "XR"
msgstr "XR"
+msgid "OpenXR"
+msgstr "OpenXR"
+
+msgid "Default Action Map"
+msgstr "기본 액션 맵"
+
+msgid "Form Factor"
+msgstr "폼 팩터"
+
+msgid "View Configuration"
+msgstr "보기 설정"
+
+msgid "Reference Space"
+msgstr "레퍼런스 공간"
+
+msgid "Submit Depth Buffer"
+msgstr "깊이 버퍼 제출"
+
+msgid "Startup Alert"
+msgstr "시작 알림"
+
+msgid "In Editor"
+msgstr "에디터 내"
+
msgid "Boot Splash"
msgstr "부트 스플래쉬"
msgid "BG Color"
msgstr "배경색"
+msgid "Pen Tablet"
+msgstr "펜 타블렛"
+
msgid "Environment"
msgstr "환경"
@@ -1773,6 +2608,12 @@ msgstr "필터 사용"
msgid "Icon"
msgstr "아이콘"
+msgid "macOS Native Icon"
+msgstr "macOS 네이티브 아이콘"
+
+msgid "Windows Native Icon"
+msgstr "Windows 네이티브 아이콘"
+
msgid "Buffering"
msgstr "버퍼링"
@@ -1788,15 +2629,27 @@ msgstr "마우스 터치 에뮬레이트"
msgid "Emulate Mouse From Touch"
msgstr "터치로 마우스 에뮬레이트"
+msgid "Text Driver"
+msgstr "텍스트 드라이버"
+
msgid "Mouse Cursor"
msgstr "마우스 커서"
+msgid "Custom Image"
+msgstr "커스텀 이미지"
+
msgid "Custom Image Hotspot"
msgstr "사용자 정의 이미지 핫스팟"
msgid "Tooltip Position Offset"
msgstr "툴팁 위치 오프셋"
+msgid "Minimum Display Time"
+msgstr "최소 표시 시간"
+
+msgid "Dotnet"
+msgstr "닷넷"
+
msgid "Project"
msgstr "프로젝트"
@@ -1806,6 +2659,9 @@ msgstr "어셈블리 이름"
msgid "Solution Directory"
msgstr "솔루션 디렉토리"
+msgid "Assembly Reload Attempts"
+msgstr "어셈블리 리로드 시도 횟수"
+
msgid "Operation"
msgstr "오퍼레이션"
@@ -1827,6 +2683,12 @@ msgstr "충돌 레이어"
msgid "Collision Mask"
msgstr "충돌 마스크"
+msgid "Collision Priority"
+msgstr "충돌우선순위"
+
+msgid "Flip Faces"
+msgstr "면 뒤집기"
+
msgid "Mesh"
msgstr "메시"
@@ -1900,14 +2762,29 @@ msgid "CSG"
msgstr "CSG"
msgid "GDScript"
-msgstr "GD스크립트"
+msgstr "GDScript"
msgid "Function Definition Color"
msgstr "함수 정의 색상"
+msgid "Global Function Color"
+msgstr "전역 함수 색상"
+
msgid "Node Path Color"
msgstr "노드 경로 색상"
+msgid "Node Reference Color"
+msgstr "노드 레퍼런스 색상"
+
+msgid "Annotation Color"
+msgstr "어노테이션 색상"
+
+msgid "String Name Color"
+msgstr "문자열 이름 색상"
+
+msgid "Max Call Stack"
+msgstr "최대 호출 스택"
+
msgid "Warnings"
msgstr "경고"
@@ -1920,15 +2797,27 @@ msgstr "언어 서버"
msgid "Enable Smart Resolve"
msgstr "스마트 해결 활성화"
+msgid "Show Native Symbols in Editor"
+msgstr "에디터에서 네이티브 기호 표시"
+
msgid "Use Thread"
msgstr "스레드 사용"
+msgid "glTF"
+msgstr "glTF"
+
+msgid "Embedded Image Handling"
+msgstr "임베디드 이미지 핸들링"
+
msgid "Color"
msgstr "색상"
msgid "Intensity"
msgstr "강함"
+msgid "Light Type"
+msgstr "광원 타입"
+
msgid "Range"
msgstr "범위"
@@ -1953,9 +2842,27 @@ msgstr "반사 인자"
msgid "Spec Gloss Img"
msgstr "반사광 이미지"
+msgid "Mass"
+msgstr "질량"
+
+msgid "Linear Velocity"
+msgstr "선속도"
+
msgid "Angular Velocity"
msgstr "각속도"
+msgid "Inertia Tensor"
+msgstr "관성 텐서"
+
+msgid "Is Trigger"
+msgstr "트리거 여부"
+
+msgid "Mesh Index"
+msgstr "메시 인덱스"
+
+msgid "Importer Mesh"
+msgstr "임포터 메시"
+
msgid "Json"
msgstr "Json"
@@ -1986,9 +2893,15 @@ msgstr "머티리얼"
msgid "Scene Name"
msgstr "씬 이름"
+msgid "Base Path"
+msgstr "기본 경로"
+
msgid "Root Nodes"
msgstr "루트 노드"
+msgid "Texture Samplers"
+msgstr "텍스처 샘플러"
+
msgid "Images"
msgstr "이미지"
@@ -2007,12 +2920,33 @@ msgstr "고유한 애니메이션 이름"
msgid "Skeletons"
msgstr "스켈레톤"
+msgid "Create Animations"
+msgstr "애니메이션 생성"
+
msgid "Animations"
msgstr "애니메이션"
+msgid "Handle Binary Image"
+msgstr "바이너리 이미지 처리"
+
+msgid "Blender"
+msgstr "Blender"
+
+msgid "RPC Port"
+msgstr "RPC 포트"
+
+msgid "RPC Server Uptime"
+msgstr "RPC 서버 업타임"
+
+msgid "Blender 3 Path"
+msgstr "Blender 3 경로"
+
msgid "FBX"
msgstr "FBX"
+msgid "FBX2glTF Path"
+msgstr "FBX2glTF 경로"
+
msgid "Buffer View"
msgstr "버퍼 보기"
@@ -2070,6 +3004,15 @@ msgstr "인덱스"
msgid "Perspective"
msgstr "원근"
+msgid "FOV"
+msgstr "FOV"
+
+msgid "Depth Far"
+msgstr "원경 깊이"
+
+msgid "Depth Near"
+msgstr "근경 깊이"
+
msgid "Blend Weights"
msgstr "혼합 가중치"
@@ -2118,6 +3061,18 @@ msgstr "SRC 이미지"
msgid "Sampler"
msgstr "샘플러"
+msgid "Mag Filter"
+msgstr "Mag 필터"
+
+msgid "Min Filter"
+msgstr "Min 필터"
+
+msgid "Wrap S"
+msgstr "S 래핑"
+
+msgid "Wrap T"
+msgstr "T 래핑"
+
msgid "Palette Min Width"
msgstr "팔레트 최소 너비"
@@ -2125,7 +3080,7 @@ msgid "Preview Size"
msgstr "미리보기 크기"
msgid "Editor Side"
-msgstr "편집기 사이드"
+msgstr "에디터 쪽"
msgid "Mesh Library"
msgstr "메시 라이브러리"
@@ -2158,22 +3113,64 @@ msgid "Priority"
msgstr "우선 순위"
msgid "Bake Navigation"
-msgstr "베이크 내비게이션"
+msgstr "내비게이션 굽기"
msgid "Lightmapping"
msgstr "라이트 매핑"
+msgid "Bake Quality"
+msgstr "굽기 품질"
+
msgid "Low Quality Ray Count"
-msgstr "낮은 품질의 광선 수"
+msgstr "낮은 품질 광선 수"
msgid "Medium Quality Ray Count"
msgstr "중간 품질 광선 수"
msgid "High Quality Ray Count"
-msgstr "고품질 광선 수"
+msgstr "높은 품질 광선 수"
msgid "Ultra Quality Ray Count"
-msgstr "초고품질 광선 수"
+msgstr "매우 높은 품질 광선 수"
+
+msgid "Bake Performance"
+msgstr "굽기 성능"
+
+msgid "Max Rays per Pass"
+msgstr "패스당 최대 광선 수"
+
+msgid "Region Size"
+msgstr "영역 크기"
+
+msgid "Low Quality Probe Ray Count"
+msgstr "낮은 품질 프로브 광선 수"
+
+msgid "Medium Quality Probe Ray Count"
+msgstr "중간 품질의 프로브 광선 수"
+
+msgid "High Quality Probe Ray Count"
+msgstr "높은 품질 프로브 광선 수"
+
+msgid "Ultra Quality Probe Ray Count"
+msgstr "매우 높은 품질 프로브 광선 수"
+
+msgid "Max Rays per Probe Pass"
+msgstr "프로브 패스 당 최대 광선 수"
+
+msgid "Primitive Meshes"
+msgstr "프리미티브 메시"
+
+msgid "Texel Size"
+msgstr "텍셀 크기"
+
+msgid "BPM"
+msgstr "BPM"
+
+msgid "Beat Count"
+msgstr "박자수"
+
+msgid "Bar Beats"
+msgstr "마디당 비트"
msgid "Loop Offset"
msgstr "루프 오프셋"
@@ -2187,6 +3184,9 @@ msgstr "IOD"
msgid "Display Width"
msgstr "디스플레이 너비"
+msgid "Display to Lens"
+msgstr "렌즈에 표시"
+
msgid "Oversample"
msgstr "오버샘플"
@@ -2196,6 +3196,36 @@ msgstr "K1"
msgid "K2"
msgstr "K2"
+msgid "Spawnable Scenes"
+msgstr "소환 가능한 씬"
+
+msgid "Spawn Path"
+msgstr "소환 경로"
+
+msgid "Spawn Limit"
+msgstr "소환 제한"
+
+msgid "Root Path"
+msgstr "루트 경로"
+
+msgid "Replication Interval"
+msgstr "리플리케이션 간격"
+
+msgid "Delta Interval"
+msgstr "델타 간격"
+
+msgid "Visibility Update Mode"
+msgstr "가시성 업데이트 모드"
+
+msgid "Public Visibility"
+msgstr "공개 가시성"
+
+msgid "Auth Callback"
+msgstr "인증 콜백"
+
+msgid "Auth Timeout"
+msgstr "인증 타임아웃"
+
msgid "Allow Object Decoding"
msgstr "오브젝트 디코딩 허용"
@@ -2205,23 +3235,80 @@ msgstr "새로운 연결 거부"
msgid "Server Relay"
msgstr "서버 릴레이"
+msgid "Max Sync Packet Size"
+msgstr "최대 동기화 패킷 크기"
+
+msgid "Max Delta Packet Size"
+msgstr "최대 델타 패킷 크기"
+
+msgid "Noise Type"
+msgstr "노이즈 타입"
+
+msgid "Frequency"
+msgstr "주파수"
+
+msgid "Fractal"
+msgstr "프랙탈"
+
msgid "Octaves"
msgstr "옥타브"
msgid "Lacunarity"
-msgstr "세심함"
+msgstr "라쿠나리티"
+
+msgid "Gain"
+msgstr "게인"
+
+msgid "Weighted Strength"
+msgstr "가중치 강도"
+
+msgid "Ping Pong Strength"
+msgstr "핑퐁 강도"
+
+msgid "Cellular"
+msgstr "셀룰러"
+
+msgid "Distance Function"
+msgstr "거리 함수"
+
+msgid "Jitter"
+msgstr "지터"
msgid "Return Type"
msgstr "반환 유형"
+msgid "Domain Warp"
+msgstr "도메인 래핑"
+
+msgid "Amplitude"
+msgstr "진폭"
+
+msgid "Fractal Type"
+msgstr "프랙탈 종류"
+
msgid "Fractal Octaves"
-msgstr "프랙털 옥타브"
+msgstr "프랙탈 옥타브"
+
+msgid "Fractal Lacunarity"
+msgstr "프랙탈 라쿠나리티"
+
+msgid "Fractal Gain"
+msgstr "프랙탈 게인"
msgid "Width"
msgstr "너비"
+msgid "Invert"
+msgstr "반전"
+
+msgid "In 3D Space"
+msgstr "3차원 공간에서"
+
msgid "Seamless"
-msgstr "원활한"
+msgstr "틈 없이"
+
+msgid "Seamless Blend Skirt"
+msgstr "틈 없는 혼합 스커트"
msgid "As Normal Map"
msgstr "노멀 맵으로"
@@ -2229,8 +3316,41 @@ msgstr "노멀 맵으로"
msgid "Bump Strength"
msgstr "범프 강도"
+msgid "Color Ramp"
+msgstr "색 변환"
+
msgid "Noise"
-msgstr "소음"
+msgstr "노이즈"
+
+msgid "Localized Name"
+msgstr "현지화된 이름"
+
+msgid "Action Type"
+msgstr "액션 타입"
+
+msgid "Toplevel Paths"
+msgstr "최상위 경로"
+
+msgid "Paths"
+msgstr "경로"
+
+msgid "Interaction Profile Path"
+msgstr "상호작용 프로필 경로"
+
+msgid "Display Refresh Rate"
+msgstr "디스플레이 주사율"
+
+msgid "Render Target Size Multiplier"
+msgstr "렌더 타겟 크기 배수"
+
+msgid "Hand"
+msgstr "손"
+
+msgid "Motion Range"
+msgstr "모션 범위"
+
+msgid "Hand Skeleton"
+msgstr "손 스켈레톤"
msgid "Subject"
msgstr "서브젝트"
@@ -2268,44 +3388,329 @@ msgstr "IGD 우리의 주소"
msgid "IGD Status"
msgstr "IGD 상태"
+msgid "Write Mode"
+msgstr "쓰기 모드"
+
msgid "WebRTC"
msgstr "WebRTC"
+msgid "Max Channel in Buffer (KB)"
+msgstr "버퍼 내 최대 채널 (KB)"
+
+msgid "Supported Protocols"
+msgstr "지원 프로토콜"
+
+msgid "Handshake Headers"
+msgstr "핸드쉐이크 헤더"
+
+msgid "Inbound Buffer Size"
+msgstr "인바운드 버퍼 크기"
+
+msgid "Outbound Buffer Size"
+msgstr "아웃바운드 버퍼 크기"
+
msgid "Handshake Timeout"
msgstr "핸드쉐이크 타임아웃"
+msgid "Max Queued Packets"
+msgstr "큐 내 최대 패킷 수"
+
+msgid "Session Mode"
+msgstr "세션 모드"
+
msgid "Required Features"
msgstr "필수적 기능"
msgid "Optional Features"
msgstr "선택적 기능"
+msgid "Requested Reference Space Types"
+msgstr "요청된 레퍼런스 공간 타입"
+
+msgid "Reference Space Type"
+msgstr "레퍼런스 공간 타입"
+
+msgid "Visibility State"
+msgstr "가시성 상태"
+
msgid "Android"
msgstr "Android"
+msgid "Android SDK Path"
+msgstr "Android SDK 경로"
+
+msgid "Debug Keystore"
+msgstr "디버그 Keystore"
+
+msgid "Debug Keystore User"
+msgstr "디버그 Keystore 유저명"
+
+msgid "Debug Keystore Pass"
+msgstr "디버그 Keystore 암호"
+
+msgid "Force System User"
+msgstr "시스템 유저 강제"
+
+msgid "Shutdown ADB on Exit"
+msgstr "종료 시 ADB도 종료"
+
+msgid "One Click Deploy Clear Previous Install"
+msgstr "원클릭 배포의 이전 설치 모두 삭제"
+
+msgid "Launcher Icons"
+msgstr "런처 아이콘"
+
+msgid "Main 192 X 192"
+msgstr "메인 192 x 192"
+
+msgid "Adaptive Foreground 432 X 432"
+msgstr "적응형 앞배경 432 x 432"
+
+msgid "Adaptive Background 432 X 432"
+msgstr "적응형 뒷배경 432 x 432"
+
+msgid "Gradle Build"
+msgstr "Gradle 빌드"
+
+msgid "Use Gradle Build"
+msgstr "Gradle 빌드 사용"
+
+msgid "Export Format"
+msgstr "내보내기 종류"
+
+msgid "Min SDK"
+msgstr "최소 SDK"
+
+msgid "Target SDK"
+msgstr "대상 SDK"
+
msgid "Plugins"
msgstr "플러그인(Plugin)"
+msgid "Architectures"
+msgstr "구조"
+
+msgid "Keystore"
+msgstr "Keystore"
+
+msgid "Debug User"
+msgstr "디버그 유저"
+
+msgid "Debug Password"
+msgstr "디버그 암호"
+
+msgid "Release User"
+msgstr "릴리즈 유저"
+
+msgid "Release Password"
+msgstr "릴리즈 암호"
+
msgid "Version"
msgstr "버전"
+msgid "Code"
+msgstr "코드"
+
+msgid "Package"
+msgstr "패키지"
+
msgid "Unique Name"
msgstr "고유 이름"
+msgid "Signed"
+msgstr "서명됨"
+
msgid "App Category"
msgstr "앱 카테고리"
+msgid "Retain Data on Uninstall"
+msgstr "설치 삭제 시 데이터 유지"
+
+msgid "Exclude From Recents"
+msgstr "최근 항목에서 제외"
+
msgid "Graphics"
msgstr "그래픽"
+msgid "OpenGL Debug"
+msgstr "OpenGL 디버그"
+
+msgid "XR Features"
+msgstr "XR 기능"
+
+msgid "XR Mode"
+msgstr "XR 모드"
+
+msgid "Hand Tracking"
+msgstr "손 트래킹"
+
+msgid "Hand Tracking Frequency"
+msgstr "손 트래킹 빈도"
+
+msgid "Passthrough"
+msgstr "패스스루"
+
+msgid "Immersive Mode"
+msgstr "몰입형 모드"
+
+msgid "Support Small"
+msgstr "소형 화면 지원"
+
+msgid "Support Normal"
+msgstr "중형 화면 지원"
+
+msgid "Support Large"
+msgstr "대형 화면 지원"
+
+msgid "Support Xlarge"
+msgstr "초대형 화면 지원"
+
+msgid "User Data Backup"
+msgstr "유저 데이터 백업"
+
+msgid "Allow"
+msgstr "허용"
+
+msgid "Command Line"
+msgstr "명령줄 인수"
+
msgid "Extra Args"
msgstr "추가적인 인수"
+msgid "APK Expansion"
+msgstr "APK 확장"
+
+msgid "Salt"
+msgstr "솔트"
+
+msgid "Public Key"
+msgstr "공개 키"
+
+msgid "Permissions"
+msgstr "권한"
+
+msgid "Custom Permissions"
+msgstr "커스텀 권한"
+
msgid "Icons"
msgstr "아이콘"
+msgid "iPhone 120 X 120"
+msgstr "iPhone 120 X 120"
+
+msgid "iPhone 180 X 180"
+msgstr "iPhone 180 X 180"
+
+msgid "iPad 76 X 76"
+msgstr "iPad 76 X 76"
+
+msgid "iPad 152 X 152"
+msgstr "iPad 152 X 152"
+
+msgid "iPad 167 X 167"
+msgstr "iPad 167 X 167"
+
+msgid "App Store 1024 X 1024"
+msgstr "App Store 1024 X 1024"
+
+msgid "Spotlight 40 X 40"
+msgstr "Spotlight 40 X 40"
+
+msgid "Spotlight 80 X 80"
+msgstr "Spotlight 80 X 80"
+
+msgid "Settings 58 X 58"
+msgstr "설정 58 X 58"
+
+msgid "Settings 87 X 87"
+msgstr "설정 87 X 87"
+
+msgid "Notification 40 X 40"
+msgstr "알림 40 X 40"
+
+msgid "Notification 60 X 60"
+msgstr "알림 60 X 60"
+
+msgid "Landscape Launch Screens"
+msgstr "가로 모드 실행 화면"
+
+msgid "iPhone 2436 X 1125"
+msgstr "iPhone 2436 X 1125"
+
+msgid "iPhone 2208 X 1242"
+msgstr "iPhone 2208 X 1242"
+
+msgid "iPad 1024 X 768"
+msgstr "iPad 1024 X 768"
+
+msgid "iPad 2048 X 1536"
+msgstr "iPad 1024 X 768"
+
+msgid "Portrait Launch Screens"
+msgstr "세로 모드 실행 화면"
+
+msgid "iPhone 640 X 960"
+msgstr "iPhone 640 X 960"
+
+msgid "iPhone 640 X 1136"
+msgstr "iPhone 640 X 1136"
+
+msgid "iPhone 750 X 1334"
+msgstr "iPhone 750 X 1334"
+
+msgid "iPhone 1125 X 2436"
+msgstr "iPhone 1125 X 2436"
+
+msgid "iPad 768 X 1024"
+msgstr "iPad 768 X 1024"
+
+msgid "iPad 1536 X 2048"
+msgstr "iPad 1536 X 2048"
+
+msgid "iPhone 1242 X 2208"
+msgstr "iPhone 1242 X 2208"
+
+msgid "App Store Team ID"
+msgstr "App Store 팀 ID"
+
+msgid "Provisioning Profile UUID Debug"
+msgstr "권한 설정 프로파일 UUID 디버그"
+
+msgid "Code Sign Identity Debug"
+msgstr "코드 서명 ID 디버그"
+
+msgid "Export Method Debug"
+msgstr "내보내기 방법 디버그"
+
+msgid "Provisioning Profile UUID Release"
+msgstr "권한 설정 프로파일 UUID 릴리즈"
+
+msgid "Code Sign Identity Release"
+msgstr "코드 서명 ID 릴리즈"
+
msgid "Export Method Release"
-msgstr "내보내기 모드 출시"
+msgstr "내보내기 방법 릴리즈"
+
+msgid "Targeted Device Family"
+msgstr "목표 디바이스 제품군"
+
+msgid "Bundle Identifier"
+msgstr "번들 식별자"
+
+msgid "Signature"
+msgstr "서명"
+
+msgid "Short Version"
+msgstr "짧은 버전"
+
+msgid "Icon Interpolation"
+msgstr "아이콘 보간"
+
+msgid "Launch Screens Interpolation"
+msgstr "실행 화면 보간"
+
+msgid "Capabilities"
+msgstr "앱 기능"
msgid "Access Wi-Fi"
msgstr "Wi-Fi 연결"
@@ -2313,9 +3718,141 @@ msgstr "Wi-Fi 연결"
msgid "Push Notifications"
msgstr "푸시 알림"
+msgid "User Data"
+msgstr "유저 데이터"
+
+msgid "Accessible From Files App"
+msgstr "파일 앱에서 접근 가능"
+
+msgid "Accessible From iTunes Sharing"
+msgstr "iTunes 공유에서 접근 가능"
+
+msgid "Privacy"
+msgstr "프라이버시"
+
+msgid "Camera Usage Description"
+msgstr "카메라 사용 설명"
+
+msgid "Camera Usage Description Localized"
+msgstr "카메라 사용 설명 현지화됨"
+
+msgid "Microphone Usage Description"
+msgstr "마이크 사용 설명"
+
+msgid "Microphone Usage Description Localized"
+msgstr "마이크 사용 설명 현지화됨"
+
+msgid "Photolibrary Usage Description"
+msgstr "사진 보관함 사용 설명"
+
+msgid "Photolibrary Usage Description Localized"
+msgstr "사진 보관함 사용 설명 현지화됨"
+
+msgid "Storyboard"
+msgstr "스토리보드"
+
+msgid "Use Launch Screen Storyboard"
+msgstr "실행 화면 스토리보드 사용"
+
+msgid "Image Scale Mode"
+msgstr "이미지 스케일 모드"
+
+msgid "Custom Image @2x"
+msgstr "커스텀 이미지 @ 2x"
+
+msgid "Custom Image @3x"
+msgstr "커스텀 이미지 @ 3x"
+
+msgid "Use Custom BG Color"
+msgstr "커스텀 배경색 사용"
+
+msgid "Custom BG Color"
+msgstr "커스텀 배경색"
+
+msgid "Architecture"
+msgstr "아키텍쳐"
+
+msgid "SSH Remote Deploy"
+msgstr "SSH 원격 배포"
+
+msgid "Extra Args SSH"
+msgstr "SSH 추가적인 인수"
+
+msgid "Extra Args SCP"
+msgstr "SCP 추가적인 인수"
+
+msgid "Run Script"
+msgstr "실행 스크립트"
+
+msgid "Cleanup Script"
+msgstr "클린업 스크립트"
+
+msgid "macOS"
+msgstr "macOS"
+
+msgid "rcodesign"
+msgstr "rcodesign"
+
+msgid "Distribution Type"
+msgstr "배포 타입"
+
+msgid "Copyright"
+msgstr "저작권"
+
+msgid "Copyright Localized"
+msgstr "저작권 현지화됨"
+
+msgid "Min macOS Version"
+msgstr "최소 macOS 버전"
+
+msgid "High Res"
+msgstr "고해상도"
+
+msgid "Xcode"
+msgstr "XCode"
+
+msgid "Platform Build"
+msgstr "플랫폼 빌드"
+
+msgid "SDK Version"
+msgstr "SDK 버전"
+
+msgid "SDK Build"
+msgstr "SDK 빌드"
+
+msgid "SDK Name"
+msgstr "SDK 이름"
+
+msgid "Xcode Version"
+msgstr "XCode 버전"
+
+msgid "Xcode Build"
+msgstr "Xcode 빌드"
+
+msgid "Codesign"
+msgstr "코드 서명"
+
+msgid "Installer Identity"
+msgstr "인스톨러 아이덴티티"
+
+msgid "Apple Team ID"
+msgstr "Apple 팀 ID"
+
+msgid "Identity"
+msgstr "아이덴티티"
+
+msgid "Certificate File"
+msgstr "인증서 파일"
+
+msgid "Certificate Password"
+msgstr "인증서 암호"
+
msgid "Location"
msgstr "위치"
+msgid "UWP"
+msgstr "UWP"
+
msgid "Product GUID"
msgstr "제품 GUID"
@@ -2331,9 +3868,108 @@ msgstr "풍경"
msgid "Tiles"
msgstr "타일"
+msgid "Web"
+msgstr "웹"
+
+msgid "HTTP Host"
+msgstr "HTTP 호스트"
+
+msgid "HTTP Port"
+msgstr "HTTP 포트"
+
+msgid "Use TLS"
+msgstr "TLS 사용"
+
+msgid "TLS Key"
+msgstr "TLS 키"
+
+msgid "TLS Certificate"
+msgstr "TLS 인증서"
+
msgid "Variant"
msgstr "변종"
+msgid "Extensions Support"
+msgstr "확장 기능 지원"
+
+msgid "VRAM Texture Compression"
+msgstr "VRAM 텍스처 압축"
+
+msgid "For Desktop"
+msgstr "데스크탑용"
+
+msgid "For Mobile"
+msgstr "모바일용"
+
+msgid "HTML"
+msgstr "HTML"
+
+msgid "Export Icon"
+msgstr "내보내기 아이콘"
+
+msgid "Custom HTML Shell"
+msgstr "커스텀 HTML 셸"
+
+msgid "Head Include"
+msgstr "Head에 포함"
+
+msgid "Canvas Resize Policy"
+msgstr "Canvas 크기 조정 방식"
+
+msgid "Focus Canvas on Start"
+msgstr "시작할 때 Canvas에 포커스"
+
+msgid "Experimental Virtual Keyboard"
+msgstr "실험용 가상 키보드"
+
+msgid "Progressive Web App"
+msgstr "프로그레시브 웹 앱"
+
+msgid "Offline Page"
+msgstr "오프라인 페이지"
+
+msgid "Icon 144 X 144"
+msgstr "아이콘 144 X 144"
+
+msgid "Icon 180 X 180"
+msgstr "아이콘 180 X 180"
+
+msgid "Icon 512 X 512"
+msgstr "아이콘 512 X 512"
+
+msgid "Windows"
+msgstr "Windows"
+
+msgid "rcedit"
+msgstr "rcedit"
+
+msgid "osslsigncode"
+msgstr "osslsigncode"
+
+msgid "wine"
+msgstr "wine"
+
+msgid "Identity Type"
+msgstr "아이덴티티 종류"
+
+msgid "Timestamp"
+msgstr "타임스탬프"
+
+msgid "Timestamp Server URL"
+msgstr "타임스탬프 서버 URL"
+
+msgid "Digest Algorithm"
+msgstr "해시 알고리즘"
+
+msgid "Modify Resources"
+msgstr "리소스 수정"
+
+msgid "Console Wrapper Icon"
+msgstr "콘솔 래퍼 아이콘"
+
+msgid "File Version"
+msgstr "파일 버전"
+
msgid "Product Version"
msgstr "제품 버전"
@@ -2343,51 +3979,342 @@ msgstr "회사 이름"
msgid "Product Name"
msgstr "제품 이름"
+msgid "File Description"
+msgstr "파일 설명"
+
+msgid "Trademarks"
+msgstr "상표"
+
+msgid "Sprite Frames"
+msgstr "스프라이트 프레임"
+
msgid "Frame"
msgstr "프레임"
+msgid "Speed Scale"
+msgstr "속도 배수"
+
+msgid "Centered"
+msgstr "가운데 맞춤"
+
+msgid "Flip H"
+msgstr "가로 뒤집기"
+
+msgid "Flip V"
+msgstr "세로 뒤집기"
+
+msgid "Monitoring"
+msgstr "모니터링"
+
+msgid "Monitorable"
+msgstr "모니터링 가능"
+
+msgid "Gravity"
+msgstr "중력"
+
msgid "Space Override"
msgstr "공간 오버라이드"
msgid "Point"
msgstr "점"
+msgid "Point Unit Distance"
+msgstr "점 유닛 거리"
+
+msgid "Point Center"
+msgstr "점 중간"
+
+msgid "Direction"
+msgstr "방향"
+
+msgid "Linear Damp"
+msgstr "선형 댐핑"
+
+msgid "Angular Damp"
+msgstr "각도 댐핑"
+
+msgid "Audio Bus"
+msgstr "오디오 버스"
+
msgid "Current"
-msgstr "현재"
+msgstr "사용 중"
+
+msgid "Volume dB"
+msgstr "음량 dB"
+
+msgid "Pitch Scale"
+msgstr "피치 스케일"
+
+msgid "Playing"
+msgstr "재생"
+
+msgid "Autoplay"
+msgstr "자동 재생"
+
+msgid "Stream Paused"
+msgstr "재생 일시정지"
msgid "Max Distance"
msgstr "최대 거리"
+msgid "Attenuation"
+msgstr "감쇠량"
+
+msgid "Max Polyphony"
+msgstr "최대 동시재생"
+
+msgid "Panning Strength"
+msgstr "패닝 강도"
+
+msgid "Bus"
+msgstr "버스"
+
+msgid "Area Mask"
+msgstr "구역 마스크"
+
+msgid "Copy Mode"
+msgstr "복사 모드"
+
+msgid "Anchor Mode"
+msgstr "앵커 모드"
+
+msgid "Ignore Rotation"
+msgstr "회전 무시"
+
+msgid "Process Callback"
+msgstr "Process 콜백"
+
msgid "Left"
msgstr "왼쪽"
msgid "Top"
-msgstr "맨 위"
+msgstr "위쪽"
msgid "Right"
msgstr "오른쪽"
+msgid "Bottom"
+msgstr "아래쪽"
+
+msgid "Smoothed"
+msgstr "부드럽게 하기"
+
+msgid "Position Smoothing"
+msgstr "부드러운 위치 이동"
+
+msgid "Rotation Smoothing"
+msgstr "부드러운 회전"
+
+msgid "Drag"
+msgstr "드래그"
+
+msgid "Horizontal Enabled"
+msgstr "가로 활성화"
+
+msgid "Vertical Enabled"
+msgstr "세로 활성화"
+
+msgid "Horizontal Offset"
+msgstr "가로 오프셋"
+
+msgid "Vertical Offset"
+msgstr "세로 오프셋"
+
+msgid "Left Margin"
+msgstr "왼쪽 마진"
+
+msgid "Top Margin"
+msgstr "위쪽 마진"
+
+msgid "Right Margin"
+msgstr "오른쪽 마진"
+
+msgid "Bottom Margin"
+msgstr "아래쪽 마진"
+
+msgid "Draw Screen"
+msgstr "화면 그리기"
+
+msgid "Draw Limits"
+msgstr "제한 그리기"
+
+msgid "Draw Drag Margin"
+msgstr "드래그 마진 그리기"
+
+msgid "Tweaks"
+msgstr "트윅"
+
+msgid "Fit Margin"
+msgstr "여백에 맞추기"
+
+msgid "Clear Margin"
+msgstr "여백 비우기"
+
+msgid "Use Mipmaps"
+msgstr "밉맵 사용"
+
+msgid "Disable Mode"
+msgstr "비활성화 모드"
+
msgid "Input"
msgstr "입력"
+msgid "Disabled"
+msgstr "비활성화됨"
+
+msgid "One Way Collision"
+msgstr "일방향 충돌"
+
+msgid "One Way Collision Margin"
+msgstr "일방향 충돌 간격"
+
+msgid "Debug Color"
+msgstr "디버그 색상"
+
+msgid "Emitting"
+msgstr "방출"
+
msgid "Time"
msgstr "시간"
+msgid "Lifetime"
+msgstr "수명"
+
+msgid "One Shot"
+msgstr "원샷"
+
+msgid "Preprocess"
+msgstr "전처리"
+
+msgid "Explosiveness"
+msgstr "폭발성"
+
msgid "Randomness"
msgstr "무작위성"
+msgid "Lifetime Randomness"
+msgstr "수명 무작위성"
+
+msgid "Fixed FPS"
+msgstr "고정 FPS"
+
+msgid "Draw Order"
+msgstr "그리기 순서"
+
msgid "Points"
msgstr "점"
+msgid "Normals"
+msgstr "노멀"
+
msgid "Colors"
msgstr "색상"
+msgid "Linear Accel"
+msgstr "선형 가속도"
+
msgid "Accel Min"
msgstr "최소 가속도"
msgid "Accel Max"
msgstr "최대 가속도"
+msgid "Accel Curve"
+msgstr "가속도 곡선"
+
+msgid "Radial Accel"
+msgstr "방사형 가속도"
+
+msgid "Tangential Accel"
+msgstr "접선 가속도"
+
+msgid "Damping"
+msgstr "댐핑"
+
+msgid "Damping Min"
+msgstr "최소 댐핑"
+
+msgid "Damping Max"
+msgstr "최대 댐핑"
+
+msgid "Damping Curve"
+msgstr "댐핑 곡선"
+
+msgid "Angle"
+msgstr "각도"
+
+msgid "Angle Min"
+msgstr "최대 각도"
+
+msgid "Angle Max"
+msgstr "최소 각도"
+
+msgid "Angle Curve"
+msgstr "각도 곡선"
+
+msgid "Interpolate"
+msgstr "보간"
+
+msgid "Trails"
+msgstr "자취"
+
+msgid "Bias"
+msgstr "바이어스"
+
+msgid "Length"
+msgstr "길이"
+
+msgid "Initial Offset"
+msgstr "초기 오프셋"
+
+msgid "Editor Only"
+msgstr "에디터 전용"
+
+msgid "Energy"
+msgstr "에너지"
+
+msgid "Blend Mode"
+msgstr "혼합 모드"
+
+msgid "Z Min"
+msgstr "최소 Z"
+
+msgid "Z Max"
+msgstr "최대 Z"
+
+msgid "Layer Min"
+msgstr "최소 레이어"
+
+msgid "Layer Max"
+msgstr "최대 레이어"
+
+msgid "Item Cull Mask"
+msgstr "개체 컬 마스크"
+
+msgid "Shadow"
+msgstr "그림자"
+
+msgid "Filter Smooth"
+msgstr "부드럽게 필터"
+
+msgid "Texture Scale"
+msgstr "텍스처 스케일"
+
+msgid "Closed"
+msgstr "닫힘"
+
+msgid "Cull Mode"
+msgstr "컬 모드"
+
+msgid "SDF Collision"
+msgstr "SDF 콜리전"
+
+msgid "Default Color"
+msgstr "기본 색"
+
+msgid "Fill"
+msgstr "채우기"
+
msgid "Path Max Distance"
msgstr "경로 최대 거리"
@@ -2397,27 +4324,63 @@ msgstr "내비게이션 레이어"
msgid "Max Speed"
msgstr "최대 속도"
+msgid "Skew"
+msgstr "기울임"
+
+msgid "Scroll"
+msgstr "스크롤"
+
msgid "Base Offset"
msgstr "기본 오프셋"
+msgid "Base Scale"
+msgstr "기본 스케일"
+
+msgid "Limit Begin"
+msgstr "제한범위 시작"
+
+msgid "Limit End"
+msgstr "제한범위 끝"
+
+msgid "Ignore Camera Zoom"
+msgstr "카메라 줌 무시"
+
+msgid "Progress"
+msgstr "진행도"
+
+msgid "Progress Ratio"
+msgstr "진행도 비율"
+
msgid "H Offset"
msgstr "가로 오프셋"
msgid "V Offset"
msgstr "세로 오프셋"
+msgid "Rotates"
+msgstr "회전함"
+
+msgid "Cubic Interp"
+msgstr "입방형 보간"
+
msgid "Physics Material Override"
msgstr "물리 머티리얼 오버라이드"
msgid "Inertia"
msgstr "관성"
+msgid "Sleeping"
+msgstr "슬립 중"
+
msgid "Can Sleep"
msgstr "슬립 가능"
msgid "Linear"
msgstr "직선형"
+msgid "Torque"
+msgstr "토크"
+
msgid "Max Angle"
msgstr "최대 각도"
@@ -2439,30 +4402,189 @@ msgstr "업데이트"
msgid "Editor Settings"
msgstr "에디터 설정"
+msgid "Tile Set"
+msgstr "타일셋"
+
+msgid "Layers"
+msgstr "레이어"
+
msgid "Bitmask"
msgstr "비트 마스크"
+msgid "Enabling"
+msgstr "활성화함"
+
+msgid "Wind"
+msgstr "바람"
+
+msgid "Reverb Bus"
+msgstr "리버브 버스"
+
+msgid "Max dB"
+msgstr "최대 dB"
+
msgid "Degrees"
msgstr "각도"
+msgid "Cutoff Hz"
+msgstr "컷오프 Hz"
+
msgid "dB"
msgstr "dB"
+msgid "Doppler"
+msgstr "도플러 효과"
+
+msgid "Keep Aspect"
+msgstr "비율 유지"
+
+msgid "Cull Mask"
+msgstr "컬 마스크"
+
+msgid "Attributes"
+msgstr "속성"
+
+msgid "Doppler Tracking"
+msgstr "도플러 효과"
+
+msgid "Projection"
+msgstr "투상"
+
+msgid "Frustum Offset"
+msgstr "절두체 오프셋"
+
+msgid "Near"
+msgstr "근경"
+
+msgid "Far"
+msgstr "원경"
+
+msgid "Albedo"
+msgstr "알베도"
+
+msgid "Normal"
+msgstr "노멀"
+
+msgid "Emission"
+msgstr "방출"
+
+msgid "Parameters"
+msgstr "매개변수"
+
+msgid "Emission Energy"
+msgstr "방출 에너지"
+
msgid "Modulate"
msgstr "변조"
+msgid "Begin"
+msgstr "시작점"
+
+msgid "Visibility AABB"
+msgstr "가시성 AABB"
+
+msgid "X"
+msgstr "X"
+
+msgid "Y"
+msgstr "Y"
+
+msgid "Z"
+msgstr "Z"
+
+msgid "Equilibrium Point"
+msgstr "평형점"
+
+msgid "ERP"
+msgstr "ERP"
+
+msgid "Pixel Size"
+msgstr "픽셀 크기"
+
msgid "Flags"
msgstr "플래그"
+msgid "Billboard"
+msgstr "빌보드"
+
+msgid "Shaded"
+msgstr "셰이딩 받음"
+
+msgid "Double Sided"
+msgstr "양면"
+
+msgid "No Depth Test"
+msgstr "깊이 테스트 없음"
+
+msgid "Fixed Size"
+msgstr "고정 크기"
+
+msgid "Alpha Cut"
+msgstr "알파 자르기"
+
+msgid "Alpha Scissor Threshold"
+msgstr "알파 가위 역치값"
+
+msgid "Alpha Hash Scale"
+msgstr "알파 해시 스케일"
+
+msgid "Alpha Antialiasing Mode"
+msgstr "알파 안티앨리어싱 모드"
+
+msgid "Alpha Antialiasing Edge"
+msgstr "알파 안티앨리어싱 윤곽선"
+
+msgid "Texture Filter"
+msgstr "텍스처 필터"
+
msgid "Render Priority"
msgstr "렌더 우선 순위"
+msgid "Outline Render Priority"
+msgstr "윤곽선 렌더 우선순위"
+
msgid "Text"
msgstr "텍스트"
+msgid "Outline Modulate"
+msgstr "윤곽선 조정"
+
+msgid "Font"
+msgstr "글꼴"
+
+msgid "Horizontal Alignment"
+msgstr "가로 정렬"
+
+msgid "Vertical Alignment"
+msgstr "세로 정렬"
+
msgid "Uppercase"
msgstr "대문자로"
+msgid "BiDi"
+msgstr "BiDi"
+
+msgid "Text Direction"
+msgstr "텍스트 방향"
+
+msgid "Intensity Lumens"
+msgstr "강도 루멘"
+
+msgid "Intensity Lux"
+msgstr "강도 럭스"
+
+msgid "Temperature"
+msgstr "색온도"
+
+msgid "Indirect Energy"
+msgstr "간접광 에너지"
+
+msgid "Volumetric Fog Energy"
+msgstr "볼류메트릭 안개 에너지"
+
+msgid "Opacity"
+msgstr "투명도"
+
msgid "Blur"
msgstr "흐림"
@@ -2472,14 +4594,53 @@ msgstr "품질"
msgid "Use Denoiser"
msgstr "노이즈 감소 사용"
+msgid "Visibility"
+msgstr "가시성"
+
+msgid "Visible"
+msgstr "볼 수 있음"
+
+msgid "Visibility Parent"
+msgstr "가시성 부모"
+
+msgid "Bake"
+msgstr "굽기"
+
+msgid "Rotation Mode"
+msgstr "회전 모드"
+
+msgid "Axis Lock"
+msgstr "축 잠금"
+
+msgid "Linear X"
+msgstr "선형 X"
+
+msgid "Linear Y"
+msgstr "선형 Y"
+
+msgid "Linear Z"
+msgstr "선형 Z"
+
+msgid "Angular X"
+msgstr "각 X"
+
+msgid "Angular Y"
+msgstr "각 Y"
+
+msgid "Angular Z"
+msgstr "각 Z"
+
msgid "Enable Shadows"
msgstr "그림자 켜기"
msgid "Bones"
msgstr "본"
+msgid "Interpolation"
+msgstr "보간"
+
msgid "Target"
-msgstr "Target(대상)"
+msgstr "대상"
msgid "Use Magnet"
msgstr "자석 사용"
@@ -2532,12 +4693,18 @@ msgstr "무작위 지연"
msgid "Request"
msgstr "요청"
+msgid "Active"
+msgstr "활성"
+
msgid "Reset"
msgstr "되돌리기"
msgid "Switch"
msgstr "스위치"
+msgid "Advance"
+msgstr "진행"
+
msgid "Condition"
msgstr "조건"
@@ -2547,14 +4714,86 @@ msgstr "표현"
msgid "Root Node"
msgstr "루트 노드"
+msgid "Alignment"
+msgstr "정렬"
+
msgid "Button Group"
msgstr "버튼 그룹"
+msgid "Indentation"
+msgstr "들여쓰기"
+
+msgid "Theme Overrides"
+msgstr "테마 오버라이드"
+
+msgid "Constants"
+msgstr "제약"
+
+msgid "Font Sizes"
+msgstr "글꼴 크기"
+
+msgid "Styles"
+msgstr "스타일"
+
+msgid "Clip Contents"
+msgstr "내용물 자르기"
+
+msgid "Custom Minimum Size"
+msgstr "커스텀 최소 크기"
+
+msgid "Layout Direction"
+msgstr "레이아웃 방향"
+
+msgid "Layout Mode"
+msgstr "레이아웃 모드"
+
+msgid "Anchors Preset"
+msgstr "앵커 프리셋"
+
+msgid "Anchor Points"
+msgstr "앵커 지점"
+
+msgid "Anchor Offsets"
+msgstr "앵커 오프셋"
+
+msgid "Grow Direction"
+msgstr "자라날 방향"
+
+msgid "Pivot Offset"
+msgstr "회전축 오프셋"
+
+msgid "Container Sizing"
+msgstr "컨테이너 크기"
+
+msgid "Stretch Ratio"
+msgstr "늘림 비율"
+
msgid "Localization"
msgstr "현지화"
msgid "Auto Translate"
-msgstr "자동 옮기기"
+msgstr "자동 번역"
+
+msgid "Localize Numeral System"
+msgstr "숫자 체계 현지화"
+
+msgid "Tooltip"
+msgstr "툴팁"
+
+msgid "Focus"
+msgstr "포커스"
+
+msgid "Neighbor Left"
+msgstr "왼쪽 이웃"
+
+msgid "Neighbor Top"
+msgstr "위쪽 이웃"
+
+msgid "Neighbor Right"
+msgstr "오른쪽 이웃"
+
+msgid "Neighbor Bottom"
+msgstr "아래쪽 이웃"
msgid "Next"
msgstr "다음"
@@ -2562,11 +4801,71 @@ msgstr "다음"
msgid "Previous"
msgstr "이전"
+msgid "Mouse"
+msgstr "마우스"
+
+msgid "Force Pass Scroll Events"
+msgstr "강제로 스크롤 이벤트 넘겨주기"
+
+msgid "Default Cursor Shape"
+msgstr "기본 커서 모양"
+
+msgid "Shortcut Context"
+msgstr "단축키 문맥"
+
+msgid "Type Variation"
+msgstr "타입 바리에이션"
+
+msgid "OK Button Text"
+msgstr "확인 버튼 텍스트"
+
+msgid "Dialog"
+msgstr "창"
+
+msgid "Hide on OK"
+msgstr "확인 시 숨기기"
+
+msgid "Close on Escape"
+msgstr "ESC 시 닫기"
+
+msgid "Autowrap"
+msgstr "자동 줄바꿈"
+
+msgid "Cancel Button Text"
+msgstr "취소 버튼 텍스트"
+
+msgid "Mode Overrides Title"
+msgstr "모드가 제목을 정함"
+
+msgid "Root Subfolder"
+msgstr "루트 서브폴더"
+
msgid "Use Snap"
msgstr "스냅 사용"
+msgid "UI"
+msgstr "UI"
+
+msgid "Selected"
+msgstr "선택됨"
+
+msgid "Comment"
+msgstr "주석"
+
+msgid "Overlay"
+msgstr "오버레이"
+
msgid "Select Mode"
-msgstr "모드 선택"
+msgstr "선택 모드"
+
+msgid "Allow Reselect"
+msgstr "재선택 허용"
+
+msgid "Allow RMB Select"
+msgstr "우클릭 선택 허용"
+
+msgid "Allow Search"
+msgstr "검색 허용"
msgid "Items"
msgstr "항목"
@@ -2574,24 +4873,240 @@ msgstr "항목"
msgid "Icon Mode"
msgstr "아이콘 모드"
+msgid "Label Settings"
+msgstr "라벨 설정"
+
+msgid "Tab Stops"
+msgstr "탭 정지점"
+
+msgid "Displayed Text"
+msgstr "표시되는 텍스트"
+
+msgid "Lines Skipped"
+msgstr "건너뛴 줄"
+
+msgid "Max Lines Visible"
+msgstr "표시할 최대 줄 수"
+
+msgid "Visible Characters"
+msgstr "표시할 글자 수"
+
+msgid "Visible Characters Behavior"
+msgstr "표시할 글자 행동"
+
+msgid "Visible Ratio"
+msgstr "표시할 글자 비율"
+
+msgid "Placeholder Text"
+msgstr "플레이스홀더 텍스트"
+
+msgid "Max Length"
+msgstr "최대 길이"
+
+msgid "Secret"
+msgstr "비밀번호"
+
+msgid "Secret Character"
+msgstr "비밀번호 문자"
+
+msgid "Expand to Text Length"
+msgstr "텍스트 길이에 따라 늘어남"
+
+msgid "Context Menu Enabled"
+msgstr "우클릭 메뉴 허용"
+
+msgid "Virtual Keyboard Enabled"
+msgstr "가상 키보드 허용"
+
+msgid "Virtual Keyboard Type"
+msgstr "가상 키보드 타입"
+
+msgid "Clear Button Enabled"
+msgstr "전체 삭제 버튼 허용"
+
+msgid "Shortcut Keys Enabled"
+msgstr "단축키 허용"
+
+msgid "Middle Mouse Paste Enabled"
+msgstr "휠 클릭시 붙여넣기 허용"
+
+msgid "Selecting Enabled"
+msgstr "텍스트 선택 허용"
+
+msgid "Deselect on Focus Loss Enabled"
+msgstr "포커스 잃을 시 텍스트 선택 해제"
+
+msgid "Right Icon"
+msgstr "우측 아이콘"
+
+msgid "Draw Control Chars"
+msgstr "제어 문자 표시"
+
+msgid "Select All on Focus"
+msgstr "포커스를 얻을 때 전체 선택"
+
+msgid "Blink"
+msgstr "깜빡이기"
+
+msgid "Blink Interval"
+msgstr "깜빡임 간격"
+
+msgid "Column"
+msgstr "열"
+
+msgid "Force Displayed"
+msgstr "항상 보이기"
+
+msgid "Mid Grapheme"
+msgstr "조합형 문자 단위 편집"
+
+msgid "Underline"
+msgstr "밑줄"
+
+msgid "URI"
+msgstr "URI"
+
+msgid "Start Index"
+msgstr "시작 인덱스"
+
msgid "Step"
msgstr "단계"
msgid "Syntax Highlighter"
msgstr "구문 강조"
+msgid "Smooth"
+msgstr "부드럽게"
+
+msgid "Past End of File"
+msgstr "파일의 끝을 넘어서"
+
+msgid "Fit Content Height"
+msgstr "내용물 높이에 맞추기"
+
+msgid "Draw"
+msgstr "그리기"
+
+msgid "Draw When Editable Disabled"
+msgstr "편집 불가능할 때도 그리기"
+
+msgid "Hover"
+msgstr "호버"
+
+msgid "Focused"
+msgstr "포커스"
+
+msgid "Tint"
+msgstr "색조"
+
+msgid "Paused"
+msgstr "일시정지"
+
+msgid "Expand"
+msgstr "확장"
+
+msgid "Self Modulate"
+msgstr "자신 변조"
+
+msgid "Show Behind Parent"
+msgstr "부모 뒤에 그리기"
+
+msgid "Clip Children"
+msgstr "자식 자르기"
+
+msgid "Light Mask"
+msgstr "광원 마스크"
+
+msgid "Visibility Layer"
+msgstr "가시성 레이어"
+
+msgid "Ordering"
+msgstr "순서"
+
msgid "Z Index"
msgstr "Z 인덱스"
+msgid "Z as Relative"
+msgstr "Z를 상대값으로"
+
+msgid "Y Sort Enabled"
+msgstr "Y 정렬 사용"
+
msgid "Repeat"
msgstr "반복"
+msgid "Use Parent Material"
+msgstr "부모 머티리얼 사용"
+
+msgid "NormalMap"
+msgstr "노멀 맵"
+
+msgid "Follow Viewport"
+msgstr "뷰포트 따라가기"
+
+msgid "Download File"
+msgstr "다운로드 파일"
+
+msgid "Download Chunk Size"
+msgstr "다운로드 청크 크기"
+
+msgid "Accept Gzip"
+msgstr "Gzip 허용"
+
+msgid "Body Size Limit"
+msgstr "본문 크기 제한"
+
+msgid "Max Redirects"
+msgstr "최대 리다이렉트 수"
+
+msgid "Timeout"
+msgstr "최대 대기 시간"
+
msgid "Transfer Mode"
msgstr "전송 모드"
msgid "Transfer Channel"
msgstr "전송 채널"
+msgid "Node Name Num Separator"
+msgstr "노드 이름 숫자 구분자"
+
+msgid "Node Name Casing"
+msgstr "노드 이름 대소문자"
+
+msgid "Physics Priority"
+msgstr "물리 우선순위"
+
+msgid "Thread Group"
+msgstr "스레드 그룹"
+
+msgid "Group"
+msgstr "그룹"
+
+msgid "Group Order"
+msgstr "그룹 순서"
+
+msgid "Messages"
+msgstr "메시지"
+
+msgid "Editor Description"
+msgstr "에디터상 설명"
+
+msgid "Time Left"
+msgstr "남은 시간"
+
+msgid "MSAA 2D"
+msgstr "MSAA 2D"
+
+msgid "MSAA 3D"
+msgstr "MSAA 3D"
+
+msgid "VRS"
+msgstr "VRS"
+
+msgid "SDF"
+msgstr "SDF"
+
msgid "Audio Listener"
msgstr "오디오 리스너"
@@ -2637,15 +5152,60 @@ msgstr "메뉴 강조"
msgid "Node"
msgstr "노드"
+msgid "Sky"
+msgstr "스카이"
+
msgid "Source"
msgstr "소스"
+msgid "Tonemap"
+msgstr "톤맵"
+
+msgid "SSR"
+msgstr "SSR"
+
+msgid "SSAO"
+msgstr "SSAO"
+
+msgid "SSIL"
+msgstr "SSIL"
+
+msgid "SDFGI"
+msgstr "SDFGI"
+
+msgid "Glow"
+msgstr "빛번짐"
+
+msgid "1"
+msgstr "1"
+
+msgid "2"
+msgstr "2"
+
+msgid "3"
+msgstr "3"
+
+msgid "4"
+msgstr "4"
+
+msgid "5"
+msgstr "5"
+
+msgid "6"
+msgstr "6"
+
+msgid "7"
+msgstr "7"
+
msgid "Mix"
msgstr "믹스"
msgid "Bloom"
msgstr "블룸"
+msgid "Fog"
+msgstr "포그"
+
msgid "Features"
msgstr "기능"
@@ -2661,18 +5221,39 @@ msgstr "연산자"
msgid "Subsurface Scattering"
msgstr "서브서피스 산란"
+msgid "UV1"
+msgstr "UV1"
+
+msgid "UV2"
+msgstr "UV2"
+
+msgid "H Frames"
+msgstr "가로 프레임 수"
+
+msgid "V Frames"
+msgstr "세로 프레임 수"
+
+msgid "MSDF"
+msgstr "MSDF"
+
msgid "Item"
msgstr "항목"
msgid "Preview"
msgstr "미리보기"
+msgid "A"
+msgstr "A"
+
msgid "B"
msgstr "B"
msgid "Bone"
msgstr "뼈"
+msgid "Ground Color"
+msgstr "땅 색상"
+
msgid "Blend"
msgstr "혼합"
@@ -2688,18 +5269,267 @@ msgstr "오른쪽 아래"
msgid "Bottom Left"
msgstr "왼쪽 아래"
+msgid "Atlas"
+msgstr "아틀라스"
+
+msgid "Terrains"
+msgstr "지형"
+
+msgid "Custom Data"
+msgstr "커스텀 데이터"
+
msgid "Scene"
msgstr "씬"
msgid "Transpose"
msgstr "행렬 맞바꾸기"
+msgid "Probability"
+msgstr "확률"
+
msgid "Constant"
msgstr "상수"
msgid "Function"
msgstr "함수"
+msgid "Degrees Mode"
+msgstr "각도 모드"
+
+msgid "Custom"
+msgstr "커스텀"
+
+msgid "Streams"
+msgstr "스트림"
+
+msgid "Playback Mode"
+msgstr "재생 모드"
+
+msgid "Random Pitch"
+msgstr "무작위 피치"
+
+msgid "Random Volume Offset dB"
+msgstr "무작위 볼륨 오프셋 dB"
+
+msgid "Buffer Length"
+msgstr "버퍼 길이"
+
+msgid "Voice Count"
+msgstr "보이스 개수"
+
+msgid "Voice"
+msgstr "보이스"
+
+msgid "Delay (ms)"
+msgstr "딜레이 (ms)"
+
+msgid "Rate Hz"
+msgstr "빈도 Hz"
+
+msgid "Depth (ms)"
+msgstr "깊이 (ms)"
+
+msgid "Level dB"
+msgstr "레벨 dB"
+
+msgid "Pan"
+msgstr "패닝"
+
+msgid "Attack (µs)"
+msgstr "어택 (µs)"
+
+msgid "Release (ms)"
+msgstr "릴리즈 (ms)"
+
+msgid "Sidechain"
+msgstr "사이드체인"
+
+msgid "Tap 1"
+msgstr "탭 1"
+
+msgid "Tap 2"
+msgstr "탭 2"
+
+msgid "Feedback"
+msgstr "피드백"
+
+msgid "Low-pass"
+msgstr "로우패스"
+
+msgid "Pre Gain"
+msgstr "프리 게인"
+
+msgid "Drive"
+msgstr "드라이브"
+
+msgid "Post Gain"
+msgstr "포스트 게인"
+
+msgid "Resonance"
+msgstr "레조넌스"
+
+msgid "Ceiling dB"
+msgstr "천장값 dB"
+
+msgid "Threshold dB"
+msgstr "역치값 dB"
+
+msgid "Soft Clip dB"
+msgstr "소프트 클립 dB"
+
+msgid "Soft Clip Ratio"
+msgstr "소프트 클립 비율"
+
+msgid "Range Min Hz"
+msgstr "범위 최소 Hz"
+
+msgid "Range Max Hz"
+msgstr "범위 최대 Hz"
+
+msgid "FFT Size"
+msgstr "FFT 크기"
+
+msgid "Predelay"
+msgstr "선 딜레이"
+
+msgid "Msec"
+msgstr "밀리초"
+
+msgid "Room Size"
+msgstr "공간 크기"
+
+msgid "High-pass"
+msgstr "하이패스"
+
+msgid "Surround"
+msgstr "서라운드"
+
+msgid "Enable Input"
+msgstr "입력 활성화"
+
+msgid "Output Latency"
+msgstr "출력 레이턴시"
+
+msgid "Channel Disable Threshold dB"
+msgstr "채널 비활성화 역치값 dB"
+
+msgid "Channel Disable Time"
+msgstr "채널 비활성화 시간"
+
+msgid "Video"
+msgstr "비디오"
+
+msgid "Video Delay Compensation (ms)"
+msgstr "비디오 딜레이 보정 (ms)"
+
+msgid "Bus Count"
+msgstr "버스 개수"
+
+msgid "Output Device"
+msgstr "출력 장치"
+
+msgid "Input Device"
+msgstr "입력 장치"
+
+msgid "Playback Speed Scale"
+msgstr "재생 속도 스케일"
+
+msgid "Feed"
+msgstr "피드"
+
+msgid "Is Active"
+msgstr "활성화됨"
+
+msgid "Movie Writer"
+msgstr "영상 제작기"
+
+msgid "Speaker Mode"
+msgstr "스피커 모드"
+
+msgid "MJPEG Quality"
+msgstr "MJPEG 품질"
+
+msgid "Movie File"
+msgstr "영상 파일"
+
+msgid "Disable V-Sync"
+msgstr "수직동기화 비활성화"
+
+msgid "Inverse Mass"
+msgstr "질량의 역수"
+
+msgid "Inverse Inertia"
+msgstr "관성의 역수"
+
+msgid "Total Angular Damp"
+msgstr "총 각도 댐핑"
+
+msgid "Total Linear Damp"
+msgstr "총 선형 댐핑"
+
+msgid "Total Gravity"
+msgstr "총 중력"
+
+msgid "Center of Mass Local"
+msgstr "로컬 질량 중심점"
+
+msgid "Exclude"
+msgstr "제외"
+
+msgid "Collide With Bodies"
+msgstr "물체와 충돌"
+
+msgid "Collide With Areas"
+msgstr "구역과 충돌"
+
+msgid "Canvas Instance ID"
+msgstr "캔버스 인스턴스 ID"
+
+msgid "Shape RID"
+msgstr "모양 RID"
+
+msgid "Default Gravity"
+msgstr "기본 중력"
+
+msgid "Default Gravity Vector"
+msgstr "기본 중력 벡터"
+
+msgid "Default Linear Damp"
+msgstr "기본 선형 댐핑"
+
+msgid "Default Angular Damp"
+msgstr "기본 각도 댐핑"
+
+msgid "Sleep Threshold Linear"
+msgstr "선형 슬립 역치값"
+
+msgid "Sleep Threshold Angular"
+msgstr "각도 슬립 역치값"
+
+msgid "Time Before Sleep"
+msgstr "슬립까지 기다릴 시간"
+
+msgid "Solver"
+msgstr "솔버"
+
+msgid "Solver Iterations"
+msgstr "솔버 반복 횟수"
+
+msgid "Contact Recycle Radius"
+msgstr "접촉 재활용 범위"
+
+msgid "Contact Max Separation"
+msgstr "접촉 최대 분리"
+
+msgid "Physics Engine"
+msgstr "물리 엔진"
+
+msgid "Inverse Inertia Tensor"
+msgstr "역 관성 텐서"
+
+msgid "Max Collisions"
+msgstr "최대 충돌 수"
+
msgid "Vertex"
msgstr "꼭짓점"
@@ -2709,6 +5539,9 @@ msgstr "프래그먼트"
msgid "Vertex Lighting"
msgstr "꼭짓점 조명"
+msgid "Shadow Atlas"
+msgstr "그림자 아틀라스"
+
msgid "Shader Compiler"
msgstr "셰이더 컴파일러"
@@ -2718,12 +5551,18 @@ msgstr "셰이더 캐시"
msgid "Reflections"
msgstr "반사"
+msgid "GI"
+msgstr "GI"
+
msgid "Overrides"
msgstr "오버라이드"
msgid "Global Shader Variables"
msgstr "전역 셰이더 변수"
+msgid "OpenGL"
+msgstr "OpenGL"
+
msgid "Shaders"
msgstr "셰이더"
diff --git a/editor/translations/properties/pl.po b/editor/translations/properties/pl.po
index a3c5ad9d5a..2949d1a275 100644
--- a/editor/translations/properties/pl.po
+++ b/editor/translations/properties/pl.po
@@ -77,7 +77,7 @@ msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-16 02:06+0000\n"
+"PO-Revision-Date: 2023-06-29 16:02+0000\n"
"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot-properties/pl/>\n"
@@ -87,7 +87,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.18.1-dev\n"
+"X-Generator: Weblate 4.18.1\n"
msgid "Application"
msgstr "Aplikacja"
@@ -378,7 +378,7 @@ msgid "Pressed"
msgstr "Wciśnięty"
msgid "Unicode"
-msgstr "Unicode"
+msgstr "Unikod"
msgid "Echo"
msgstr "Echo"
diff --git a/editor/translations/properties/pt_BR.po b/editor/translations/properties/pt_BR.po
index f6512c1f6b..072e55965b 100644
--- a/editor/translations/properties/pt_BR.po
+++ b/editor/translations/properties/pt_BR.po
@@ -163,7 +163,7 @@ msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2023-06-26 09:55+0000\n"
+"PO-Revision-Date: 2023-06-30 06:50+0000\n"
"Last-Translator: Daniel Mucciolo <danielviannapsi@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot-properties/pt_BR/>\n"
@@ -4911,6 +4911,9 @@ msgstr "Nó Raiz"
msgid "Root Motion"
msgstr "Movimento Raiz"
+msgid "Stretch Mode"
+msgstr "Modo Esticado"
+
msgid "Alignment"
msgstr "Alinhamento"
@@ -5142,6 +5145,9 @@ msgstr "Rolagem"
msgid "Split Offset"
msgstr "Deslocamento de Divisão"
+msgid "Stretch Shrink"
+msgstr "Esticar Encolher"
+
msgid "Current Tab"
msgstr "Aba Atual"
diff --git a/editor/translations/properties/ru.po b/editor/translations/properties/ru.po
index 0ecbd86331..34195c65e7 100644
--- a/editor/translations/properties/ru.po
+++ b/editor/translations/properties/ru.po
@@ -56,7 +56,7 @@
# Константин Рин <email.to.rean@gmail.com>, 2019, 2020.
# Maxim Samburskiy <alpacones@outlook.com>, 2019.
# Dima Koshel <form.eater@gmail.com>, 2019.
-# Danil Alexeev <danil@alexeev.xyz>, 2019, 2020, 2021, 2022.
+# Danil Alexeev <danil@alexeev.xyz>, 2019, 2020, 2021, 2022, 2023.
# Ravager <al.porkhunov@gmail.com>, 2019.
# Александр <akonn7@mail.ru>, 2019.
# Rei <clxgamer12@gmail.com>, 2019.
@@ -148,7 +148,7 @@ msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-23 12:55+0000\n"
+"PO-Revision-Date: 2023-07-05 13:49+0000\n"
"Last-Translator: ZIP2020 <folstagking@gmail.com>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot-properties/ru/>\n"
@@ -158,7 +158,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.18.1\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Application"
msgstr "Приложение"
@@ -289,6 +289,12 @@ msgstr "Редактор"
msgid "Script"
msgstr "Скрипт"
+msgid "Subwindows"
+msgstr "Под-окна"
+
+msgid "Embed Subwindows"
+msgstr "Встроенные подокна"
+
msgid "Physics"
msgstr "Физика"
@@ -325,9 +331,18 @@ msgstr "Лимит функций"
msgid "Compression"
msgstr "Сжатие"
+msgid "Formats"
+msgstr "Форматы"
+
+msgid "Long Distance Matching"
+msgstr "Сравнение Длинных Дистанций"
+
msgid "Compression Level"
msgstr "Уровень сжатия"
+msgid "Window Log Size"
+msgstr "Размер Лога Окна"
+
msgid "Crash Handler"
msgstr "Обработчик падений"
@@ -401,7 +416,7 @@ msgid "Pressed"
msgstr "Нажато"
msgid "Unicode"
-msgstr "Юникод"
+msgstr "Unicode"
msgid "Echo"
msgstr "Эхо"
@@ -1336,6 +1351,9 @@ msgstr "Скрыть Slider"
msgid "Multichannel Signed Distance Field"
msgstr "Многоканальное поле расстояния со знаком"
+msgid "Hinting"
+msgstr "Подсказка"
+
msgid "Oversampling"
msgstr "Передискретизация"
@@ -2039,7 +2057,7 @@ msgid "Parent"
msgstr "Родитель"
msgid "Skin"
-msgstr "Скин"
+msgstr "Кожа"
msgid "Children"
msgstr "Дети"
@@ -3406,6 +3424,9 @@ msgstr "Группа кнопок"
msgid "Expand Icon"
msgstr "Расширить иконку"
+msgid "Indentation"
+msgstr "Отступ"
+
msgid "Deferred Mode"
msgstr "Отложенный режим"
@@ -3676,6 +3697,9 @@ msgstr "Сглаживание"
msgid "Atlas Size"
msgstr "Размер атласа"
+msgid "SDF"
+msgstr "ПРсЗ"
+
msgid "Wait Time"
msgstr "Ждать время"
@@ -4033,6 +4057,9 @@ msgstr "Размер точки"
msgid "Distance"
msgstr "Расстояние"
+msgid "MSDF"
+msgstr "МПРсЗ"
+
msgid "Item"
msgstr "Элемент"
@@ -4219,18 +4246,33 @@ msgstr "Глубина (мс)"
msgid "Level dB"
msgstr "Уровень дБ"
+msgid "Pan"
+msgstr "Персональная сеть"
+
msgid "Release (ms)"
msgstr "Релиз (мс)"
+msgid "Tap 1"
+msgstr "Нажмите 1"
+
+msgid "Tap 2"
+msgstr "Нажмите 2"
+
msgid "Feedback"
msgstr "Отзыв"
+msgid "Drive"
+msgstr "Диск"
+
msgid "Resonance"
msgstr "Резонанс"
msgid "Threshold dB"
msgstr "Порог, дБ"
+msgid "Soft Clip dB"
+msgstr "Софт Клиппинг дБ"
+
msgid "Soft Clip Ratio"
msgstr "Коэффициент мягкого скольжения"
diff --git a/editor/translations/properties/tr.po b/editor/translations/properties/tr.po
index 1a47b89f1c..54bb3b605f 100644
--- a/editor/translations/properties/tr.po
+++ b/editor/translations/properties/tr.po
@@ -91,13 +91,14 @@
# Muhammed Said Gülberk <msgulberk@gmail.com>, 2022.
# Yılmaz Durmaz <yilmaz_durmaz@hotmail.com>, 2023.
# Black <ebubekir23atalay@gmail.com>, 2023.
+# Mertcan YILDIRIM <mertcanyildirim463@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-06-23 12:55+0000\n"
-"Last-Translator: Yılmaz Durmaz <yilmaz_durmaz@hotmail.com>\n"
+"PO-Revision-Date: 2023-06-27 20:10+0000\n"
+"Last-Translator: Mertcan YILDIRIM <mertcanyildirim463@gmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot-properties/tr/>\n"
"Language: tr\n"
@@ -224,6 +225,9 @@ msgstr "Varsayılan Veriyolu Düzeni"
msgid "General"
msgstr "Genel"
+msgid "Text to Speech"
+msgstr "Metin Okuma"
+
msgid "2D Panning Strength"
msgstr "2D Kaydırma Keskinliği"
@@ -272,12 +276,18 @@ msgstr "Hata Ayıklama"
msgid "Settings"
msgstr "Ayarlar"
+msgid "Profiler"
+msgstr "Profil Çıkarıcı"
+
msgid "Compression"
msgstr "Sıkıştırma"
msgid "Formats"
msgstr "Biçimler"
+msgid "Zstd"
+msgstr "Zstd"
+
msgid "Long Distance Matching"
msgstr "Uzun Mesafe Eşleşmesi"
@@ -287,6 +297,12 @@ msgstr "Sıkıştırma Seviyesi"
msgid "Window Log Size"
msgstr "Pencere Günlüğü Boyutu"
+msgid "Zlib"
+msgstr "Zlib"
+
+msgid "Gzip"
+msgstr "Gzip"
+
msgid "Crash Handler"
msgstr "Çökme İşleyicisi"
@@ -2192,6 +2208,9 @@ msgstr "Uçak"
msgid "Custom"
msgstr "Özel"
+msgid "Pan"
+msgstr "Kaydır"
+
msgid "Sidechain"
msgstr "Sidechain"
diff --git a/editor/translations/properties/uk.po b/editor/translations/properties/uk.po
index f469cc813f..803c189185 100644
--- a/editor/translations/properties/uk.po
+++ b/editor/translations/properties/uk.po
@@ -28,13 +28,14 @@
# kirill7606 <k7606irill@gmail.com>, 2022.
# Alex <anna.loban@yahoo.com>, 2023.
# Maksym <maksym@mowemax.com>, 2023.
+# Dan <jonweblin2205@protonmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-04-20 03:46+0000\n"
-"Last-Translator: Мирослав <hlopukmyroslav@gmail.com>\n"
+"PO-Revision-Date: 2023-06-30 21:28+0000\n"
+"Last-Translator: Dan <jonweblin2205@protonmail.com>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot-properties/uk/>\n"
"Language: uk\n"
@@ -43,10 +44,10 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.18-dev\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Application"
-msgstr "Програма"
+msgstr "Застосунок"
msgid "Config"
msgstr "Налаштування"
diff --git a/editor/translations/properties/zh_CN.po b/editor/translations/properties/zh_CN.po
index 52c8f35e71..ae50649e1f 100644
--- a/editor/translations/properties/zh_CN.po
+++ b/editor/translations/properties/zh_CN.po
@@ -93,7 +93,7 @@ msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2023-06-13 15:35+0000\n"
+"PO-Revision-Date: 2023-06-27 20:10+0000\n"
"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot-properties/zh_Hans/>\n"
@@ -102,7 +102,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.18-dev\n"
+"X-Generator: Weblate 4.18.1\n"
msgid "Application"
msgstr "应用"
@@ -1730,6 +1730,9 @@ msgstr "自定义模板"
msgid "Release"
msgstr "发布"
+msgid "Export Console Wrapper"
+msgstr "导出控制台封装"
+
msgid "Binary Format"
msgstr "二进制格式"
@@ -2513,6 +2516,9 @@ msgstr "驱动"
msgid "GL Compatibility"
msgstr "GL 兼容性"
+msgid "Nvidia Disable Threaded Optimization"
+msgstr "Nvidia 禁用多线程优化"
+
msgid "Renderer"
msgstr "渲染器"
@@ -2696,6 +2702,9 @@ msgstr "程序集名称"
msgid "Solution Directory"
msgstr "解决方案目录"
+msgid "Assembly Reload Attempts"
+msgstr "尝试重新加载程序集"
+
msgid "Operation"
msgstr "操作"
@@ -9461,6 +9470,9 @@ msgstr "默认边界连接边距"
msgid "Default Link Connection Radius"
msgstr "默认链接连接半径"
+msgid "Default Cell Height"
+msgstr "默认单元格高度"
+
msgid "Avoidance Use Multiple Threads"
msgstr "避障使用多线程"
diff --git a/editor/translations/properties/zh_TW.po b/editor/translations/properties/zh_TW.po
index dd5efab466..043679253e 100644
--- a/editor/translations/properties/zh_TW.po
+++ b/editor/translations/properties/zh_TW.po
@@ -18,7 +18,7 @@
# leela <53352@protonmail.com>, 2019.
# Kenneth Lo <closer.tw@gmail.com>, 2019.
# SIYU FU <1002492607@qq.com>, 2019.
-# 鄭惟中 <biglionlion06@gmail.com>, 2020.
+# 鄭惟中 <biglionlion06@gmail.com>, 2020, 2023.
# Alexander Wang <zxcvb22217@gmail.com>, 2020.
# binotaliu <binota@protonmail.ch>, 2020.
# Allen H. <w84miracle@gmail.com>, 2020.
@@ -44,8 +44,8 @@ msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-03-31 00:59+0000\n"
-"Last-Translator: leo <leowong1220@gmail.com>\n"
+"PO-Revision-Date: 2023-07-01 13:08+0000\n"
+"Last-Translator: 鄭惟中 <biglionlion06@gmail.com>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot-properties/zh_Hant/>\n"
"Language: zh_TW\n"
@@ -53,7 +53,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.17-dev\n"
+"X-Generator: Weblate 5.0-dev\n"
msgid "Application"
msgstr "應用"
@@ -220,6 +220,9 @@ msgstr "使用累積輸入"
msgid "Input Devices"
msgstr "輸入裝置"
+msgid "Compatibility"
+msgstr "相容"
+
msgid "Device"
msgstr "裝置"
@@ -347,7 +350,7 @@ msgid "Region"
msgstr "區域"
msgid "Offset"
-msgstr "偏移"
+msgstr "偏移量"
msgid "Cell Size"
msgstr "單元格大小"
@@ -979,6 +982,9 @@ msgstr "洋蔥層先前顏色"
msgid "Onion Layers Future Color"
msgstr "洋蔥層未來顏色"
+msgid "Shader Editor"
+msgstr "著色器編輯器"
+
msgid "Visual Editors"
msgstr "視覺化編輯器"
@@ -1241,10 +1247,10 @@ msgid "Slices"
msgstr "切片"
msgid "Horizontal"
-msgstr "水平"
+msgstr "水平方向"
msgid "Vertical"
-msgstr "垂直"
+msgstr "垂直方向"
msgid "Layout"
msgstr "配置;畫面佈局"
@@ -1472,7 +1478,7 @@ msgid "Texture"
msgstr "紋理貼圖"
msgid "Separation"
-msgstr "間距"
+msgstr "分隔方向"
msgid "Speed"
msgstr "速度"
@@ -1558,6 +1564,9 @@ msgstr "iOS"
msgid "Hide Home Indicator"
msgstr "隱藏 Home 橫條"
+msgid "XR"
+msgstr "XR"
+
msgid "Boot Splash"
msgstr "啟動畫面"
@@ -2191,6 +2200,9 @@ msgstr "發射"
msgid "Time"
msgstr "時間"
+msgid "One Shot"
+msgstr "一次性"
+
msgid "Randomness"
msgstr "隨機性"
@@ -2209,6 +2221,9 @@ msgstr "色相變化"
msgid "Variation Curve"
msgstr "變化曲線"
+msgid "Fill"
+msgstr "填滿"
+
msgid "End Cap Mode"
msgstr "尾端模式"
@@ -2413,12 +2428,21 @@ msgstr "樹根節點"
msgid "Button Group"
msgstr "按鍵分組"
+msgid "Indentation"
+msgstr "縮 排"
+
+msgid "Font Sizes"
+msgstr "字體大小s"
+
msgid "Pivot Offset"
msgstr "樞紐偏移量"
msgid "Localization"
msgstr "在地化"
+msgid "Focus"
+msgstr "焦點"
+
msgid "Next"
msgstr "下一頁"
@@ -2488,6 +2512,9 @@ msgstr "填充角度"
msgid "Hide Root"
msgstr "隱藏根節點"
+msgid "Expand"
+msgstr "展開"
+
msgid "Z Index"
msgstr "Z 索引"
@@ -2521,6 +2548,12 @@ msgstr "最小尺寸"
msgid "Max Size"
msgstr "最大大小"
+msgid "2D Physics"
+msgstr "2D物理"
+
+msgid "3D Physics"
+msgstr "3D物理"
+
msgid "Format"
msgstr "格式"
@@ -2602,12 +2635,24 @@ msgstr "節點"
msgid "Source"
msgstr "來源"
+msgid "Tonemap"
+msgstr "色調圖"
+
msgid "Fade In"
msgstr "淡入"
msgid "Fade Out"
msgstr "淡出"
+msgid "SSAO"
+msgstr "SSAO(螢幕空間環境光遮蔽)"
+
+msgid "SSIL"
+msgstr "SSIL(螢幕空間間接照明)"
+
+msgid "Glow"
+msgstr "發光"
+
msgid "Mix"
msgstr "混合 (Mix)"
@@ -2683,6 +2728,9 @@ msgstr "光澤大小"
msgid "Horizon Color"
msgstr "地平線顏色"
+msgid "Ground Color"
+msgstr "地面顏色"
+
msgid "Blend"
msgstr "混合 (Blend)"
@@ -2716,6 +2764,9 @@ msgstr "函式"
msgid "Plane"
msgstr "平面"
+msgid "Custom"
+msgstr "自訂"
+
msgid "Random Pitch"
msgstr "隨機音高"
@@ -2791,15 +2842,24 @@ msgstr "VRAM壓縮"
msgid "Force PNG"
msgstr "強制 PNG"
+msgid "Shadow Atlas"
+msgstr "陰影合集"
+
msgid "Reflections"
msgstr "反射"
msgid "Texture Array Reflections"
msgstr "紋理貼圖陣列反射"
+msgid "GI"
+msgstr "GI"
+
msgid "Overrides"
msgstr "複寫"
+msgid "OpenGL"
+msgstr "OpenGL(開放圖形庫)"
+
msgid "Shaders"
msgstr "著色器"
diff --git a/editor/window_wrapper.cpp b/editor/window_wrapper.cpp
index 3a8dbf017f..91d5aa8860 100644
--- a/editor/window_wrapper.cpp
+++ b/editor/window_wrapper.cpp
@@ -313,7 +313,7 @@ void WindowWrapper::set_margins_enabled(bool p_enabled) {
}
WindowWrapper::WindowWrapper() {
- if (SceneTree::get_singleton()->get_root()->is_embedding_subwindows() || !EDITOR_GET("interface/multi_window/enable")) {
+ if (SceneTree::get_singleton()->get_root()->is_embedding_subwindows() || EDITOR_GET("interface/editor/single_window_mode") || !EDITOR_GET("interface/multi_window/enable")) {
return;
}
diff --git a/main/main.cpp b/main/main.cpp
index f6c4df583b..7e2741648d 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -474,6 +474,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print("Standalone tools:\n");
OS::get_singleton()->print(" -s, --script <script> Run a script.\n");
+ OS::get_singleton()->print(" --main-loop <main_loop_name> Run a MainLoop specified by its global class name.\n");
OS::get_singleton()->print(" --check-only Only parse for errors and quit (use with --script).\n");
#ifdef TOOLS_ENABLED
OS::get_singleton()->print(" --export-release <preset> <path> Export the project in release mode using the given preset and output path. The preset name should match one defined in export_presets.cfg.\n");
@@ -1956,6 +1957,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->_verbose_stdout = GLOBAL_GET("debug/settings/stdout/verbose_stdout");
}
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
+ OS::get_singleton()->set_environment("MVK_CONFIG_LOG_LEVEL", OS::get_singleton()->_verbose_stdout ? "3" : "1"); // 1 = Errors only, 3 = Info
+#endif
+
if (frame_delay == 0) {
frame_delay = GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/frame_delay_msec", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), 0);
}
@@ -2598,6 +2603,7 @@ bool Main::start() {
String positional_arg;
String game_path;
String script;
+ String main_loop_type;
bool check_only = false;
#ifdef TOOLS_ENABLED
@@ -2661,6 +2667,8 @@ bool Main::start() {
bool parsed_pair = true;
if (args[i] == "-s" || args[i] == "--script") {
script = args[i + 1];
+ } else if (args[i] == "--main-loop") {
+ main_loop_type = args[i + 1];
#ifdef TOOLS_ENABLED
} else if (args[i] == "--doctool") {
doc_tool_path = args[i + 1];
@@ -2702,6 +2710,9 @@ bool Main::start() {
}
uint64_t minimum_time_msec = GLOBAL_DEF(PropertyInfo(Variant::INT, "application/boot_splash/minimum_display_time", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:ms"), 0);
+ if (Engine::get_singleton()->is_editor_hint()) {
+ minimum_time_msec = 0;
+ }
#ifdef TOOLS_ENABLED
#ifdef MODULE_GDSCRIPT_ENABLED
@@ -2880,7 +2891,9 @@ bool Main::start() {
if (editor) {
main_loop = memnew(SceneTree);
}
- String main_loop_type = GLOBAL_GET("application/run/main_loop_type");
+ if (main_loop_type.is_empty()) {
+ main_loop_type = GLOBAL_GET("application/run/main_loop_type");
+ }
if (!script.is_empty()) {
Ref<Script> script_res = ResourceLoader::load(script);
@@ -2907,7 +2920,7 @@ bool Main::start() {
ERR_FAIL_V_MSG(false, vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script));
}
- script_loop->set_initialize_script(script_res);
+ script_loop->set_script(script_res);
main_loop = script_loop;
} else {
return false;
@@ -2930,7 +2943,7 @@ bool Main::start() {
OS::get_singleton()->alert("Error: Invalid MainLoop script base type: " + script_base);
ERR_FAIL_V_MSG(false, vformat("The global class %s does not inherit from SceneTree or MainLoop.", main_loop_type));
}
- script_loop->set_initialize_script(script_res);
+ script_loop->set_script(script_res);
main_loop = script_loop;
}
}
@@ -2955,6 +2968,8 @@ bool Main::start() {
}
}
+ OS::get_singleton()->set_main_loop(main_loop);
+
SceneTree *sml = Object::cast_to<SceneTree>(main_loop);
if (sml) {
#ifdef DEBUG_ENABLED
@@ -3274,8 +3289,6 @@ bool Main::start() {
DisplayServer::get_singleton()->set_icon(icon);
}
- OS::get_singleton()->set_main_loop(main_loop);
-
if (movie_writer) {
movie_writer->begin(DisplayServer::get_singleton()->window_get_size(), fixed_fps, Engine::get_singleton()->get_write_movie_path());
}
diff --git a/misc/dist/macos_tools.app/Contents/Info.plist b/misc/dist/macos_tools.app/Contents/Info.plist
index bff5743e15..6151593f72 100644
--- a/misc/dist/macos_tools.app/Contents/Info.plist
+++ b/misc/dist/macos_tools.app/Contents/Info.plist
@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>4.1</string>
+ <string>4.2</string>
<key>CFBundleSignature</key>
<string>godot</string>
<key>CFBundleVersion</key>
- <string>4.1</string>
+ <string>4.2</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required to capture audio.</string>
<key>NSCameraUsageDescription</key>
diff --git a/misc/dist/windows/godot.iss b/misc/dist/windows/godot.iss
index 819327000c..ba8be69a92 100644
--- a/misc/dist/windows/godot.iss
+++ b/misc/dist/windows/godot.iss
@@ -1,5 +1,5 @@
#define MyAppName "Godot Engine"
-#define MyAppVersion "4.1"
+#define MyAppVersion "4.2"
#define MyAppPublisher "Godot Engine contributors"
#define MyAppURL "https://godotengine.org/"
#define MyAppExeName "godot.exe"
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index c241f1cabd..4c217dac28 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -953,12 +953,12 @@ void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) {
return;
}
if (mesh.is_valid()) {
- mesh->disconnect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed));
+ mesh->disconnect_changed(callable_mp(this, &CSGMesh3D::_mesh_changed));
}
mesh = p_mesh;
if (mesh.is_valid()) {
- mesh->connect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed));
+ mesh->connect_changed(callable_mp(this, &CSGMesh3D::_mesh_changed));
}
_mesh_changed();
diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml
index 3d756a3822..f56cb355ca 100644
--- a/modules/csg/doc_classes/CSGBox3D.xml
+++ b/modules/csg/doc_classes/CSGBox3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGBox3D" inherits="CSGPrimitive3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSGBox3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Box shape.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGCombiner3D.xml b/modules/csg/doc_classes/CSGCombiner3D.xml
index bf50d6151b..d785b2f818 100644
--- a/modules/csg/doc_classes/CSGCombiner3D.xml
+++ b/modules/csg/doc_classes/CSGCombiner3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGCombiner3D" inherits="CSGShape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSGCombiner3D" inherits="CSGShape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG node that allows you to combine other CSG modifiers.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGCylinder3D.xml b/modules/csg/doc_classes/CSGCylinder3D.xml
index 489371bb0e..f722b569e7 100644
--- a/modules/csg/doc_classes/CSGCylinder3D.xml
+++ b/modules/csg/doc_classes/CSGCylinder3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGCylinder3D" inherits="CSGPrimitive3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSGCylinder3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Cylinder shape.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml
index 9d409e442d..9a0f121e19 100644
--- a/modules/csg/doc_classes/CSGMesh3D.xml
+++ b/modules/csg/doc_classes/CSGMesh3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGMesh3D" inherits="CSGPrimitive3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSGMesh3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Mesh shape that uses a mesh resource.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml
index b7cc7c29d0..338adc9b52 100644
--- a/modules/csg/doc_classes/CSGPolygon3D.xml
+++ b/modules/csg/doc_classes/CSGPolygon3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGPolygon3D" inherits="CSGPrimitive3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSGPolygon3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Extrudes a 2D polygon shape to create a 3D mesh.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGPrimitive3D.xml b/modules/csg/doc_classes/CSGPrimitive3D.xml
index 1686175d1d..6afbf4a3d7 100644
--- a/modules/csg/doc_classes/CSGPrimitive3D.xml
+++ b/modules/csg/doc_classes/CSGPrimitive3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGPrimitive3D" inherits="CSGShape3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSGPrimitive3D" inherits="CSGShape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Base class for CSG primitives.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index cae30ed446..0414aa362d 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGShape3D" inherits="GeometryInstance3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSGShape3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
The CSG base class.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGSphere3D.xml b/modules/csg/doc_classes/CSGSphere3D.xml
index bdcee99647..a11979444e 100644
--- a/modules/csg/doc_classes/CSGSphere3D.xml
+++ b/modules/csg/doc_classes/CSGSphere3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGSphere3D" inherits="CSGPrimitive3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSGSphere3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Sphere shape.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGTorus3D.xml b/modules/csg/doc_classes/CSGTorus3D.xml
index 856c2d8731..9bef522bb6 100644
--- a/modules/csg/doc_classes/CSGTorus3D.xml
+++ b/modules/csg/doc_classes/CSGTorus3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGTorus3D" inherits="CSGPrimitive3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSGTorus3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Torus shape.
</brief_description>
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index e6523e3d09..8a3a36e84b 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -31,6 +31,7 @@
#include "texture_loader_dds.h"
#include "core/io/file_access.h"
+#include "scene/resources/image_texture.h"
#define PF_FOURCC(s) ((uint32_t)(((s)[3] << 24U) | ((s)[2] << 16U) | ((s)[1] << 8U) | ((s)[0])))
diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h
index dc3df1fcee..3763700ff1 100644
--- a/modules/dds/texture_loader_dds.h
+++ b/modules/dds/texture_loader_dds.h
@@ -32,7 +32,6 @@
#define TEXTURE_LOADER_DDS_H
#include "core/io/resource_loader.h"
-#include "scene/resources/texture.h"
class ResourceFormatDDS : public ResourceFormatLoader {
public:
diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml
index b46a3273c8..1f2964522b 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ENetConnection" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="ENetConnection" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A wrapper class for an [url=http://enet.bespin.org/group__host.html]ENetHost[/url].
</brief_description>
diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml
index 646cf37b55..c49d16eb13 100644
--- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml
+++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ENetMultiplayerPeer" inherits="MultiplayerPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="ENetMultiplayerPeer" inherits="MultiplayerPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A MultiplayerPeer implementation using the [url=http://enet.bespin.org/index.html]ENet[/url] library.
</brief_description>
diff --git a/modules/enet/doc_classes/ENetPacketPeer.xml b/modules/enet/doc_classes/ENetPacketPeer.xml
index 0e531b0e89..3171da1f6d 100644
--- a/modules/enet/doc_classes/ENetPacketPeer.xml
+++ b/modules/enet/doc_classes/ENetPacketPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ENetPacketPeer" inherits="PacketPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="ENetPacketPeer" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A wrapper class for an [url=http://enet.bespin.org/group__peer.html]ENetPeer[/url].
</brief_description>
diff --git a/modules/enet/enet_packet_peer.cpp b/modules/enet/enet_packet_peer.cpp
index f64704c67d..a131841a07 100644
--- a/modules/enet/enet_packet_peer.cpp
+++ b/modules/enet/enet_packet_peer.cpp
@@ -76,7 +76,7 @@ void ENetPacketPeer::throttle_configure(int p_interval, int p_acceleration, int
void ENetPacketPeer::set_timeout(int p_timeout, int p_timeout_min, int p_timeout_max) {
ERR_FAIL_COND_MSG(peer == nullptr, "Peer not connected");
- ERR_FAIL_COND_MSG(p_timeout > p_timeout_min || p_timeout_min > p_timeout_max, "Timeout limit must be less than minimum timeout, which itself must be less then maximum timeout");
+ ERR_FAIL_COND_MSG(p_timeout > p_timeout_min || p_timeout_min > p_timeout_max, "Timeout limit must be less than minimum timeout, which itself must be less than maximum timeout");
enet_peer_timeout(peer, p_timeout, p_timeout_min, p_timeout_max);
}
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 42b7fa3199..0c300eade4 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="@GDScript" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="@GDScript" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Built-in GDScript constants, functions, and annotations.
</brief_description>
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index b9fcce4883..5f7a7e2915 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDScript" inherits="Script" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GDScript" inherits="Script" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A script implemented in the GDScript programming language.
</brief_description>
diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp
index df17581ad1..0d8453738d 100644
--- a/modules/gdscript/editor/gdscript_docgen.cpp
+++ b/modules/gdscript/editor/gdscript_docgen.cpp
@@ -236,6 +236,8 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
p_script->member_lines[name] = m_enum->start_line;
+ doc.enums[name] = m_enum->doc_description;
+
for (const GDP::EnumNode::Value &val : m_enum->values) {
DocData::ConstantDoc const_doc;
const_doc.name = val.identifier->name;
@@ -244,7 +246,6 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
const_doc.description = val.doc_description;
const_doc.enumeration = name;
- doc.enums[const_doc.name] = const_doc.description;
doc.constants.push_back(const_doc);
}
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 3d6d133579..0bf9f72a2c 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -787,11 +787,11 @@ Error GDScript::reload(bool p_keep_state) {
err = compiler.compile(&parser, this, p_keep_state);
if (err) {
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
if (can_run) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
}
- _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
reloading = false;
return ERR_COMPILATION_FAILED;
} else {
@@ -2094,10 +2094,7 @@ String GDScriptLanguage::get_extension() const {
}
void GDScriptLanguage::finish() {
- if (_call_stack) {
- memdelete_arr(_call_stack);
- _call_stack = nullptr;
- }
+ _call_stack.free();
// Clear the cache before parsing the script_list
GDScriptCache::clear();
@@ -2140,12 +2137,12 @@ void GDScriptLanguage::profiling_start() {
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
- elem->self()->profile.call_count = 0;
- elem->self()->profile.self_time = 0;
- elem->self()->profile.total_time = 0;
- elem->self()->profile.frame_call_count = 0;
- elem->self()->profile.frame_self_time = 0;
- elem->self()->profile.frame_total_time = 0;
+ elem->self()->profile.call_count.set(0);
+ elem->self()->profile.self_time.set(0);
+ elem->self()->profile.total_time.set(0);
+ elem->self()->profile.frame_call_count.set(0);
+ elem->self()->profile.frame_self_time.set(0);
+ elem->self()->profile.frame_total_time.set(0);
elem->self()->profile.last_frame_call_count = 0;
elem->self()->profile.last_frame_self_time = 0;
elem->self()->profile.last_frame_total_time = 0;
@@ -2175,9 +2172,9 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,
if (current >= p_info_max) {
break;
}
- p_info_arr[current].call_count = elem->self()->profile.call_count;
- p_info_arr[current].self_time = elem->self()->profile.self_time;
- p_info_arr[current].total_time = elem->self()->profile.total_time;
+ p_info_arr[current].call_count = elem->self()->profile.call_count.get();
+ p_info_arr[current].self_time = elem->self()->profile.self_time.get();
+ p_info_arr[current].total_time = elem->self()->profile.total_time.get();
p_info_arr[current].signature = elem->self()->profile.signature;
elem = elem->next();
current++;
@@ -2395,12 +2392,12 @@ void GDScriptLanguage::frame() {
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
- elem->self()->profile.last_frame_call_count = elem->self()->profile.frame_call_count;
- elem->self()->profile.last_frame_self_time = elem->self()->profile.frame_self_time;
- elem->self()->profile.last_frame_total_time = elem->self()->profile.frame_total_time;
- elem->self()->profile.frame_call_count = 0;
- elem->self()->profile.frame_self_time = 0;
- elem->self()->profile.frame_total_time = 0;
+ elem->self()->profile.last_frame_call_count = elem->self()->profile.frame_call_count.get();
+ elem->self()->profile.last_frame_self_time = elem->self()->profile.frame_self_time.get();
+ elem->self()->profile.last_frame_total_time = elem->self()->profile.frame_total_time.get();
+ elem->self()->profile.frame_call_count.set(0);
+ elem->self()->profile.frame_self_time.set(0);
+ elem->self()->profile.frame_total_time.set(0);
elem = elem->next();
}
}
@@ -2607,6 +2604,8 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
return c->identifier != nullptr ? String(c->identifier->name) : String();
}
+thread_local GDScriptLanguage::CallStack GDScriptLanguage::_call_stack;
+
GDScriptLanguage::GDScriptLanguage() {
calls = 0;
ERR_FAIL_COND(singleton);
@@ -2626,18 +2625,14 @@ GDScriptLanguage::GDScriptLanguage() {
profiling = false;
script_frame_time = 0;
- _debug_call_stack_pos = 0;
int dmcs = GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "512," + itos(GDScriptFunction::MAX_CALL_DEPTH - 1) + ",1"), 1024);
if (EngineDebugger::is_active()) {
//debugging enabled!
_debug_max_call_stack = dmcs;
- _call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1);
-
} else {
_debug_max_call_stack = 0;
- _call_stack = nullptr;
}
#ifdef DEBUG_ENABLED
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index d131ec6ab1..c41b1a0def 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -364,12 +364,26 @@ class GDScriptLanguage : public ScriptLanguage {
int *line = nullptr;
};
- int _debug_parse_err_line;
- String _debug_parse_err_file;
- String _debug_error;
- int _debug_call_stack_pos;
- int _debug_max_call_stack;
- CallLevel *_call_stack = nullptr;
+ static thread_local int _debug_parse_err_line;
+ static thread_local String _debug_parse_err_file;
+ static thread_local String _debug_error;
+ struct CallStack {
+ CallLevel *levels = nullptr;
+ int stack_pos = 0;
+
+ void free() {
+ if (levels) {
+ memdelete(levels);
+ levels = nullptr;
+ }
+ }
+ ~CallStack() {
+ free();
+ }
+ };
+
+ static thread_local CallStack _call_stack;
+ int _debug_max_call_stack = 0;
void _add_global(const StringName &p_name, const Variant &p_value);
@@ -395,59 +409,51 @@ public:
bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
_FORCE_INLINE_ void enter_function(GDScriptInstance *p_instance, GDScriptFunction *p_function, Variant *p_stack, int *p_ip, int *p_line) {
- if (Thread::get_main_id() != Thread::get_caller_id()) {
- return; //no support for other threads than main for now
+ if (unlikely(_call_stack.levels == nullptr)) {
+ _call_stack.levels = memnew_arr(CallLevel, _debug_max_call_stack + 1);
}
if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) {
EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() + 1);
}
- if (_debug_call_stack_pos >= _debug_max_call_stack) {
+ if (_call_stack.stack_pos >= _debug_max_call_stack) {
//stack overflow
_debug_error = vformat("Stack overflow (stack size: %s). Check for infinite recursion in your script.", _debug_max_call_stack);
EngineDebugger::get_script_debugger()->debug(this);
return;
}
- _call_stack[_debug_call_stack_pos].stack = p_stack;
- _call_stack[_debug_call_stack_pos].instance = p_instance;
- _call_stack[_debug_call_stack_pos].function = p_function;
- _call_stack[_debug_call_stack_pos].ip = p_ip;
- _call_stack[_debug_call_stack_pos].line = p_line;
- _debug_call_stack_pos++;
+ _call_stack.levels[_call_stack.stack_pos].stack = p_stack;
+ _call_stack.levels[_call_stack.stack_pos].instance = p_instance;
+ _call_stack.levels[_call_stack.stack_pos].function = p_function;
+ _call_stack.levels[_call_stack.stack_pos].ip = p_ip;
+ _call_stack.levels[_call_stack.stack_pos].line = p_line;
+ _call_stack.stack_pos++;
}
_FORCE_INLINE_ void exit_function() {
- if (Thread::get_main_id() != Thread::get_caller_id()) {
- return; //no support for other threads than main for now
- }
-
if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) {
EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() - 1);
}
- if (_debug_call_stack_pos == 0) {
+ if (_call_stack.stack_pos == 0) {
_debug_error = "Stack Underflow (Engine Bug)";
EngineDebugger::get_script_debugger()->debug(this);
return;
}
- _debug_call_stack_pos--;
+ _call_stack.stack_pos--;
}
virtual Vector<StackInfo> debug_get_current_stack_info() override {
- if (Thread::get_main_id() != Thread::get_caller_id()) {
- return Vector<StackInfo>();
- }
-
Vector<StackInfo> csi;
- csi.resize(_debug_call_stack_pos);
- for (int i = 0; i < _debug_call_stack_pos; i++) {
- csi.write[_debug_call_stack_pos - i - 1].line = _call_stack[i].line ? *_call_stack[i].line : 0;
- if (_call_stack[i].function) {
- csi.write[_debug_call_stack_pos - i - 1].func = _call_stack[i].function->get_name();
- csi.write[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_script_path();
+ csi.resize(_call_stack.stack_pos);
+ for (int i = 0; i < _call_stack.stack_pos; i++) {
+ csi.write[_call_stack.stack_pos - i - 1].line = _call_stack.levels[i].line ? *_call_stack.levels[i].line : 0;
+ if (_call_stack.levels[i].function) {
+ csi.write[_call_stack.stack_pos - i - 1].func = _call_stack.levels[i].function->get_name();
+ csi.write[_call_stack.stack_pos - i - 1].file = _call_stack.levels[i].function->get_script()->get_script_path();
}
}
return csi;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index d3445b8cc0..01e94ebb22 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -1553,7 +1553,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
}
parser->push_warning(p_function->parameters[i]->identifier, GDScriptWarning::UNUSED_PARAMETER, visible_name, p_function->parameters[i]->identifier->name);
}
- is_shadowing(p_function->parameters[i]->identifier, "function parameter");
+ is_shadowing(p_function->parameters[i]->identifier, "function parameter", true);
#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED
if (p_function->parameters[i]->initializer) {
@@ -1874,9 +1874,8 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
} else if (p_variable->assignments == 0) {
parser->push_warning(p_variable, GDScriptWarning::UNASSIGNED_VARIABLE, p_variable->identifier->name);
}
-
- is_shadowing(p_variable->identifier, kind);
}
+ is_shadowing(p_variable->identifier, kind, p_is_local);
#endif
}
@@ -1889,9 +1888,8 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
if (p_constant->usages == 0) {
parser->push_warning(p_constant, GDScriptWarning::UNUSED_LOCAL_CONSTANT, p_constant->identifier->name);
}
-
- is_shadowing(p_constant->identifier, kind);
}
+ is_shadowing(p_constant->identifier, kind, p_is_local);
#endif
}
@@ -2052,7 +2050,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
p_for->set_datatype(p_for->loop->get_datatype());
#ifdef DEBUG_ENABLED
if (p_for->variable) {
- is_shadowing(p_for->variable, R"("for" iterator variable)");
+ is_shadowing(p_for->variable, R"("for" iterator variable)", true);
}
#endif
}
@@ -2148,7 +2146,7 @@ void GDScriptAnalyzer::resolve_match_pattern(GDScriptParser::PatternNode *p_matc
}
p_match_pattern->bind->set_datatype(result);
#ifdef DEBUG_ENABLED
- is_shadowing(p_match_pattern->bind, "pattern bind");
+ is_shadowing(p_match_pattern->bind, "pattern bind", true);
if (p_match_pattern->bind->usages == 0 && !String(p_match_pattern->bind->name).begins_with("_")) {
parser->push_warning(p_match_pattern->bind, GDScriptWarning::UNUSED_VARIABLE, p_match_pattern->bind->name);
}
@@ -4517,6 +4515,10 @@ Variant GDScriptAnalyzer::make_variable_default_value(GDScriptParser::VariableNo
return result;
}
+const HashMap<String, Ref<GDScriptParserRef>> &GDScriptAnalyzer::get_depended_parsers() {
+ return depended_parsers;
+}
+
GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType result;
result.is_constant = true;
@@ -4890,8 +4892,8 @@ void GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p
}
#ifdef DEBUG_ENABLED
-void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context) {
- const StringName &name = p_local->name;
+void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier, const String &p_context, const bool p_in_local_scope) {
+ const StringName &name = p_identifier->name;
GDScriptParser::DataType base = parser->current_class->get_datatype();
GDScriptParser::ClassNode *base_class = base.class_type;
@@ -4901,29 +4903,30 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
for (MethodInfo &info : gdscript_funcs) {
if (info.name == name) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
return;
}
}
-
if (Variant::has_utility_function(name)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
return;
} else if (ClassDB::class_exists(name)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "global class");
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "global class");
return;
} else if (GDScriptParser::get_builtin_type(name) != Variant::VARIANT_MAX) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in type");
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in type");
return;
}
}
- while (base_class != nullptr) {
- if (base_class->has_member(name)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_local->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()));
- return;
+ if (p_in_local_scope) {
+ while (base_class != nullptr) {
+ if (base_class->has_member(name)) {
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_identifier->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()));
+ return;
+ }
+ base_class = base_class->base_type.class_type;
}
- base_class = base_class->base_type.class_type;
}
StringName parent = base.native_type;
@@ -4931,19 +4934,19 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
ERR_FAIL_COND_MSG(!class_exists(parent), "Non-existent native base class.");
if (ClassDB::has_method(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "method", parent);
return;
} else if (ClassDB::has_signal(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "signal", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "signal", parent);
return;
} else if (ClassDB::has_property(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "property", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "property", parent);
return;
} else if (ClassDB::has_integer_constant(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "constant", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "constant", parent);
return;
} else if (ClassDB::has_enum(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "enum", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "enum", parent);
return;
}
parent = ClassDB::get_parent_class(parent);
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 195e23b503..5bc2c89a87 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -133,7 +133,7 @@ class GDScriptAnalyzer {
Ref<GDScriptParserRef> get_parser_for(const String &p_path);
void reduce_identifier_from_base_set_class(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType p_identifier_datatype);
#ifdef DEBUG_ENABLED
- void is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context);
+ void is_shadowing(GDScriptParser::IdentifierNode *p_identifier, const String &p_context, const bool p_in_local_scope);
#endif
public:
@@ -144,6 +144,7 @@ public:
Error analyze();
Variant make_variable_default_value(GDScriptParser::VariableNode *p_variable);
+ const HashMap<String, Ref<GDScriptParserRef>> &get_depended_parsers();
GDScriptAnalyzer(GDScriptParser *p_parser);
};
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index e5bb93e3c8..d191bd0224 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -294,8 +294,12 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
if (p_update_from_disk) {
r_error = script->load_source_code(p_path);
+ if (r_error) {
+ return script;
+ }
}
+ r_error = script->reload(true);
if (r_error) {
return script;
}
@@ -303,7 +307,6 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
singleton->full_gdscript_cache[p_path] = script;
singleton->shallow_gdscript_cache.erase(p_path);
- script->reload(true);
return script;
}
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 004af80a91..3f571602e8 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -2579,9 +2579,9 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
}
} else if (!base->is_valid()) {
Error err = OK;
- Ref<GDScript> base_root = GDScriptCache::get_full_script(base->path, err, p_script->path);
+ Ref<GDScript> base_root = GDScriptCache::get_shallow_script(base->path, err, p_script->path);
if (err) {
- _set_error(vformat(R"(Could not compile base class "%s" from "%s": %s)", base->fully_qualified_name, base->path, error_names[err]), nullptr);
+ _set_error(vformat(R"(Could not parse base class "%s" from "%s": %s)", base->fully_qualified_name, base->path, error_names[err]), nullptr);
return err;
}
if (base_root.is_valid()) {
@@ -2591,7 +2591,12 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
_set_error(vformat(R"(Could not find class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr);
return ERR_COMPILATION_FAILED;
}
- ERR_FAIL_COND_V(!base->is_valid() && !base->reloading, ERR_BUG);
+
+ err = _populate_class_members(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;
+ }
}
p_script->base = base;
@@ -2968,7 +2973,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
GDScriptCache::add_static_script(p_script);
}
- return GDScriptCache::finish_compiling(main_script->get_path());
+ return GDScriptCache::finish_compiling(main_script->path);
}
String GDScriptCompiler::get_error() const {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index cd34feb8b3..47ceee3943 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -143,14 +143,26 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li
#endif
if (err) {
if (r_errors) {
- for (const GDScriptParser::ParserError &E : parser.get_errors()) {
- const GDScriptParser::ParserError &pe = E;
+ for (const GDScriptParser::ParserError &pe : parser.get_errors()) {
ScriptLanguage::ScriptError e;
+ e.path = p_path;
e.line = pe.line;
e.column = pe.column;
e.message = pe.message;
r_errors->push_back(e);
}
+
+ for (KeyValue<String, Ref<GDScriptParserRef>> E : analyzer.get_depended_parsers()) {
+ GDScriptParser *depended_parser = E.value->get_parser();
+ for (const GDScriptParser::ParserError &pe : depended_parser->get_errors()) {
+ ScriptLanguage::ScriptError e;
+ e.path = E.key;
+ e.line = pe.line;
+ e.column = pe.column;
+ e.message = pe.message;
+ r_errors->push_back(e);
+ }
+ }
}
return false;
} else {
@@ -221,6 +233,10 @@ Script *GDScriptLanguage::create_script() const {
/* DEBUGGER FUNCTIONS */
+thread_local int GDScriptLanguage::_debug_parse_err_line = -1;
+thread_local String GDScriptLanguage::_debug_parse_err_file;
+thread_local String GDScriptLanguage::_debug_error;
+
bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) {
// break because of parse error
@@ -229,6 +245,9 @@ bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const
_debug_parse_err_file = p_file;
_debug_error = p_error;
EngineDebugger::get_script_debugger()->debug(this, false, true);
+ // Because this is thread local, clear the memory afterwards.
+ _debug_parse_err_file = String();
+ _debug_error = String();
return true;
} else {
return false;
@@ -236,12 +255,15 @@ bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const
}
bool GDScriptLanguage::debug_break(const String &p_error, bool p_allow_continue) {
- if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) {
+ if (EngineDebugger::is_active()) {
_debug_parse_err_line = -1;
_debug_parse_err_file = "";
_debug_error = p_error;
bool is_error_breakpoint = p_error != "Breakpoint";
EngineDebugger::get_script_debugger()->debug(this, p_allow_continue, is_error_breakpoint);
+ // Because this is thread local, clear the memory afterwards.
+ _debug_parse_err_file = String();
+ _debug_error = String();
return true;
} else {
return false;
@@ -257,7 +279,7 @@ int GDScriptLanguage::debug_get_stack_level_count() const {
return 1;
}
- return _debug_call_stack_pos;
+ return _call_stack.stack_pos;
}
int GDScriptLanguage::debug_get_stack_level_line(int p_level) const {
@@ -265,11 +287,11 @@ int GDScriptLanguage::debug_get_stack_level_line(int p_level) const {
return _debug_parse_err_line;
}
- ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, -1);
+ ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, -1);
- int l = _debug_call_stack_pos - p_level - 1;
+ int l = _call_stack.stack_pos - p_level - 1;
- return *(_call_stack[l].line);
+ return *(_call_stack.levels[l].line);
}
String GDScriptLanguage::debug_get_stack_level_function(int p_level) const {
@@ -277,9 +299,9 @@ String GDScriptLanguage::debug_get_stack_level_function(int p_level) const {
return "";
}
- ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, "");
- int l = _debug_call_stack_pos - p_level - 1;
- return _call_stack[l].function->get_name();
+ ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, "");
+ int l = _call_stack.stack_pos - p_level - 1;
+ return _call_stack.levels[l].function->get_name();
}
String GDScriptLanguage::debug_get_stack_level_source(int p_level) const {
@@ -287,9 +309,9 @@ String GDScriptLanguage::debug_get_stack_level_source(int p_level) const {
return _debug_parse_err_file;
}
- ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, "");
- int l = _debug_call_stack_pos - p_level - 1;
- return _call_stack[l].function->get_source();
+ ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, "");
+ int l = _call_stack.stack_pos - p_level - 1;
+ return _call_stack.levels[l].function->get_source();
}
void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
@@ -297,17 +319,17 @@ void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p
return;
}
- ERR_FAIL_INDEX(p_level, _debug_call_stack_pos);
- int l = _debug_call_stack_pos - p_level - 1;
+ ERR_FAIL_INDEX(p_level, _call_stack.stack_pos);
+ int l = _call_stack.stack_pos - p_level - 1;
- GDScriptFunction *f = _call_stack[l].function;
+ GDScriptFunction *f = _call_stack.levels[l].function;
List<Pair<StringName, int>> locals;
- f->debug_get_stack_member_state(*_call_stack[l].line, &locals);
+ f->debug_get_stack_member_state(*_call_stack.levels[l].line, &locals);
for (const Pair<StringName, int> &E : locals) {
p_locals->push_back(E.first);
- p_values->push_back(_call_stack[l].stack[E.second]);
+ p_values->push_back(_call_stack.levels[l].stack[E.second]);
}
}
@@ -316,10 +338,10 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *
return;
}
- ERR_FAIL_INDEX(p_level, _debug_call_stack_pos);
- int l = _debug_call_stack_pos - p_level - 1;
+ ERR_FAIL_INDEX(p_level, _call_stack.stack_pos);
+ int l = _call_stack.stack_pos - p_level - 1;
- GDScriptInstance *instance = _call_stack[l].instance;
+ GDScriptInstance *instance = _call_stack.levels[l].instance;
if (!instance) {
return;
@@ -341,10 +363,10 @@ ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) {
return nullptr;
}
- ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, nullptr);
+ ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, nullptr);
- int l = _debug_call_stack_pos - p_level - 1;
- ScriptInstance *instance = _call_stack[l].instance;
+ int l = _call_stack.stack_pos - p_level - 1;
+ ScriptInstance *instance = _call_stack.levels[l].instance;
return instance;
}
@@ -1435,11 +1457,11 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
} break;
case GDScriptParser::Node::SELF: {
if (p_context.current_class) {
- r_type.type.kind = GDScriptParser::DataType::CLASS;
- r_type.type.type_source = GDScriptParser::DataType::INFERRED;
- r_type.type.is_constant = true;
- r_type.type.class_type = p_context.current_class;
- r_type.value = p_context.base;
+ if (p_context.type != GDScriptParser::COMPLETION_SUPER_METHOD) {
+ r_type.type = p_context.current_class->get_datatype();
+ } else {
+ r_type.type = p_context.current_class->base_type;
+ }
found = true;
}
} break;
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 9bbfb14f31..dfe66e6688 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -539,12 +539,12 @@ private:
struct Profile {
StringName signature;
- uint64_t call_count = 0;
- uint64_t self_time = 0;
- uint64_t total_time = 0;
- uint64_t frame_call_count = 0;
- uint64_t frame_self_time = 0;
- uint64_t frame_total_time = 0;
+ SafeNumeric<uint64_t> call_count;
+ SafeNumeric<uint64_t> self_time;
+ SafeNumeric<uint64_t> total_time;
+ SafeNumeric<uint64_t> frame_call_count;
+ SafeNumeric<uint64_t> frame_self_time;
+ SafeNumeric<uint64_t> frame_total_time;
uint64_t last_frame_call_count = 0;
uint64_t last_frame_self_time = 0;
uint64_t last_frame_total_time = 0;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index e17ee0668f..2b91ba8f86 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -783,20 +783,6 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(b
if (member->identifier != nullptr) {
if (!((String)member->identifier->name).is_empty()) { // Enums may be unnamed.
-
-#ifdef DEBUG_ENABLED
- List<MethodInfo> gdscript_funcs;
- GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
- for (MethodInfo &info : gdscript_funcs) {
- if (info.name == member->identifier->name) {
- push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
- }
- }
- if (Variant::has_utility_function(member->identifier->name)) {
- push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
- }
-#endif
-
if (current_class->members_indices.has(member->identifier->name)) {
push_error(vformat(R"(%s "%s" has the same name as a previously declared %s.)", p_member_kind.capitalize(), member->identifier->name, current_class->get_member(member->identifier->name).get_type_name()), member->identifier);
} else {
@@ -1139,6 +1125,7 @@ GDScriptParser::ConstantNode *GDScriptParser::parse_constant(bool p_is_static) {
ConstantNode *constant = alloc_node<ConstantNode>();
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected constant name after "const".)")) {
+ complete_extents(constant);
return nullptr;
}
@@ -2147,6 +2134,7 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_
ExpressionNode *expression = parse_expression(false);
if (expression == nullptr) {
push_error(R"(Expected expression for match pattern.)");
+ complete_extents(pattern);
return nullptr;
} else {
if (expression->type == GDScriptParser::Node::LITERAL) {
@@ -3229,7 +3217,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_type_test(ExpressionNode *
}
GDScriptParser::ExpressionNode *GDScriptParser::parse_yield(ExpressionNode *p_previous_operand, bool p_can_assign) {
- push_error(R"("yield" was removed in Godot 4.0. Use "await" instead.)");
+ push_error(R"("yield" was removed in Godot 4. Use "await" instead.)");
return nullptr;
}
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index a8c9cfa579..44c4cb0fc3 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -663,8 +663,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (GDScriptLanguage::get_singleton()->profiling) {
function_start_time = OS::get_singleton()->get_ticks_usec();
function_call_time = 0;
- profile.call_count++;
- profile.frame_call_count++;
+ profile.call_count.increment();
+ profile.frame_call_count.increment();
}
bool exit_ok = false;
bool awaited = false;
@@ -3550,7 +3550,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
// line
bool do_break = false;
- if (EngineDebugger::get_script_debugger()->get_lines_left() > 0) {
+ if (unlikely(EngineDebugger::get_script_debugger()->get_lines_left() > 0)) {
if (EngineDebugger::get_script_debugger()->get_depth() <= 0) {
EngineDebugger::get_script_debugger()->set_lines_left(EngineDebugger::get_script_debugger()->get_lines_left() - 1);
}
@@ -3563,7 +3563,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
do_break = true;
}
- if (do_break) {
+ if (unlikely(do_break)) {
GDScriptLanguage::get_singleton()->debug_break("Breakpoint", true);
}
@@ -3630,11 +3630,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
uint64_t time_taken = OS::get_singleton()->get_ticks_usec() - function_start_time;
- profile.total_time += time_taken;
- profile.self_time += time_taken - function_call_time;
- profile.frame_total_time += time_taken;
- profile.frame_self_time += time_taken - function_call_time;
- GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
+ profile.total_time.add(time_taken);
+ profile.self_time.add(time_taken - function_call_time);
+ profile.frame_total_time.add(time_taken);
+ profile.frame_self_time.add(time_taken - function_call_time);
+ if (Thread::get_caller_id() == Thread::get_main_id()) {
+ GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
+ }
}
// Check if this is not the last time it was interrupted by `await` or if it's the first time executing.
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index e23bd50b8b..605e82be6e 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -98,7 +98,7 @@ public:
return;
}
- virtual String _get_name() const override { return "GDScript"; }
+ virtual String get_name() const override { return "GDScript"; }
};
static void _editor_init() {
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd
index 38c2faa859..8709b89b54 100644
--- a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd
@@ -1,2 +1,2 @@
func test():
- CanvasItem.new()
+ InstancePlaceholder.new()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out
index 9eff912b59..36224c6b6f 100644
--- a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out
@@ -1,2 +1,2 @@
GDTEST_ANALYZER_ERROR
-Native class "CanvasItem" cannot be constructed as it is abstract.
+Native class "InstancePlaceholder" cannot be constructed as it is abstract.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd
index 118e7e8a45..be67182efb 100644
--- a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd
@@ -1,4 +1,4 @@
-class A extends CanvasItem:
+class A extends InstancePlaceholder:
func _init():
print('no')
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out
index 8b956f5974..260f062555 100644
--- a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out
@@ -1,2 +1,2 @@
GDTEST_ANALYZER_ERROR
-Class "abstract_script_instantiate.gd::B" cannot be constructed as it is based on abstract native class "CanvasItem".
+Class "abstract_script_instantiate.gd::B" cannot be constructed as it is based on abstract native class "InstancePlaceholder".
diff --git a/modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.gd b/modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.gd
index a9004a346b..3e647407cd 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.gd
+++ b/modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.gd
@@ -1,7 +1,7 @@
extends Node
@onready var shorthand = $Node
-@onready var call = get_node(^"Node")
+@onready var call_no_cast = get_node(^"Node")
@onready var shorthand_with_cast = $Node as Node
@onready var call_with_cast = get_node(^"Node") as Node
@@ -13,6 +13,6 @@ func _init():
func test():
# Those are expected to be `null` since `_ready()` is never called on tests.
prints("shorthand", shorthand)
- prints("call", call)
+ prints("call_no_cast", call_no_cast)
prints("shorthand_with_cast", shorthand_with_cast)
prints("call_with_cast", call_with_cast)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.out b/modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.out
index eddc2deec0..78b830aad0 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.out
+++ b/modules/gdscript/tests/scripts/analyzer/features/allow_get_node_with_onready.out
@@ -1,5 +1,5 @@
GDTEST_OK
shorthand <null>
-call <null>
+call_no_cast <null>
shorthand_with_cast <null>
call_with_cast <null>
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd
index 61945c9c8f..29239a19da 100644
--- a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd
@@ -1,5 +1,9 @@
var member: int = 0
+var print_debug := 'print_debug'
+@warning_ignore("shadowed_global_identifier")
+var print := 'print'
+
@warning_ignore("unused_variable")
func test():
var Array := 'Array'
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out
index 8467697a96..accc791d8a 100644
--- a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out
@@ -1,26 +1,30 @@
GDTEST_OK
>> WARNING
->> Line: 5
+>> Line: 3
+>> SHADOWED_GLOBAL_IDENTIFIER
+>> The variable "print_debug" has the same name as a built-in function.
+>> WARNING
+>> Line: 9
>> SHADOWED_GLOBAL_IDENTIFIER
>> The variable "Array" has the same name as a built-in type.
>> WARNING
->> Line: 6
+>> Line: 10
>> SHADOWED_GLOBAL_IDENTIFIER
>> The variable "Node" has the same name as a global class.
>> WARNING
->> Line: 7
+>> Line: 11
>> SHADOWED_GLOBAL_IDENTIFIER
>> The variable "is_same" has the same name as a built-in function.
>> WARNING
->> Line: 8
+>> Line: 12
>> SHADOWED_GLOBAL_IDENTIFIER
>> The variable "sqrt" has the same name as a built-in function.
>> WARNING
->> Line: 9
+>> Line: 13
>> SHADOWED_VARIABLE
>> The local variable "member" is shadowing an already-declared variable at line 1.
>> WARNING
->> Line: 10
+>> Line: 14
>> SHADOWED_VARIABLE_BASE_CLASS
>> The local variable "reference" is shadowing an already-declared method at the base class "RefCounted".
warn
diff --git a/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.out b/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.out
index 36cb699e92..f68d76d101 100644
--- a/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.out
+++ b/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-"yield" was removed in Godot 4.0. Use "await" instead.
+"yield" was removed in Godot 4. Use "await" instead.
diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml
index 62263eaea6..24f6dbd887 100644
--- a/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml
+++ b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneFormatImporterBlend" inherits="EditorSceneFormatImporter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="EditorSceneFormatImporterBlend" inherits="EditorSceneFormatImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Importer for Blender's [code].blend[/code] scene file format.
</brief_description>
diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml
index 7e609d8c7d..b33735f4ad 100644
--- a/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml
+++ b/modules/gltf/doc_classes/EditorSceneFormatImporterFBX.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneFormatImporterFBX" inherits="EditorSceneFormatImporter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="EditorSceneFormatImporterFBX" inherits="EditorSceneFormatImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Importer for the [code].fbx[/code] scene file format.
</brief_description>
diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml
index 80932fad59..2293e75a3c 100644
--- a/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml
+++ b/modules/gltf/doc_classes/EditorSceneFormatImporterGLTF.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneFormatImporterGLTF" inherits="EditorSceneFormatImporter" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="EditorSceneFormatImporterGLTF" inherits="EditorSceneFormatImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml
index e4e4b79d6e..8e4a72e6ae 100644
--- a/modules/gltf/doc_classes/GLTFAccessor.xml
+++ b/modules/gltf/doc_classes/GLTFAccessor.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFAccessor" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFAccessor" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFAnimation.xml b/modules/gltf/doc_classes/GLTFAnimation.xml
index df7fa50a93..c1fe85c1c0 100644
--- a/modules/gltf/doc_classes/GLTFAnimation.xml
+++ b/modules/gltf/doc_classes/GLTFAnimation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFAnimation" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFAnimation" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFBufferView.xml b/modules/gltf/doc_classes/GLTFBufferView.xml
index 0acf8942ac..ce19650b5b 100644
--- a/modules/gltf/doc_classes/GLTFBufferView.xml
+++ b/modules/gltf/doc_classes/GLTFBufferView.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFBufferView" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFBufferView" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml
index e34e5d028c..c2ed4d08e3 100644
--- a/modules/gltf/doc_classes/GLTFCamera.xml
+++ b/modules/gltf/doc_classes/GLTFCamera.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFCamera" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFCamera" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents a GLTF camera.
</brief_description>
diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index a1cdbdea25..5bc6081803 100644
--- a/modules/gltf/doc_classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFDocument" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFDocument" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
index 6b8f2aa904..927ffb6aae 100644
--- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFDocumentExtension" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFDocumentExtension" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
[GLTFDocument] extension class.
</brief_description>
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml
index d54d675e15..3ca0359311 100644
--- a/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFDocumentExtensionConvertImporterMesh" inherits="GLTFDocumentExtension" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFDocumentExtensionConvertImporterMesh" inherits="GLTFDocumentExtension" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml
index 9b12d42d63..c55962eeaa 100644
--- a/modules/gltf/doc_classes/GLTFLight.xml
+++ b/modules/gltf/doc_classes/GLTFLight.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFLight" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFLight" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents a GLTF light.
</brief_description>
diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml
index aa8e8448f7..df4d436f5c 100644
--- a/modules/gltf/doc_classes/GLTFMesh.xml
+++ b/modules/gltf/doc_classes/GLTFMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFMesh" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFMesh" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index 853af99257..2ec39801f3 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFNode" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFNode" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
GLTF node class.
</brief_description>
diff --git a/modules/gltf/doc_classes/GLTFPhysicsBody.xml b/modules/gltf/doc_classes/GLTFPhysicsBody.xml
index 5d21deff05..3aab1c5183 100644
--- a/modules/gltf/doc_classes/GLTFPhysicsBody.xml
+++ b/modules/gltf/doc_classes/GLTFPhysicsBody.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFPhysicsBody" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFPhysicsBody" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents a GLTF physics body.
</brief_description>
diff --git a/modules/gltf/doc_classes/GLTFPhysicsShape.xml b/modules/gltf/doc_classes/GLTFPhysicsShape.xml
index 4b673d6001..2891fab115 100644
--- a/modules/gltf/doc_classes/GLTFPhysicsShape.xml
+++ b/modules/gltf/doc_classes/GLTFPhysicsShape.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFPhysicsShape" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFPhysicsShape" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents a GLTF physics shape.
</brief_description>
diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml
index 8073db3ce9..c7b8cb2ac3 100644
--- a/modules/gltf/doc_classes/GLTFSkeleton.xml
+++ b/modules/gltf/doc_classes/GLTFSkeleton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFSkeleton" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFSkeleton" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml
index 3d5d8000ab..98436ea2e7 100644
--- a/modules/gltf/doc_classes/GLTFSkin.xml
+++ b/modules/gltf/doc_classes/GLTFSkin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFSkin" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFSkin" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFSpecGloss.xml b/modules/gltf/doc_classes/GLTFSpecGloss.xml
index b153444c84..d64a918920 100644
--- a/modules/gltf/doc_classes/GLTFSpecGloss.xml
+++ b/modules/gltf/doc_classes/GLTFSpecGloss.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFSpecGloss" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFSpecGloss" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Archived GLTF extension for specular/glossy materials.
</brief_description>
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 7614839b8b..32023de696 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFState" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFState" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents all data of a GLTF file.
</brief_description>
diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml
index 768e7a8945..41c20439ea 100644
--- a/modules/gltf/doc_classes/GLTFTexture.xml
+++ b/modules/gltf/doc_classes/GLTFTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFTexture" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFTexture" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gltf/doc_classes/GLTFTextureSampler.xml b/modules/gltf/doc_classes/GLTFTextureSampler.xml
index a24c2f0f84..027d35e9d2 100644
--- a/modules/gltf/doc_classes/GLTFTextureSampler.xml
+++ b/modules/gltf/doc_classes/GLTFTextureSampler.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GLTFTextureSampler" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GLTFTextureSampler" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents a GLTF texture sampler
</brief_description>
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 00bf3e58b0..d828363e03 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -49,6 +49,8 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
+#include "scene/resources/image_texture.h"
+#include "scene/resources/portable_compressed_texture.h"
#include "scene/resources/skin.h"
#include "scene/resources/surface_tool.h"
@@ -3769,6 +3771,12 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
extensions["KHR_materials_unlit"] = mat_unlit;
p_state->add_used_extension("KHR_materials_unlit");
}
+ if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && !Math::is_equal_approx(base_material->get_emission_energy_multiplier(), 1.0f)) {
+ Dictionary mat_emissive_strength;
+ mat_emissive_strength["emissiveStrength"] = base_material->get_emission_energy_multiplier();
+ extensions["KHR_materials_emissive_strength"] = mat_emissive_strength;
+ p_state->add_used_extension("KHR_materials_emissive_strength");
+ }
d["extensions"] = extensions;
materials.push_back(d);
@@ -3789,28 +3797,35 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
const Array &materials = p_state->json["materials"];
for (GLTFMaterialIndex i = 0; i < materials.size(); i++) {
- const Dictionary &d = materials[i];
+ const Dictionary &material_dict = materials[i];
Ref<StandardMaterial3D> material;
material.instantiate();
- if (d.has("name") && !String(d["name"]).is_empty()) {
- material->set_name(d["name"]);
+ if (material_dict.has("name") && !String(material_dict["name"]).is_empty()) {
+ material->set_name(material_dict["name"]);
} else {
material->set_name(vformat("material_%s", itos(i)));
}
material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- Dictionary pbr_spec_gloss_extensions;
- if (d.has("extensions")) {
- pbr_spec_gloss_extensions = d["extensions"];
+ Dictionary material_extensions;
+ if (material_dict.has("extensions")) {
+ material_extensions = material_dict["extensions"];
}
- if (pbr_spec_gloss_extensions.has("KHR_materials_unlit")) {
+ if (material_extensions.has("KHR_materials_unlit")) {
material->set_shading_mode(BaseMaterial3D::SHADING_MODE_UNSHADED);
}
- if (pbr_spec_gloss_extensions.has("KHR_materials_pbrSpecularGlossiness")) {
+ if (material_extensions.has("KHR_materials_emissive_strength")) {
+ Dictionary emissive_strength = material_extensions["KHR_materials_emissive_strength"];
+ if (emissive_strength.has("emissiveStrength")) {
+ material->set_emission_energy_multiplier(emissive_strength["emissiveStrength"]);
+ }
+ }
+
+ if (material_extensions.has("KHR_materials_pbrSpecularGlossiness")) {
WARN_PRINT("Material uses a specular and glossiness workflow. Textures will be converted to roughness and metallic workflow, which may not be 100% accurate.");
- Dictionary sgm = pbr_spec_gloss_extensions["KHR_materials_pbrSpecularGlossiness"];
+ Dictionary sgm = material_extensions["KHR_materials_pbrSpecularGlossiness"];
Ref<GLTFSpecGloss> spec_gloss;
spec_gloss.instantiate();
@@ -3858,8 +3873,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
}
spec_gloss_to_rough_metal(spec_gloss, material);
- } else if (d.has("pbrMetallicRoughness")) {
- const Dictionary &mr = d["pbrMetallicRoughness"];
+ } else if (material_dict.has("pbrMetallicRoughness")) {
+ const Dictionary &mr = material_dict["pbrMetallicRoughness"];
if (mr.has("baseColorFactor")) {
const Array &arr = mr["baseColorFactor"];
ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR);
@@ -3911,8 +3926,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
}
}
- if (d.has("normalTexture")) {
- const Dictionary &bct = d["normalTexture"];
+ if (material_dict.has("normalTexture")) {
+ const Dictionary &bct = material_dict["normalTexture"];
if (bct.has("index")) {
material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(p_state, bct["index"], TEXTURE_TYPE_NORMAL));
material->set_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING, true);
@@ -3921,8 +3936,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
material->set_normal_scale(bct["scale"]);
}
}
- if (d.has("occlusionTexture")) {
- const Dictionary &bct = d["occlusionTexture"];
+ if (material_dict.has("occlusionTexture")) {
+ const Dictionary &bct = material_dict["occlusionTexture"];
if (bct.has("index")) {
material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(p_state, bct["index"], TEXTURE_TYPE_GENERIC));
material->set_ao_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED);
@@ -3930,8 +3945,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
}
}
- if (d.has("emissiveFactor")) {
- const Array &arr = d["emissiveFactor"];
+ if (material_dict.has("emissiveFactor")) {
+ const Array &arr = material_dict["emissiveFactor"];
ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
@@ -3939,8 +3954,8 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
material->set_emission(c);
}
- if (d.has("emissiveTexture")) {
- const Dictionary &bct = d["emissiveTexture"];
+ if (material_dict.has("emissiveTexture")) {
+ const Dictionary &bct = material_dict["emissiveTexture"];
if (bct.has("index")) {
material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(p_state, bct["index"], TEXTURE_TYPE_GENERIC));
material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
@@ -3948,20 +3963,20 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
}
}
- if (d.has("doubleSided")) {
- const bool ds = d["doubleSided"];
+ if (material_dict.has("doubleSided")) {
+ const bool ds = material_dict["doubleSided"];
if (ds) {
material->set_cull_mode(BaseMaterial3D::CULL_DISABLED);
}
}
- if (d.has("alphaMode")) {
- const String &am = d["alphaMode"];
+ if (material_dict.has("alphaMode")) {
+ const String &am = material_dict["alphaMode"];
if (am == "BLEND") {
material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
} else if (am == "MASK") {
material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR);
- if (d.has("alphaCutoff")) {
- material->set_alpha_scissor_threshold(d["alphaCutoff"]);
+ if (material_dict.has("alphaCutoff")) {
+ material->set_alpha_scissor_threshold(material_dict["alphaCutoff"]);
} else {
material->set_alpha_scissor_threshold(0.5f);
}
@@ -7461,6 +7476,7 @@ Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> p_state) {
supported_extensions.insert("KHR_materials_pbrSpecularGlossiness");
supported_extensions.insert("KHR_texture_transform");
supported_extensions.insert("KHR_materials_unlit");
+ supported_extensions.insert("KHR_materials_emissive_strength");
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
Vector<String> ext_supported_extensions = ext->get_supported_extensions();
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index 87149fa11d..1788ffac3a 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -70,9 +70,9 @@ static void _editor_init() {
if (blend_enabled) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (blender3_path.is_empty()) {
- WARN_PRINT("Blend file import is enabled in the project settings, but no Blender path is configured in the editor settings. Blend files will not be imported.");
+ WARN_PRINT(TTR("Blend file import is enabled in the project settings, but no Blender path is configured in the editor settings. Blend files will not be imported."));
} else if (!da->dir_exists(blender3_path)) {
- WARN_PRINT("Blend file import is enabled, but the Blender path doesn't point to an accessible directory. Blend files will not be imported.");
+ WARN_PRINT(TTR("Blend file import is enabled, but the Blender path doesn't point to an accessible directory. Blend files will not be imported."));
} else {
Ref<EditorSceneFormatImporterBlend> importer;
importer.instantiate();
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index e413560c16..f9c3ca476a 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GridMap" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GridMap" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Node for 3D tile-based maps.
</brief_description>
@@ -138,11 +138,11 @@
Returns the position of a grid cell in the GridMap's local coordinate space. To convert the returned value into global coordinates, use [method Node3D.to_global]. See also [method map_to_local].
</description>
</method>
- <method name="resource_changed">
+ <method name="resource_changed" is_deprecated="true">
<return type="void" />
<param index="0" name="resource" type="Resource" />
<description>
- Notifies the [GridMap] about changed resource and recreates octant data.
+ [i]Obsoleted.[/i] Use [signal Resource.changed] instead.
</description>
</method>
<method name="set_cell_item">
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index c77fa98be2..f1e2218434 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -258,11 +258,11 @@ RID GridMap::get_navigation_map() const {
void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) {
if (!mesh_library.is_null()) {
- mesh_library->unregister_owner(this);
+ mesh_library->disconnect_changed(callable_mp(this, &GridMap::_recreate_octant_data));
}
mesh_library = p_mesh_library;
if (!mesh_library.is_null()) {
- mesh_library->register_owner(this);
+ mesh_library->connect_changed(callable_mp(this, &GridMap::_recreate_octant_data));
}
_recreate_octant_data();
@@ -1005,9 +1005,10 @@ void GridMap::clear() {
clear_baked_meshes();
}
+#ifndef DISABLE_DEPRECATED
void GridMap::resource_changed(const Ref<Resource> &p_res) {
- _recreate_octant_data();
}
+#endif
void GridMap::_update_octants_callback() {
if (!awaiting_update) {
@@ -1079,7 +1080,9 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &GridMap::map_to_local);
ClassDB::bind_method(D_METHOD("_update_octants_callback"), &GridMap::_update_octants_callback);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &GridMap::resource_changed);
+#endif
ClassDB::bind_method(D_METHOD("set_center_x", "enable"), &GridMap::set_center_x);
ClassDB::bind_method(D_METHOD("get_center_x"), &GridMap::get_center_x);
@@ -1336,10 +1339,6 @@ void GridMap::_navigation_map_changed(RID p_map) {
#endif // DEBUG_ENABLED
GridMap::~GridMap() {
- if (!mesh_library.is_null()) {
- mesh_library->unregister_owner(this);
- }
-
clear();
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton()->disconnect("map_changed", callable_mp(this, &GridMap::_navigation_map_changed));
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index 18c3f90269..e05979efbc 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -203,7 +203,9 @@ class GridMap : public Node3D {
void _queue_octants_dirty();
void _update_octants_callback();
+#ifndef DISABLE_DEPRECATED
void resource_changed(const Ref<Resource> &p_res);
+#endif
void _clear_internal();
diff --git a/modules/minimp3/config.py b/modules/minimp3/config.py
index bd35d099b9..e6bdcb2a83 100644
--- a/modules/minimp3/config.py
+++ b/modules/minimp3/config.py
@@ -9,6 +9,7 @@ def configure(env):
def get_doc_classes():
return [
"AudioStreamMP3",
+ "ResourceImporterMP3",
]
diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml
index 3ece7ce15e..14676a4545 100644
--- a/modules/minimp3/doc_classes/AudioStreamMP3.xml
+++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamMP3" inherits="AudioStream" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="AudioStreamMP3" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
MP3 audio stream driver.
</brief_description>
diff --git a/modules/minimp3/doc_classes/ResourceImporterMP3.xml b/modules/minimp3/doc_classes/ResourceImporterMP3.xml
new file mode 100644
index 0000000000..a84c51cf68
--- /dev/null
+++ b/modules/minimp3/doc_classes/ResourceImporterMP3.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterMP3" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Imports a MP3 audio file for playback.
+ </brief_description>
+ <description>
+ MP3 is a lossy audio format, with worse audio quality compared to [ResourceImporterOggVorbis] at a given bitrate.
+ In most cases, it's recommended to use Ogg Vorbis over MP3. However, if you're using a MP3 sound source with no higher quality source available, then it's recommended to use the MP3 file directly to avoid double lossy compression.
+ MP3 requires more CPU to decode than [ResourceImporterWAV]. If you need to play a lot of simultaneous sounds, it's recommended to use WAV for those sounds instead, especially if targeting low-end devices.
+ </description>
+ <tutorials>
+ <link title="Importing audio samples">$DOCS_URL/tutorials/assets_pipeline/importing_audio_samples.html</link>
+ </tutorials>
+ <members>
+ <member name="bar_beats" type="int" setter="" getter="" default="4">
+ The number of bars within a single beat in the audio track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects.
+ A more convenient editor for [member bar_beats] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio.
+ </member>
+ <member name="beat_count" type="int" setter="" getter="" default="0">
+ The beat count of the audio track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects.
+ A more convenient editor for [member beat_count] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio.
+ </member>
+ <member name="bpm" type="float" setter="" getter="" default="0">
+ The Beats Per Minute of the audio track. This should match the BPM measure that was used to compose the track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects.
+ A more convenient editor for [member bpm] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio.
+ </member>
+ <member name="loop" type="bool" setter="" getter="" default="false">
+ If enabled, the audio will begin playing at the beginning after playback ends by reaching the end of the audio.
+ [b]Note:[/b] In [AudioStreamPlayer], the [signal AudioStreamPlayer.finished] signal won't be emitted for looping audio when it reaches the end of the audio file, as the audio will keep playing indefinitely.
+ </member>
+ <member name="loop_offset" type="float" setter="" getter="" default="0">
+ Determines where audio will start to loop after playback reaches the end of the audio. This can be used to only loop a part of the audio file, which is useful for some ambient sounds or music. The value is determined in seconds relative to the beginning of the audio. A value of [code]0.0[/code] will loop the entire audio file.
+ Only has an effect if [member loop] is [code]true[/code].
+ A more convenient editor for [member loop_offset] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio.
+ </member>
+ </members>
+</class>
diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp
index da89321018..627d093bc1 100644
--- a/modules/minimp3/register_types.cpp
+++ b/modules/minimp3/register_types.cpp
@@ -51,7 +51,11 @@ void initialize_minimp3_module(ModuleInitializationLevel p_level) {
mp3_import.instantiate();
ResourceFormatImporter::get_singleton()->add_importer(mp3_import);
}
+
+ // Required to document import options in the class reference.
+ GDREGISTER_CLASS(ResourceImporterMP3);
#endif
+
GDREGISTER_CLASS(AudioStreamMP3);
}
diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
index ecd07d4520..1be8cc828d 100644
--- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml
+++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MobileVRInterface" inherits="XRInterface" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="MobileVRInterface" inherits="XRInterface" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Generic mobile VR implementation.
</brief_description>
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
index 0b91cda9b8..580f51c973 100755
--- a/modules/mono/build_scripts/build_assemblies.py
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -286,15 +286,29 @@ def generate_sdk_package_versions():
version_status = version_status[:pos] + "." + version_status[pos:]
version_str += "-" + version_status
+ import version
+
+ version_defines = (
+ [
+ f"GODOT{version.major}",
+ f"GODOT{version.major}_{version.minor}",
+ f"GODOT{version.major}_{version.minor}_{version.patch}",
+ ]
+ + [f"GODOT{v}_OR_GREATER" for v in range(4, version.major + 1)]
+ + [f"GODOT{version.major}_{v}_OR_GREATER" for v in range(0, version.minor + 1)]
+ + [f"GODOT{version.major}_{version.minor}_{v}_OR_GREATER" for v in range(0, version.patch + 1)]
+ )
+
props = """<Project>
<PropertyGroup>
<PackageVersion_GodotSharp>{0}</PackageVersion_GodotSharp>
<PackageVersion_Godot_NET_Sdk>{0}</PackageVersion_Godot_NET_Sdk>
<PackageVersion_Godot_SourceGenerators>{0}</PackageVersion_Godot_SourceGenerators>
+ <GodotVersionConstants>{1}</GodotVersionConstants>
</PropertyGroup>
</Project>
""".format(
- version_str
+ version_str, ";".join(version_defines)
)
# We write in ../SdkPackageVersions.props.
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 3e032f213b..1ed495943f 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -2272,7 +2272,7 @@ void CSharpScript::reload_registered_script(Ref<CSharpScript> p_script) {
// If the EditorFileSystem singleton is available, update the file;
// otherwise, the file will be updated when the singleton becomes available.
EditorFileSystem *efs = EditorFileSystem::get_singleton();
- if (efs) {
+ if (efs && !p_script->get_path().is_empty()) {
efs->update_file(p_script->get_path());
}
#endif
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml
index ab14c13811..b559ca20b2 100644
--- a/modules/mono/doc_classes/CSharpScript.xml
+++ b/modules/mono/doc_classes/CSharpScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSharpScript" inherits="Script" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="CSharpScript" inherits="Script" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A script implemented in the C# programming language, saved with the [code].cs[/code] extension (Mono-enabled builds only).
</brief_description>
diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml
index 76eefc4925..969ca14350 100644
--- a/modules/mono/doc_classes/GodotSharp.xml
+++ b/modules/mono/doc_classes/GodotSharp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GodotSharp" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="GodotSharp" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Bridge between Godot and the Mono runtime (Mono-enabled builds only).
</brief_description>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
index e8ad6a77ea..663eb14f07 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
@@ -7,7 +7,7 @@
<Authors>Godot Engine contributors</Authors>
<PackageId>Godot.NET.Sdk</PackageId>
- <Version>4.1.0</Version>
+ <Version>4.2.0</Version>
<PackageVersion>$(PackageVersion_Godot_NET_Sdk)</PackageVersion>
<RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/Godot.NET.Sdk</RepositoryUrl>
<PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
index 45f930fdf7..b0bee795f8 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
@@ -74,15 +74,8 @@
<!-- Godot DefineConstants. -->
<PropertyGroup>
- <!-- Define constants to identify Godot builds and versions. -->
- <GodotDefineConstants>
- GODOT;
- GODOT4;GODOT4_OR_GREATER;
- GODOT4_1;GODOT4_1_OR_GREATER;GODOT4_0_OR_GREATER;
- GODOT4_1_0;GODOT4_1_0_OR_GREATER;
- </GodotDefineConstants>
- <!-- Ensure the define constants don't contain whitespace (see https://github.com/dotnet/roslyn/issues/58391). -->
- <GodotDefineConstants>$(GodotDefineConstants.Replace('%0A','').Replace('%0D','').Replace('%09','').Replace(' ',''))</GodotDefineConstants>
+ <!-- Define constants to identify Godot builds. -->
+ <GodotDefineConstants>GODOT</GodotDefineConstants>
<!--
Define constant to determine the target Godot platform. This includes the
@@ -97,7 +90,7 @@
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'ios' ">GODOT_IPHONE;GODOT_IOS;GODOT_MOBILE</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'web' ">GODOT_JAVASCRIPT;GODOT_HTML5;GODOT_WASM;GODOT_WEB</GodotPlatformConstants>
- <GodotDefineConstants>$(GodotDefineConstants);$(GodotPlatformConstants)</GodotDefineConstants>
+ <GodotDefineConstants>$(GodotDefineConstants);$(GodotPlatformConstants);$(GodotVersionConstants)</GodotDefineConstants>
</PropertyGroup>
<PropertyGroup>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
index 8be1151142..72614dd7e0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -384,5 +384,65 @@ namespace Godot.SourceGenerators
typeArgumentSyntax.GetLocation(),
typeArgumentSyntax.SyntaxTree.FilePath));
}
+
+ public static readonly DiagnosticDescriptor GlobalClassMustDeriveFromGodotObjectRule =
+ new DiagnosticDescriptor(id: "GD0401",
+ title: "The class must derive from GodotObject or a derived class",
+ messageFormat: "The class '{0}' must derive from GodotObject or a derived class.",
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ "The class must derive from GodotObject or a derived class. Change the base class or remove the '[GlobalClass]' attribute.");
+
+ public static void ReportGlobalClassMustDeriveFromGodotObject(
+ SyntaxNodeAnalysisContext context,
+ SyntaxNode classSyntax,
+ ISymbol typeSymbol)
+ {
+ string message = $"The class '{typeSymbol.ToDisplayString()}' must derive from GodotObject or a derived class";
+
+ string description = $"{message}. Change the base class or remove the '[GlobalClass]' attribute.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0401",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ classSyntax.GetLocation(),
+ classSyntax.SyntaxTree.FilePath));
+ }
+
+ public static readonly DiagnosticDescriptor GlobalClassMustNotBeGenericRule =
+ new DiagnosticDescriptor(id: "GD0402",
+ title: "The class must not contain generic arguments",
+ messageFormat: "The class '{0}' must not contain generic arguments",
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ "The class must be a non-generic type. Remove the generic arguments or the '[GlobalClass]' attribute.");
+
+ public static void ReportGlobalClassMustNotBeGeneric(
+ SyntaxNodeAnalysisContext context,
+ SyntaxNode classSyntax,
+ ISymbol typeSymbol)
+ {
+ string message = $"The class '{typeSymbol.ToDisplayString()}' must not contain generic arguments";
+
+ string description = $"{message}. Remove the generic arguments or the '[GlobalClass]' attribute.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0402",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ classSyntax.GetLocation(),
+ classSyntax.SyntaxTree.FilePath));
+ }
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index 38af1cbade..b6ea4b8e88 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -37,7 +37,7 @@ namespace Godot.SourceGenerators
while (symbol != null)
{
if (symbol.ContainingAssembly?.Name == assemblyName &&
- symbol.ToString() == typeFullName)
+ symbol.FullQualifiedNameOmitGlobal() == typeFullName)
{
return true;
}
@@ -81,7 +81,7 @@ namespace Godot.SourceGenerators
return godotClassName ?? nativeType.Name;
}
- private static bool IsGodotScriptClass(
+ private static bool TryGetGodotScriptClass(
this ClassDeclarationSyntax cds, Compilation compilation,
out INamedTypeSymbol? symbol
)
@@ -108,7 +108,7 @@ namespace Godot.SourceGenerators
{
foreach (var cds in source)
{
- if (cds.IsGodotScriptClass(compilation, out var symbol))
+ if (cds.TryGetGodotScriptClass(compilation, out var symbol))
yield return (cds, symbol!);
}
}
@@ -230,22 +230,22 @@ namespace Godot.SourceGenerators
.Replace(">", ")");
public static bool IsGodotExportAttribute(this INamedTypeSymbol symbol)
- => symbol.ToString() == GodotClasses.ExportAttr;
+ => symbol.FullQualifiedNameOmitGlobal() == GodotClasses.ExportAttr;
public static bool IsGodotSignalAttribute(this INamedTypeSymbol symbol)
- => symbol.ToString() == GodotClasses.SignalAttr;
+ => symbol.FullQualifiedNameOmitGlobal() == GodotClasses.SignalAttr;
public static bool IsGodotMustBeVariantAttribute(this INamedTypeSymbol symbol)
- => symbol.ToString() == GodotClasses.MustBeVariantAttr;
+ => symbol.FullQualifiedNameOmitGlobal() == GodotClasses.MustBeVariantAttr;
public static bool IsGodotClassNameAttribute(this INamedTypeSymbol symbol)
- => symbol.ToString() == GodotClasses.GodotClassNameAttr;
+ => symbol.FullQualifiedNameOmitGlobal() == GodotClasses.GodotClassNameAttr;
public static bool IsGodotGlobalClassAttribute(this INamedTypeSymbol symbol)
- => symbol.ToString() == GodotClasses.GlobalClassAttr;
+ => symbol.FullQualifiedNameOmitGlobal() == GodotClasses.GlobalClassAttr;
public static bool IsSystemFlagsAttribute(this INamedTypeSymbol symbol)
- => symbol.ToString() == GodotClasses.SystemFlagsAttr;
+ => symbol.FullQualifiedNameOmitGlobal() == GodotClasses.SystemFlagsAttr;
public static GodotMethodData? HasGodotCompatibleSignature(
this IMethodSymbol method,
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs
new file mode 100644
index 0000000000..bcb35dae8a
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs
@@ -0,0 +1,42 @@
+using System.Collections.Immutable;
+using System.Linq;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Godot.SourceGenerators
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class GlobalClassAnalyzer : DiagnosticAnalyzer
+ {
+ public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
+ => ImmutableArray.Create(
+ Common.GlobalClassMustDeriveFromGodotObjectRule,
+ Common.GlobalClassMustNotBeGenericRule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+ context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
+ }
+
+ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
+ {
+ var typeClassDecl = (ClassDeclarationSyntax)context.Node;
+
+ // Return if not a type symbol or the type is not a global class.
+ if (context.ContainingSymbol is not INamedTypeSymbol typeSymbol ||
+ !typeSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotGlobalClassAttribute() ?? false))
+ return;
+
+ if (typeSymbol.IsGenericType)
+ Common.ReportGlobalClassMustNotBeGeneric(context, typeClassDecl, typeSymbol);
+
+ if (!typeSymbol.InheritsFrom("GodotSharp", GodotClasses.GodotObject))
+ Common.ReportGlobalClassMustDeriveFromGodotObject(context, typeClassDecl, typeSymbol);
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
index 2557b70e75..a03c9bc06c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
@@ -9,7 +9,7 @@
<Authors>Godot Engine contributors</Authors>
<PackageId>Godot.SourceGenerators</PackageId>
- <Version>4.1.0</Version>
+ <Version>4.2.0</Version>
<PackageVersion>$(PackageVersion_Godot_SourceGenerators)</PackageVersion>
<RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators</RepositoryUrl>
<PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
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 1affe692d0..5ea0ca53c3 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -135,6 +135,10 @@ namespace Godot.SourceGenerators
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+ source.Append(" /// <summary>\n")
+ .Append(" /// Cached StringNames for the methods contained in this class, for fast lookup.\n")
+ .Append(" /// </summary>\n");
+
source.Append(
$" public new class MethodName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.MethodName {{\n");
@@ -147,6 +151,12 @@ namespace Godot.SourceGenerators
foreach (string methodName in distinctMethodNames)
{
+ source.Append(" /// <summary>\n")
+ .Append(" /// Cached name for the '")
+ .Append(methodName)
+ .Append("' method.\n")
+ .Append(" /// </summary>\n");
+
source.Append(" public new static readonly global::Godot.StringName ");
source.Append(methodName);
source.Append(" = \"");
@@ -162,6 +172,14 @@ namespace Godot.SourceGenerators
{
const string listType = "global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
+ source.Append(" /// <summary>\n")
+ .Append(" /// Get the method information for all the methods declared in this class.\n")
+ .Append(" /// This method is used by Godot to register the available methods in the editor.\n")
+ .Append(" /// Do not call this method.\n")
+ .Append(" /// </summary>\n");
+
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
+
source.Append(" internal new static ")
.Append(listType)
.Append(" GetGodotMethodList()\n {\n");
@@ -188,6 +206,8 @@ namespace Godot.SourceGenerators
if (godotClassMethods.Length > 0)
{
+ source.Append(" /// <inheritdoc/>\n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(" protected override bool InvokeGodotClassMethod(in godot_string_name method, ");
source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n {\n");
@@ -205,6 +225,8 @@ namespace Godot.SourceGenerators
if (distinctMethodNames.Length > 0)
{
+ source.Append(" /// <inheritdoc/>\n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(" protected override bool HasGodotClassMethod(in godot_string_name method)\n {\n");
bool isFirstEntry = true;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index e856ad5c13..94d8696717 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -124,6 +124,10 @@ namespace Godot.SourceGenerators
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+ source.Append(" /// <summary>\n")
+ .Append(" /// Cached StringNames for the properties and fields contained in this class, for fast lookup.\n")
+ .Append(" /// </summary>\n");
+
source.Append(
$" public new class PropertyName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.PropertyName {{\n");
@@ -132,6 +136,13 @@ namespace Godot.SourceGenerators
foreach (var property in godotClassProperties)
{
string propertyName = property.PropertySymbol.Name;
+
+ source.Append(" /// <summary>\n")
+ .Append(" /// Cached name for the '")
+ .Append(propertyName)
+ .Append("' property.\n")
+ .Append(" /// </summary>\n");
+
source.Append(" public new static readonly global::Godot.StringName ");
source.Append(propertyName);
source.Append(" = \"");
@@ -142,6 +153,13 @@ namespace Godot.SourceGenerators
foreach (var field in godotClassFields)
{
string fieldName = field.FieldSymbol.Name;
+
+ source.Append(" /// <summary>\n")
+ .Append(" /// Cached name for the '")
+ .Append(fieldName)
+ .Append("' field.\n")
+ .Append(" /// </summary>\n");
+
source.Append(" public new static readonly global::Godot.StringName ");
source.Append(fieldName);
source.Append(" = \"");
@@ -162,6 +180,8 @@ namespace Godot.SourceGenerators
if (!allPropertiesAreReadOnly)
{
+ source.Append(" /// <inheritdoc/>\n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(" protected override bool SetGodotClassPropertyValue(in godot_string_name name, ");
source.Append("in godot_variant value)\n {\n");
@@ -193,6 +213,8 @@ namespace Godot.SourceGenerators
// Generate GetGodotClassPropertyValue
+ source.Append(" /// <inheritdoc/>\n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, ");
source.Append("out godot_variant value)\n {\n");
@@ -217,7 +239,15 @@ namespace Godot.SourceGenerators
// Generate GetGodotPropertyList
- string dictionaryType = "global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>";
+ const string dictionaryType = "global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>";
+
+ source.Append(" /// <summary>\n")
+ .Append(" /// Get the property information for all the properties declared in this class.\n")
+ .Append(" /// This method is used by Godot to register the available properties in the editor.\n")
+ .Append(" /// Do not call this method.\n")
+ .Append(" /// </summary>\n");
+
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(" internal new static ")
.Append(dictionaryType)
@@ -362,7 +392,7 @@ namespace Godot.SourceGenerators
{
foreach (var attr in memberSymbol.GetAttributes())
{
- PropertyUsageFlags? propertyUsage = attr.AttributeClass?.ToString() switch
+ PropertyUsageFlags? propertyUsage = attr.AttributeClass?.FullQualifiedNameOmitGlobal() switch
{
GodotClasses.ExportCategoryAttr => PropertyUsageFlags.Category,
GodotClasses.ExportGroupAttr => PropertyUsageFlags.Group,
@@ -620,7 +650,7 @@ namespace Godot.SourceGenerators
bool isPresetHint = false;
- if (elementVariantType == VariantType.String)
+ if (elementVariantType == VariantType.String || elementVariantType == VariantType.StringName)
isPresetHint = GetStringArrayEnumHint(elementVariantType, exportAttr, out hintString);
if (!isPresetHint)
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
index ac908a6de3..4df16d05f0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -285,10 +285,20 @@ namespace Godot.SourceGenerators
{
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
- string dictionaryType =
+ const string dictionaryType =
"global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>";
source.Append("#if TOOLS\n");
+
+ source.Append(" /// <summary>\n")
+ .Append(" /// Get the default values for all properties declared in this class.\n")
+ .Append(" /// This method is used by Godot to determine the value that will be\n")
+ .Append(" /// used by the inspector when resetting properties.\n")
+ .Append(" /// Do not call this method.\n")
+ .Append(" /// </summary>\n");
+
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
+
source.Append(" internal new static ");
source.Append(dictionaryType);
source.Append(" GetGodotPropertyDefaultValues()\n {\n");
@@ -320,7 +330,8 @@ namespace Godot.SourceGenerators
source.Append(" return values;\n");
source.Append(" }\n");
- source.Append("#endif\n");
+
+ source.Append("#endif // TOOLS\n");
source.Append("#pragma warning restore CS0109\n");
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
index 97771b721d..231a7be021 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -149,6 +149,8 @@ namespace Godot.SourceGenerators
godotSignalDelegates.Add(new(signalName, signalDelegateSymbol, invokeMethodData.Value));
}
+ source.Append(" /// <inheritdoc/>\n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(
" protected override void SaveGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info)\n {\n");
source.Append(" base.SaveGodotObjectData(info);\n");
@@ -196,6 +198,8 @@ namespace Godot.SourceGenerators
source.Append(" }\n");
+ source.Append(" /// <inheritdoc/>\n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(
" protected override void RestoreGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info)\n {\n");
source.Append(" base.RestoreGodotObjectData(info);\n");
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index 7e3323f588..8f2774d5ae 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -176,6 +176,10 @@ namespace Godot.SourceGenerators
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+ source.Append(" /// <summary>\n")
+ .Append(" /// Cached StringNames for the signals contained in this class, for fast lookup.\n")
+ .Append(" /// </summary>\n");
+
source.Append(
$" public new class SignalName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.SignalName {{\n");
@@ -184,6 +188,13 @@ namespace Godot.SourceGenerators
foreach (var signalDelegate in godotSignalDelegates)
{
string signalName = signalDelegate.Name;
+
+ source.Append(" /// <summary>\n")
+ .Append(" /// Cached name for the '")
+ .Append(signalName)
+ .Append("' signal.\n")
+ .Append(" /// </summary>\n");
+
source.Append(" public new static readonly global::Godot.StringName ");
source.Append(signalName);
source.Append(" = \"");
@@ -199,6 +210,14 @@ namespace Godot.SourceGenerators
{
const string listType = "global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
+ source.Append(" /// <summary>\n")
+ .Append(" /// Get the signal information for all the signals declared in this class.\n")
+ .Append(" /// This method is used by Godot to register the available signals in the editor.\n")
+ .Append(" /// Do not call this method.\n")
+ .Append(" /// </summary>\n");
+
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
+
source.Append(" internal new static ")
.Append(listType)
.Append(" GetGodotSignalList()\n {\n");
@@ -258,6 +277,8 @@ namespace Godot.SourceGenerators
if (godotSignalDelegates.Count > 0)
{
+ source.Append(" /// <inheritdoc/>\n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(
" protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, ");
source.Append("NativeVariantPtrArgs args)\n {\n");
@@ -276,6 +297,8 @@ namespace Godot.SourceGenerators
if (godotSignalDelegates.Count > 0)
{
+ source.Append(" /// <inheritdoc/>\n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(
" protected override bool HasGodotClassSignal(in godot_string_name signal)\n {\n");
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
index 30525ba04a..4a0b7f9bed 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
@@ -28,10 +28,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3.0" ExcludeAssets="runtime" PrivateAssets="all" />
+ <PackageReference Include="JetBrains.Rider.PathLocator" Version="1.0.1" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
- <!-- For RiderPathLocator -->
- <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<Reference Include="GodotSharp">
<HintPath>$(GodotApiAssembliesDir)/GodotSharp.dll</HintPath>
<Private>False</Private>
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs
index 62db6e3af5..51c7a8aa22 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs
@@ -385,9 +385,12 @@ namespace GodotTools.Ides
// However, it doesn't fix resource loading if the rest of the path is also case insensitive.
string scriptFileLocalized = FsPathUtils.LocalizePathWithCaseChecked(request.ScriptFile);
+ // The node API can only be called from the main thread.
+ await Godot.Engine.GetMainLoop().ToSignal(Godot.Engine.GetMainLoop(), "process_frame");
+
var response = new CodeCompletionResponse { Kind = request.Kind, ScriptFile = request.ScriptFile };
- response.Suggestions = await Task.Run(() =>
- Internal.CodeCompletionRequest(response.Kind, scriptFileLocalized ?? request.ScriptFile));
+ response.Suggestions = Internal.CodeCompletionRequest(response.Kind,
+ scriptFileLocalized ?? request.ScriptFile);
return response;
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderLocatorEnvironment.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderLocatorEnvironment.cs
new file mode 100644
index 0000000000..7e08d8c01d
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderLocatorEnvironment.cs
@@ -0,0 +1,51 @@
+using System;
+using Godot;
+using JetBrains.Rider.PathLocator;
+using Newtonsoft.Json;
+using OS = GodotTools.Utils.OS;
+
+namespace GodotTools.Ides.Rider;
+
+public class RiderLocatorEnvironment : IRiderLocatorEnvironment
+{
+ public JetBrains.Rider.PathLocator.OS CurrentOS
+ {
+ get
+ {
+ if (OS.IsWindows)
+ return JetBrains.Rider.PathLocator.OS.Windows;
+ if (OS.IsMacOS) return JetBrains.Rider.PathLocator.OS.MacOSX;
+ if (OS.IsUnixLike) return JetBrains.Rider.PathLocator.OS.Linux;
+ return JetBrains.Rider.PathLocator.OS.Other;
+ }
+ }
+
+ public T FromJson<T>(string json)
+ {
+ return JsonConvert.DeserializeObject<T>(json);
+ }
+
+ public void Info(string message, Exception e = null)
+ {
+ if (e == null)
+ GD.Print(message);
+ else
+ GD.Print(message, e);
+ }
+
+ public void Warn(string message, Exception e = null)
+ {
+ if (e == null)
+ GD.PushWarning(message);
+ else
+ GD.PushWarning(message, e);
+ }
+
+ public void Error(string message, Exception e = null)
+ {
+ if (e == null)
+ GD.PushError(message);
+ else
+ GD.PushError(message, e);
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
deleted file mode 100644
index dad6e35344..0000000000
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
+++ /dev/null
@@ -1,474 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.Linq;
-using System.Runtime.Versioning;
-using Godot;
-using Microsoft.Win32;
-using Newtonsoft.Json;
-using Directory = System.IO.Directory;
-using Environment = System.Environment;
-using File = System.IO.File;
-using Path = System.IO.Path;
-using OS = GodotTools.Utils.OS;
-
-// ReSharper disable UnassignedField.Local
-// ReSharper disable InconsistentNaming
-// ReSharper disable UnassignedField.Global
-// ReSharper disable MemberHidesStaticFromOuterClass
-
-namespace GodotTools.Ides.Rider
-{
- /// <summary>
- /// This code is a modified version of the JetBrains resharper-unity plugin listed under Apache License 2.0 license:
- /// https://github.com/JetBrains/resharper-unity/blob/master/unity/JetBrains.Rider.Unity.Editor/EditorPlugin/RiderPathLocator.cs
- /// </summary>
- public static class RiderPathLocator
- {
- public static RiderInfo[] GetAllRiderPaths()
- {
- try
- {
- if (OS.IsWindows)
- {
- return CollectRiderInfosWindows();
- }
- if (OS.IsMacOS)
- {
- return CollectRiderInfosMac();
- }
- if (OS.IsUnixLike)
- {
- return CollectAllRiderPathsLinux();
- }
- throw new InvalidOperationException("Unexpected OS.");
- }
- catch (Exception e)
- {
- GD.PushWarning(e.Message);
- }
-
- return Array.Empty<RiderInfo>();
- }
-
- private static RiderInfo[] CollectAllRiderPathsLinux()
- {
- var installInfos = new List<RiderInfo>();
- string home = Environment.GetEnvironmentVariable("HOME");
- if (!string.IsNullOrEmpty(home))
- {
- string toolboxRiderRootPath = GetToolboxBaseDir();
- installInfos.AddRange(CollectPathsFromToolbox(toolboxRiderRootPath, "bin", "rider.sh", false)
- .Select(a => new RiderInfo(a, true)).ToList());
-
- //$Home/.local/share/applications/jetbrains-rider.desktop
- var shortcut = new FileInfo(Path.Combine(home, @".local/share/applications/jetbrains-rider.desktop"));
-
- if (shortcut.Exists)
- {
- string[] lines = File.ReadAllLines(shortcut.FullName);
- foreach (string line in lines)
- {
- if (!line.StartsWith("Exec=\""))
- continue;
- string path = line.Split('"').Where((item, index) => index == 1).SingleOrDefault();
- if (string.IsNullOrEmpty(path))
- continue;
-
- if (installInfos.Any(a => a.Path == path)) // avoid adding similar build as from toolbox
- continue;
- installInfos.Add(new RiderInfo(path, false));
- }
- }
- }
-
- // snap install
- string snapInstallPath = "/snap/rider/current/bin/rider.sh";
- if (new FileInfo(snapInstallPath).Exists)
- installInfos.Add(new RiderInfo(snapInstallPath, false));
-
- return installInfos.ToArray();
- }
-
- private static RiderInfo[] CollectRiderInfosMac()
- {
- var installInfos = new List<RiderInfo>();
- // "/Applications/*Rider*.app"
- // should be combined with "Contents/MacOS/rider"
- var folder = new DirectoryInfo("/Applications");
- if (folder.Exists)
- {
- installInfos.AddRange(folder.GetDirectories("*Rider*.app")
- .Select(a => new RiderInfo(Path.Combine(a.FullName, "Contents/MacOS/rider"), false))
- .ToList());
- }
-
- // /Users/user/Library/Application Support/JetBrains/Toolbox/apps/Rider/ch-1/181.3870.267/Rider EAP.app
- // should be combined with "Contents/MacOS/rider"
- string toolboxRiderRootPath = GetToolboxBaseDir();
- var paths = CollectPathsFromToolbox(toolboxRiderRootPath, "", "Rider*.app", true)
- .Select(a => new RiderInfo(Path.Combine(a, "Contents/MacOS/rider"), true));
- installInfos.AddRange(paths);
-
- return installInfos.ToArray();
- }
-
- [SupportedOSPlatform("windows")]
- private static RiderInfo[] CollectRiderInfosWindows()
- {
- var installInfos = new List<RiderInfo>();
- var toolboxRiderRootPath = GetToolboxBaseDir();
- var installPathsToolbox = CollectPathsFromToolbox(toolboxRiderRootPath, "bin", "rider64.exe", false).ToList();
- installInfos.AddRange(installPathsToolbox.Select(a => new RiderInfo(a, true)).ToList());
-
- var installPaths = new List<string>();
- const string registryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
- CollectPathsFromRegistry(registryKey, installPaths);
- const string wowRegistryKey = @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
- CollectPathsFromRegistry(wowRegistryKey, installPaths);
-
- installInfos.AddRange(installPaths.Select(a => new RiderInfo(a, false)).ToList());
-
- return installInfos.ToArray();
- }
-
- private static string GetToolboxBaseDir()
- {
- if (OS.IsWindows)
- {
- string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
- return GetToolboxRiderRootPath(localAppData);
- }
-
- if (OS.IsMacOS)
- {
- var home = Environment.GetEnvironmentVariable("HOME");
- if (string.IsNullOrEmpty(home))
- return string.Empty;
- var localAppData = Path.Combine(home, @"Library/Application Support");
- return GetToolboxRiderRootPath(localAppData);
- }
-
- if (OS.IsUnixLike)
- {
- var home = Environment.GetEnvironmentVariable("HOME");
- if (string.IsNullOrEmpty(home))
- return string.Empty;
- var localAppData = Path.Combine(home, @".local/share");
- return GetToolboxRiderRootPath(localAppData);
- }
-
- return string.Empty;
- }
-
-
- private static string GetToolboxRiderRootPath(string localAppData)
- {
- var toolboxPath = Path.Combine(localAppData, @"JetBrains/Toolbox");
- var settingsJson = Path.Combine(toolboxPath, ".settings.json");
-
- if (File.Exists(settingsJson))
- {
- var path = SettingsJson.GetInstallLocationFromJson(File.ReadAllText(settingsJson));
- if (!string.IsNullOrEmpty(path))
- toolboxPath = path;
- }
-
- var toolboxRiderRootPath = Path.Combine(toolboxPath, @"apps/Rider");
- return toolboxRiderRootPath;
- }
-
- internal static ProductInfo GetBuildVersion(string path)
- {
- var buildTxtFileInfo = new FileInfo(Path.Combine(path, GetRelativePathToBuildTxt()));
- var dir = buildTxtFileInfo.DirectoryName;
- if (!Directory.Exists(dir))
- return null;
- var buildVersionFile = new FileInfo(Path.Combine(dir, "product-info.json"));
- if (!buildVersionFile.Exists)
- return null;
- var json = File.ReadAllText(buildVersionFile.FullName);
- return ProductInfo.GetProductInfo(json);
- }
-
- internal static Version GetBuildNumber(string path)
- {
- var file = new FileInfo(Path.Combine(path, GetRelativePathToBuildTxt()));
- if (!file.Exists)
- return null;
- var text = File.ReadAllText(file.FullName);
- if (text.Length <= 3)
- return null;
-
- var versionText = text.Substring(3);
- return Version.TryParse(versionText, out var v) ? v : null;
- }
-
- internal static bool IsToolbox(string path)
- {
- return path.StartsWith(GetToolboxBaseDir());
- }
-
- private static string GetRelativePathToBuildTxt()
- {
- if (OS.IsWindows || OS.IsUnixLike)
- return "../../build.txt";
- if (OS.IsMacOS)
- return "Contents/Resources/build.txt";
- throw new InvalidOperationException("Unknown OS.");
- }
-
- [SupportedOSPlatform("windows")]
- private static void CollectPathsFromRegistry(string registryKey, List<string> installPaths)
- {
- using (var key = Registry.CurrentUser.OpenSubKey(registryKey))
- {
- CollectPathsFromRegistry(installPaths, key);
- }
- using (var key = Registry.LocalMachine.OpenSubKey(registryKey))
- {
- CollectPathsFromRegistry(installPaths, key);
- }
- }
-
- [SupportedOSPlatform("windows")]
- private static void CollectPathsFromRegistry(List<string> installPaths, RegistryKey key)
- {
- if (key == null) return;
- foreach (var subkeyName in key.GetSubKeyNames().Where(a => a.Contains("Rider")))
- {
- using (var subkey = key.OpenSubKey(subkeyName))
- {
- var folderObject = subkey?.GetValue("InstallLocation");
- if (folderObject == null) continue;
- var folder = folderObject.ToString();
- var possiblePath = Path.Combine(folder, @"bin\rider64.exe");
- if (File.Exists(possiblePath))
- installPaths.Add(possiblePath);
- }
- }
- }
-
- private static string[] CollectPathsFromToolbox(string toolboxRiderRootPath, string dirName, string searchPattern,
- bool isMac)
- {
- if (!Directory.Exists(toolboxRiderRootPath))
- return Array.Empty<string>();
-
- var channelDirs = Directory.GetDirectories(toolboxRiderRootPath);
- var paths = channelDirs.SelectMany(channelDir =>
- {
- try
- {
- // use history.json - last entry stands for the active build https://jetbrains.slack.com/archives/C07KNP99D/p1547807024066500?thread_ts=1547731708.057700&cid=C07KNP99D
- var historyFile = Path.Combine(channelDir, ".history.json");
- if (File.Exists(historyFile))
- {
- var json = File.ReadAllText(historyFile);
- var build = ToolboxHistory.GetLatestBuildFromJson(json);
- if (build != null)
- {
- var buildDir = Path.Combine(channelDir, build);
- var executablePaths = GetExecutablePaths(dirName, searchPattern, isMac, buildDir);
- if (executablePaths.Any())
- return executablePaths;
- }
- }
-
- var channelFile = Path.Combine(channelDir, ".channel.settings.json");
- if (File.Exists(channelFile))
- {
- var json = File.ReadAllText(channelFile).Replace("active-application", "active_application");
- var build = ToolboxInstallData.GetLatestBuildFromJson(json);
- if (build != null)
- {
- var buildDir = Path.Combine(channelDir, build);
- var executablePaths = GetExecutablePaths(dirName, searchPattern, isMac, buildDir);
- if (executablePaths.Any())
- return executablePaths;
- }
- }
-
- // changes in toolbox json files format may brake the logic above, so return all found Rider installations
- return Directory.GetDirectories(channelDir)
- .SelectMany(buildDir => GetExecutablePaths(dirName, searchPattern, isMac, buildDir));
- }
- catch (Exception e)
- {
- // do not write to Debug.Log, just log it.
- Logger.Warn($"Failed to get RiderPath from {channelDir}", e);
- }
-
- return Array.Empty<string>();
- })
- .Where(c => !string.IsNullOrEmpty(c))
- .ToArray();
- return paths;
- }
-
- private static string[] GetExecutablePaths(string dirName, string searchPattern, bool isMac, string buildDir)
- {
- var folder = new DirectoryInfo(Path.Combine(buildDir, dirName));
- if (!folder.Exists)
- return Array.Empty<string>();
-
- if (!isMac)
- return new[] { Path.Combine(folder.FullName, searchPattern) }.Where(File.Exists).ToArray();
- return folder.GetDirectories(searchPattern).Select(f => f.FullName)
- .Where(Directory.Exists).ToArray();
- }
-
- // Disable the "field is never assigned" compiler warning. We never assign it, but Unity does.
- // Note that Unity disable this warning in the generated C# projects
-#pragma warning disable 0649
-
- [Serializable]
- class SettingsJson
- {
- public string install_location;
-
- [return: MaybeNull]
- public static string GetInstallLocationFromJson(string json)
- {
- try
- {
- return JsonConvert.DeserializeObject<SettingsJson>(json).install_location;
- }
- catch (Exception)
- {
- Logger.Warn($"Failed to get install_location from json {json}");
- }
-
- return null;
- }
- }
-
- [Serializable]
- class ToolboxHistory
- {
- public List<ItemNode> history;
-
- public static string GetLatestBuildFromJson(string json)
- {
- try
- {
- return JsonConvert.DeserializeObject<ToolboxHistory>(json).history.LastOrDefault()?.item.build;
- }
- catch (Exception)
- {
- Logger.Warn($"Failed to get latest build from json {json}");
- }
-
- return null;
- }
- }
-
- [Serializable]
- class ItemNode
- {
- public BuildNode item;
- }
-
- [Serializable]
- class BuildNode
- {
- public string build;
- }
-
- [Serializable]
- public class ProductInfo
- {
- public string version;
- public string versionSuffix;
-
- [return: MaybeNull]
- internal static ProductInfo GetProductInfo(string json)
- {
- try
- {
- var productInfo = JsonConvert.DeserializeObject<ProductInfo>(json);
- return productInfo;
- }
- catch (Exception)
- {
- Logger.Warn($"Failed to get version from json {json}");
- }
-
- return null;
- }
- }
-
- // ReSharper disable once ClassNeverInstantiated.Global
- [Serializable]
- class ToolboxInstallData
- {
- // ReSharper disable once InconsistentNaming
- public ActiveApplication active_application;
-
- [return: MaybeNull]
- public static string GetLatestBuildFromJson(string json)
- {
- try
- {
- var toolbox = JsonConvert.DeserializeObject<ToolboxInstallData>(json);
- var builds = toolbox.active_application.builds;
- if (builds != null && builds.Any())
- return builds.First();
- }
- catch (Exception)
- {
- Logger.Warn($"Failed to get latest build from json {json}");
- }
-
- return null;
- }
- }
-
- [Serializable]
- class ActiveApplication
- {
- public List<string> builds;
- }
-
-#pragma warning restore 0649
-
- public struct RiderInfo
- {
- // ReSharper disable once NotAccessedField.Global
- public bool IsToolbox;
- public string Presentation;
- public Version BuildNumber;
- public ProductInfo ProductInfo;
- public string Path;
-
- public RiderInfo(string path, bool isToolbox)
- {
- BuildNumber = GetBuildNumber(path);
- ProductInfo = GetBuildVersion(path);
- Path = new FileInfo(path).FullName; // normalize separators
- var presentation = $"Rider {BuildNumber}";
-
- if (ProductInfo != null && !string.IsNullOrEmpty(ProductInfo.version))
- {
- var suffix = string.IsNullOrEmpty(ProductInfo.versionSuffix) ? "" : $" {ProductInfo.versionSuffix}";
- presentation = $"Rider {ProductInfo.version}{suffix}";
- }
-
- if (isToolbox)
- presentation += " (JetBrains Toolbox)";
-
- Presentation = presentation;
- IsToolbox = isToolbox;
- }
- }
-
- private static class Logger
- {
- internal static void Warn(string message, Exception e = null)
- {
- throw new Exception(message, e);
- }
- }
- }
-}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
index f55ca4c7d7..5c09f1f83a 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
@@ -4,11 +4,19 @@ using System.IO;
using System.Linq;
using Godot;
using GodotTools.Internals;
+using JetBrains.Rider.PathLocator;
namespace GodotTools.Ides.Rider
{
public static class RiderPathManager
{
+ private static readonly RiderPathLocator RiderPathLocator;
+
+ static RiderPathManager()
+ {
+ RiderPathLocator = new RiderPathLocator(new RiderLocatorEnvironment());
+ }
+
public static readonly string EditorPathSettingName = "dotnet/editor/editor_path_optional";
private static string GetRiderPathFromSettings()
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 15bb574f4d..cff41a57f3 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1616,7 +1616,16 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// Generate InvokeGodotClassMethod
- output << MEMBER_BEGIN "protected internal " << (is_derived_type ? "override" : "virtual")
+ output << MEMBER_BEGIN "/// <summary>\n"
+ << INDENT1 "/// Invokes the method with the given name, using the given arguments.\n"
+ << INDENT1 "/// This method is used by Godot to invoke methods from the engine side.\n"
+ << INDENT1 "/// Do not call or override this method.\n"
+ << INDENT1 "/// </summary>\n"
+ << INDENT1 "/// <param name=\"method\">Name of the method to invoke.</param>\n"
+ << INDENT1 "/// <param name=\"args\">Arguments to use with the invoked method.</param>\n"
+ << INDENT1 "/// <param name=\"ret\">Value returned by the invoked method.</param>\n";
+
+ output << INDENT1 "protected internal " << (is_derived_type ? "override" : "virtual")
<< " bool " CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(in godot_string_name method, "
<< "NativeVariantPtrArgs args, out godot_variant ret)\n"
<< INDENT1 "{\n";
@@ -1696,6 +1705,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// Generate HasGodotClassMethod
+ output << MEMBER_BEGIN "/// <summary>\n"
+ << INDENT1 "/// Check if the type contains a method with the given name.\n"
+ << INDENT1 "/// This method is used by Godot to check if a method exists before invoking it.\n"
+ << INDENT1 "/// Do not call or override this method.\n"
+ << INDENT1 "/// </summary>\n"
+ << INDENT1 "/// <param name=\"method\">Name of the method to check for.</param>\n";
+
output << MEMBER_BEGIN "protected internal " << (is_derived_type ? "override" : "virtual")
<< " bool " CS_METHOD_HAS_GODOT_CLASS_METHOD "(in godot_string_name method)\n"
<< INDENT1 "{\n";
@@ -1728,6 +1744,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// Generate HasGodotClassSignal
+ output << MEMBER_BEGIN "/// <summary>\n"
+ << INDENT1 "/// Check if the type contains a signal with the given name.\n"
+ << INDENT1 "/// This method is used by Godot to check if a signal exists before raising it.\n"
+ << INDENT1 "/// Do not call or override this method.\n"
+ << INDENT1 "/// </summary>\n"
+ << INDENT1 "/// <param name=\"method\">Name of the method to check for.</param>\n";
+
output << MEMBER_BEGIN "protected internal " << (is_derived_type ? "override" : "virtual")
<< " bool " CS_METHOD_HAS_GODOT_CLASS_SIGNAL "(in godot_string_name signal)\n"
<< INDENT1 "{\n";
@@ -1758,39 +1781,57 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
//Generate StringName for all class members
bool is_inherit = !itype.is_singleton && obj_types.has(itype.base_name);
//PropertyName
+ output << MEMBER_BEGIN "/// <summary>\n"
+ << INDENT1 "/// Cached StringNames for the properties and fields contained in this class, for fast lookup.\n"
+ << INDENT1 "/// </summary>\n";
if (is_inherit) {
- output << MEMBER_BEGIN "public new class PropertyName : " << obj_types[itype.base_name].proxy_name << ".PropertyName";
+ output << INDENT1 "public new class PropertyName : " << obj_types[itype.base_name].proxy_name << ".PropertyName";
} else {
- output << MEMBER_BEGIN "public class PropertyName";
+ output << INDENT1 "public class PropertyName";
}
output << "\n"
<< INDENT1 "{\n";
for (const PropertyInterface &iprop : itype.properties) {
- output << INDENT2 "public static readonly StringName " << iprop.proxy_name << " = \"" << iprop.cname << "\";\n";
+ output << INDENT2 "/// <summary>\n"
+ << INDENT2 "/// Cached name for the '" << iprop.cname << "' property.\n"
+ << INDENT2 "/// </summary>\n"
+ << INDENT2 "public static readonly StringName " << iprop.proxy_name << " = \"" << iprop.cname << "\";\n";
}
output << INDENT1 "}\n";
//MethodName
+ output << MEMBER_BEGIN "/// <summary>\n"
+ << INDENT1 "/// Cached StringNames for the methods contained in this class, for fast lookup.\n"
+ << INDENT1 "/// </summary>\n";
if (is_inherit) {
- output << MEMBER_BEGIN "public new class MethodName : " << obj_types[itype.base_name].proxy_name << ".MethodName";
+ output << INDENT1 "public new class MethodName : " << obj_types[itype.base_name].proxy_name << ".MethodName";
} else {
- output << MEMBER_BEGIN "public class MethodName";
+ output << INDENT1 "public class MethodName";
}
output << "\n"
<< INDENT1 "{\n";
for (const MethodInterface &imethod : itype.methods) {
- output << INDENT2 "public static readonly StringName " << imethod.proxy_name << " = \"" << imethod.cname << "\";\n";
+ output << INDENT2 "/// <summary>\n"
+ << INDENT2 "/// Cached name for the '" << imethod.cname << "' method.\n"
+ << INDENT2 "/// </summary>\n"
+ << INDENT2 "public static readonly StringName " << imethod.proxy_name << " = \"" << imethod.cname << "\";\n";
}
output << INDENT1 "}\n";
//SignalName
+ output << MEMBER_BEGIN "/// <summary>\n"
+ << INDENT1 "/// Cached StringNames for the signals contained in this class, for fast lookup.\n"
+ << INDENT1 "/// </summary>\n";
if (is_inherit) {
- output << MEMBER_BEGIN "public new class SignalName : " << obj_types[itype.base_name].proxy_name << ".SignalName";
+ output << INDENT1 "public new class SignalName : " << obj_types[itype.base_name].proxy_name << ".SignalName";
} else {
- output << MEMBER_BEGIN "public class SignalName";
+ output << INDENT1 "public class SignalName";
}
output << "\n"
<< INDENT1 "{\n";
for (const SignalInterface &isignal : itype.signals_) {
- output << INDENT2 "public static readonly StringName " << isignal.proxy_name << " = \"" << isignal.cname << "\";\n";
+ output << INDENT2 "/// <summary>\n"
+ << INDENT2 "/// Cached name for the '" << isignal.cname << "' signal.\n"
+ << INDENT2 "/// </summary>\n"
+ << INDENT2 "public static readonly StringName " << isignal.proxy_name << " = \"" << isignal.cname << "\";\n";
}
output << INDENT1 "}\n";
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs
index 37f7005d01..a0bd96412a 100644
--- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs
@@ -38,7 +38,7 @@ internal static class ExtensionMethods
}
private static bool IsGenerateUnmanagedCallbacksAttribute(this INamedTypeSymbol symbol)
- => symbol.ToString() == GeneratorClasses.GenerateUnmanagedCallbacksAttr;
+ => symbol.FullQualifiedNameOmitGlobal() == GeneratorClasses.GenerateUnmanagedCallbacksAttr;
public static IEnumerable<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol)> SelectUnmanagedCallbacksClasses(
this IEnumerable<ClassDeclarationSyntax> source,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs
index af83cc24bf..d25944dceb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs
@@ -564,7 +564,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this <see cref="Aabb"/> is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
@@ -683,7 +683,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the AABB is exactly equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index 36f5d8e2ab..d53dd9a9af 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
+using System.ComponentModel;
namespace Godot
{
@@ -595,7 +596,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this basis is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
@@ -623,21 +624,31 @@ namespace Godot
/// </summary>
/// <param name="target">The position to look at.</param>
/// <param name="up">The relative up direction.</param>
+ /// <param name="useModelFront">
+ /// If true, then the model is oriented in reverse,
+ /// towards the model front axis (+Z, Vector3.ModelFront),
+ /// which is more useful for orienting 3D models.
+ /// </param>
/// <returns>The resulting basis matrix.</returns>
- public static Basis LookingAt(Vector3 target, Vector3 up)
+ public static Basis LookingAt(Vector3 target, Vector3? up = null, bool useModelFront = false)
{
+ up ??= Vector3.Up;
#if DEBUG
if (target.IsZeroApprox())
{
throw new ArgumentException("The vector can't be zero.", nameof(target));
}
- if (up.IsZeroApprox())
+ if (up.Value.IsZeroApprox())
{
throw new ArgumentException("The vector can't be zero.", nameof(up));
}
#endif
- Vector3 column2 = -target.Normalized();
- Vector3 column0 = up.Cross(column2);
+ Vector3 column2 = target.Normalized();
+ if (!useModelFront)
+ {
+ column2 = -column2;
+ }
+ Vector3 column0 = up.Value.Cross(column2);
#if DEBUG
if (column0.IsZeroApprox())
{
@@ -649,6 +660,13 @@ namespace Godot
return new Basis(column0, column1, column2);
}
+ /// <inheritdoc cref="LookingAt(Vector3, Nullable{Vector3}, bool)"/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static Basis LookingAt(Vector3 target, Vector3 up)
+ {
+ return LookingAt(target, up, false);
+ }
+
/// <summary>
/// Returns the orthonormalized version of the basis matrix (useful to
/// call occasionally to avoid rounding errors for orthogonal matrices).
@@ -1065,7 +1083,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the <see cref="Basis"/> is
- /// exactly equal to the given object (<see paramref="obj"/>).
+ /// exactly equal to the given object (<paramref name="obj"/>).
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index 5d03379430..6c2fb7374c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -500,24 +500,17 @@ namespace Godot
Type? returnType = hasReturn ? DeserializeType(reader) : typeof(void);
int parametersCount = reader.ReadInt32();
+ var parameterTypes = parametersCount == 0 ? Type.EmptyTypes : new Type[parametersCount];
- if (parametersCount > 0)
+ for (int i = 0; i < parametersCount; i++)
{
- var parameterTypes = new Type[parametersCount];
-
- for (int i = 0; i < parametersCount; i++)
- {
- Type? parameterType = DeserializeType(reader);
- if (parameterType == null)
- return false;
- parameterTypes[i] = parameterType;
- }
-
- methodInfo = declaringType.GetMethod(methodName, (BindingFlags)flags, null, parameterTypes, null);
- return methodInfo != null && methodInfo.ReturnType == returnType;
+ Type? parameterType = DeserializeType(reader);
+ if (parameterType == null)
+ return false;
+ parameterTypes[i] = parameterType;
}
- methodInfo = declaringType.GetMethod(methodName, (BindingFlags)flags);
+ methodInfo = declaringType.GetMethod(methodName, (BindingFlags)flags, null, parameterTypes, null);
return methodInfo != null && methodInfo.ReturnType == returnType;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs
index b9a5ac82d1..c6337e56ef 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs
@@ -125,7 +125,10 @@ namespace Godot
NativePtr = IntPtr.Zero;
}
- DisposablesTracker.UnregisterGodotObject(this, _weakReferenceToSelf);
+ if (_weakReferenceToSelf != null)
+ {
+ DisposablesTracker.UnregisterGodotObject(this, _weakReferenceToSelf);
+ }
}
/// <summary>
@@ -188,12 +191,30 @@ namespace Godot
}
// ReSharper disable once VirtualMemberNeverOverridden.Global
+ /// <summary>
+ /// Set the value of a property contained in this class.
+ /// This method is used by Godot to assign property values.
+ /// Do not call or override this method.
+ /// </summary>
+ /// <param name="name">Name of the property to set.</param>
+ /// <param name="value">Value to set the property to if it was found.</param>
+ /// <returns><see langword="true"/> if a property with the given name was found.</returns>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected internal virtual bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
{
return false;
}
// ReSharper disable once VirtualMemberNeverOverridden.Global
+ /// <summary>
+ /// Get the value of a property contained in this class.
+ /// This method is used by Godot to retrieve property values.
+ /// Do not call or override this method.
+ /// </summary>
+ /// <param name="name">Name of the property to get.</param>
+ /// <param name="value">Value of the property if it was found.</param>
+ /// <returns><see langword="true"/> if a property with the given name was found.</returns>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected internal virtual bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
{
value = default;
@@ -201,6 +222,14 @@ namespace Godot
}
// ReSharper disable once VirtualMemberNeverOverridden.Global
+ /// <summary>
+ /// Raises the signal with the given name, using the given arguments.
+ /// This method is used by Godot to raise signals from the engine side.\n"
+ /// Do not call or override this method.
+ /// </summary>
+ /// <param name="signal">Name of the signal to raise.</param>
+ /// <param name="args">Arguments to use with the raised signal.</param>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected internal virtual void RaiseGodotClassSignalCallbacks(in godot_string_name signal,
NativeVariantPtrArgs args)
{
@@ -230,11 +259,25 @@ namespace Godot
return nativeConstructor;
}
+ /// <summary>
+ /// Saves this instance's state to be restored when reloading assemblies.
+ /// Do not call or override this method.
+ /// To add data to be saved and restored, implement <see cref="ISerializationListener"/>.
+ /// </summary>
+ /// <param name="info">Object used to save the data.</param>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected internal virtual void SaveGodotObjectData(GodotSerializationInfo info)
{
}
// TODO: Should this be a constructor overload?
+ /// <summary>
+ /// Restores this instance's state after reloading assemblies.
+ /// Do not call or override this method.
+ /// To add data to be saved and restored, implement <see cref="ISerializationListener"/>.
+ /// </summary>
+ /// <param name="info">Object that contains the previously saved data.</param>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected internal virtual void RestoreGodotObjectData(GodotSerializationInfo info)
{
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
index 90b4d1b8d3..3288705dab 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
@@ -1,11 +1,21 @@
namespace Godot
{
/// <summary>
- /// An interface that requires methods for before and after serialization.
+ /// Allows a GodotObject to react to the serialization/deserialization
+ /// that occurs when Godot reloads assemblies.
/// </summary>
public interface ISerializationListener
{
+ /// <summary>
+ /// Executed before serializing this instance's state when reloading assemblies.
+ /// Clear any data that should not be serialized.
+ /// </summary>
void OnBeforeSerialize();
+
+ /// <summary>
+ /// Executed after deserializing this instance's state after reloading assemblies.
+ /// Restore any state that has been lost.
+ /// </summary>
void OnAfterDeserialize();
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
index 55b7a83fc2..3c7455a76c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -204,7 +204,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this plane is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
index 84fc73b87a..998a2786a7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
@@ -976,7 +976,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the projection is exactly equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
index 9c2a6fc654..2e282447bd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
@@ -103,7 +103,7 @@ namespace Godot
///
/// Note: This method has an abnormally high amount
/// of floating-point error, so methods such as
- /// <see cref="Mathf.IsZeroApprox"/> will not work reliably.
+ /// <see cref="Mathf.IsZeroApprox(real_t)"/> will not work reliably.
/// </summary>
/// <param name="to">The other quaternion.</param>
/// <returns>The angle between the quaternions.</returns>
@@ -320,7 +320,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this quaternion is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index 69444f8035..458802f95d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -102,7 +102,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this <see cref="Rect2"/> is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public bool IsFinite()
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index d7392dbda8..618c892681 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -232,7 +232,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this transform is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
@@ -586,7 +586,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the transform is exactly equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index 1e2aaa299f..b16e6e592e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
+using System.ComponentModel;
namespace Godot
{
@@ -155,7 +156,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this transform is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
@@ -175,14 +176,26 @@ namespace Godot
/// </summary>
/// <param name="target">The object to look at.</param>
/// <param name="up">The relative up direction.</param>
+ /// <param name="useModelFront">
+ /// If true, then the model is oriented in reverse,
+ /// towards the model front axis (+Z, Vector3.ModelFront),
+ /// which is more useful for orienting 3D models.
+ /// </param>
/// <returns>The resulting transform.</returns>
- public readonly Transform3D LookingAt(Vector3 target, Vector3 up)
+ public readonly Transform3D LookingAt(Vector3 target, Vector3? up = null, bool useModelFront = false)
{
Transform3D t = this;
- t.SetLookAt(Origin, target, up);
+ t.SetLookAt(Origin, target, up ?? Vector3.Up, useModelFront);
return t;
}
+ /// <inheritdoc cref="LookingAt(Vector3, Nullable{Vector3}, bool)"/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public readonly Transform3D LookingAt(Vector3 target, Vector3 up)
+ {
+ return LookingAt(target, up, false);
+ }
+
/// <summary>
/// Returns the transform with the basis orthogonal (90 degrees),
/// and normalized axis vectors (scale of 1 or -1).
@@ -247,9 +260,9 @@ namespace Godot
return new Transform3D(Basis * tmpBasis, Origin);
}
- private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up)
+ private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up, bool useModelFront = false)
{
- Basis = Basis.LookingAt(target - eye, up);
+ Basis = Basis.LookingAt(target - eye, up, useModelFront);
Origin = eye;
}
@@ -600,7 +613,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the transform is exactly equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index 0bf8f25f06..642ef231f3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -164,7 +164,7 @@ namespace Godot
/// <summary>
/// Returns a new vector with all components rounded up (towards positive infinity).
/// </summary>
- /// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns>
+ /// <returns>A vector with <see cref="Mathf.Ceil(real_t)"/> called on each component.</returns>
public readonly Vector2 Ceil()
{
return new Vector2(Mathf.Ceil(X), Mathf.Ceil(Y));
@@ -318,7 +318,7 @@ namespace Godot
/// <summary>
/// Returns a new vector with all components rounded down (towards negative infinity).
/// </summary>
- /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
+ /// <returns>A vector with <see cref="Mathf.Floor(real_t)"/> called on each component.</returns>
public readonly Vector2 Floor()
{
return new Vector2(Mathf.Floor(X), Mathf.Floor(Y));
@@ -335,7 +335,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this vector is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
@@ -948,7 +948,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the vector is exactly equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
index 0dac8205b6..231e791904 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
@@ -517,7 +517,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the vector is equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index c773c0fda6..7d548f1d10 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -150,7 +150,7 @@ namespace Godot
/// <summary>
/// Returns a new vector with all components rounded up (towards positive infinity).
/// </summary>
- /// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns>
+ /// <returns>A vector with <see cref="Mathf.Ceil(real_t)"/> called on each component.</returns>
public readonly Vector3 Ceil()
{
return new Vector3(Mathf.Ceil(X), Mathf.Ceil(Y), Mathf.Ceil(Z));
@@ -315,7 +315,7 @@ namespace Godot
/// <summary>
/// Returns a new vector with all components rounded down (towards negative infinity).
/// </summary>
- /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
+ /// <returns>A vector with <see cref="Mathf.Floor(real_t)"/> called on each component.</returns>
public readonly Vector3 Floor()
{
return new Vector3(Mathf.Floor(X), Mathf.Floor(Y), Mathf.Floor(Z));
@@ -332,7 +332,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this vector is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
@@ -660,6 +660,13 @@ namespace Godot
private static readonly Vector3 _forward = new Vector3(0, 0, -1);
private static readonly Vector3 _back = new Vector3(0, 0, 1);
+ private static readonly Vector3 _modelLeft = new Vector3(1, 0, 0);
+ private static readonly Vector3 _modelRight = new Vector3(-1, 0, 0);
+ private static readonly Vector3 _modelTop = new Vector3(0, 1, 0);
+ private static readonly Vector3 _modelBottom = new Vector3(0, -1, 0);
+ private static readonly Vector3 _modelFront = new Vector3(0, 0, 1);
+ private static readonly Vector3 _modelRear = new Vector3(0, 0, -1);
+
/// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
/// </summary>
@@ -712,6 +719,31 @@ namespace Godot
public static Vector3 Back { get { return _back; } }
/// <summary>
+ /// Unit vector pointing towards the left side of imported 3D assets.
+ /// </summary>
+ public static Vector3 ModelLeft { get { return _modelLeft; } }
+ /// <summary>
+ /// Unit vector pointing towards the right side of imported 3D assets.
+ /// </summary>
+ public static Vector3 ModelRight { get { return _modelRight; } }
+ /// <summary>
+ /// Unit vector pointing towards the top side (up) of imported 3D assets.
+ /// </summary>
+ public static Vector3 ModelTop { get { return _modelTop; } }
+ /// <summary>
+ /// Unit vector pointing towards the bottom side (down) of imported 3D assets.
+ /// </summary>
+ public static Vector3 ModelBottom { get { return _modelBottom; } }
+ /// <summary>
+ /// Unit vector pointing towards the front side (facing forward) of imported 3D assets.
+ /// </summary>
+ public static Vector3 ModelFront { get { return _modelFront; } }
+ /// <summary>
+ /// Unit vector pointing towards the rear side (back) of imported 3D assets.
+ /// </summary>
+ public static Vector3 ModelRear { get { return _modelRear; } }
+
+ /// <summary>
/// Constructs a new <see cref="Vector3"/> with the given components.
/// </summary>
/// <param name="x">The vector's X component.</param>
@@ -1018,7 +1050,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the vector is exactly equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
index a2927533f8..8543052f56 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
@@ -572,7 +572,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the vector is equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
index 1fd39632b0..10a0b14162 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
@@ -147,7 +147,7 @@ namespace Godot
/// <summary>
/// Returns a new vector with all components rounded up (towards positive infinity).
/// </summary>
- /// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns>
+ /// <returns>A vector with <see cref="Mathf.Ceil(real_t)"/> called on each component.</returns>
public readonly Vector4 Ceil()
{
return new Vector4(Mathf.Ceil(X), Mathf.Ceil(Y), Mathf.Ceil(Z), Mathf.Ceil(W));
@@ -264,7 +264,7 @@ namespace Godot
/// <summary>
/// Returns a new vector with all components rounded down (towards negative infinity).
/// </summary>
- /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
+ /// <returns>A vector with <see cref="Mathf.Floor(real_t)"/> called on each component.</returns>
public readonly Vector4 Floor()
{
return new Vector4(Mathf.Floor(X), Mathf.Floor(Y), Mathf.Floor(Z), Mathf.Floor(W));
@@ -281,7 +281,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if this vector is finite, by calling
- /// <see cref="Mathf.IsFinite"/> on each component.
+ /// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
@@ -832,7 +832,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the vector is exactly equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
index bb552b939d..f813903177 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
@@ -593,7 +593,7 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the vector is equal
- /// to the given object (<see paramref="obj"/>).
+ /// to the given object (<paramref name="obj"/>).
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 16820e363a..8a36b3e514 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -20,7 +20,7 @@
<Authors>Godot Engine contributors</Authors>
<PackageId>GodotSharp</PackageId>
- <Version>4.1.0</Version>
+ <Version>4.2.0</Version>
<PackageVersion>$(PackageVersion_GodotSharp)</PackageVersion>
<RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/glue/GodotSharp/GodotSharp</RepositoryUrl>
<PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
index c249ebf804..db9337d4eb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
@@ -15,7 +15,7 @@
<Authors>Godot Engine contributors</Authors>
<PackageId>GodotSharpEditor</PackageId>
- <Version>4.1.0</Version>
+ <Version>4.2.0</Version>
<PackageVersion>$(PackageVersion_GodotSharp)</PackageVersion>
<RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/glue/GodotSharp/GodotSharpEditor</RepositoryUrl>
<PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
diff --git a/modules/multiplayer/doc_classes/MultiplayerSpawner.xml b/modules/multiplayer/doc_classes/MultiplayerSpawner.xml
index e6564a8aac..482db3e8b5 100644
--- a/modules/multiplayer/doc_classes/MultiplayerSpawner.xml
+++ b/modules/multiplayer/doc_classes/MultiplayerSpawner.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiplayerSpawner" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="MultiplayerSpawner" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Automatically replicates spawnable nodes from the authority to other multiplayer peers.
</brief_description>
diff --git a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
index 82698f7b15..df2644767d 100644
--- a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
+++ b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiplayerSynchronizer" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="MultiplayerSynchronizer" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Synchronizes properties from the multiplayer authority to the remote peers.
</brief_description>
diff --git a/modules/multiplayer/doc_classes/SceneMultiplayer.xml b/modules/multiplayer/doc_classes/SceneMultiplayer.xml
index 224e481f19..7abee8e2c8 100644
--- a/modules/multiplayer/doc_classes/SceneMultiplayer.xml
+++ b/modules/multiplayer/doc_classes/SceneMultiplayer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SceneMultiplayer" inherits="MultiplayerAPI" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="SceneMultiplayer" inherits="MultiplayerAPI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
High-level multiplayer API implementation.
</brief_description>
diff --git a/modules/multiplayer/doc_classes/SceneReplicationConfig.xml b/modules/multiplayer/doc_classes/SceneReplicationConfig.xml
index 55dd9cade2..b976eea30b 100644
--- a/modules/multiplayer/doc_classes/SceneReplicationConfig.xml
+++ b/modules/multiplayer/doc_classes/SceneReplicationConfig.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SceneReplicationConfig" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="SceneReplicationConfig" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Configuration for properties to synchronize with a [MultiplayerSynchronizer].
</brief_description>
diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp
index e5207fdae2..9c2d281f72 100644
--- a/modules/multiplayer/multiplayer_synchronizer.cpp
+++ b/modules/multiplayer/multiplayer_synchronizer.cpp
@@ -157,7 +157,7 @@ Error MultiplayerSynchronizer::get_state(const List<NodePath> &p_properties, Obj
bool valid = false;
const Object *obj = _get_prop_target(p_obj, prop);
ERR_FAIL_COND_V(!obj, FAILED);
- r_variant.write[i] = obj->get(prop.get_concatenated_subnames(), &valid);
+ r_variant.write[i] = obj->get_indexed(prop.get_subnames(), &valid);
r_variant_ptrs.write[i] = &r_variant[i];
ERR_FAIL_COND_V_MSG(!valid, ERR_INVALID_DATA, vformat("Property '%s' not found.", prop));
i++;
@@ -171,7 +171,7 @@ Error MultiplayerSynchronizer::set_state(const List<NodePath> &p_properties, Obj
for (const NodePath &prop : p_properties) {
Object *obj = _get_prop_target(p_obj, prop);
ERR_FAIL_COND_V(!obj, FAILED);
- obj->set(prop.get_concatenated_subnames(), p_state[i]);
+ obj->set_indexed(prop.get_subnames(), p_state[i]);
i += 1;
}
return OK;
diff --git a/modules/navigation/SCsub b/modules/navigation/SCsub
index 18a8d550ec..46bcb0fba4 100644
--- a/modules/navigation/SCsub
+++ b/modules/navigation/SCsub
@@ -37,12 +37,10 @@ if env["builtin_recastnavigation"]:
if env["builtin_rvo2_2d"]:
thirdparty_dir = "#thirdparty/rvo2/rvo2_2d/"
thirdparty_sources = [
- "Agent2d.cc",
- "Obstacle2d.cc",
- "KdTree2d.cc",
- "Line.cc",
- "RVOSimulator2d.cc",
- "Vector2.cc",
+ "Agent2d.cpp",
+ "Obstacle2d.cpp",
+ "KdTree2d.cpp",
+ "RVOSimulator2d.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
@@ -56,11 +54,9 @@ if env["builtin_rvo2_2d"]:
if env["builtin_rvo2_3d"]:
thirdparty_dir = "#thirdparty/rvo2/rvo2_3d/"
thirdparty_sources = [
- "Agent3d.cc",
- "KdTree3d.cc",
- "Plane.cc",
- "RVOSimulator3d.cc",
- "Vector3.cc",
+ "Agent3d.cpp",
+ "KdTree3d.cpp",
+ "RVOSimulator3d.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index bf34779735..c0fa6eef9e 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -340,6 +340,20 @@ RID GodotNavigationServer::region_create() {
return rid;
}
+COMMAND_2(region_set_enabled, RID, p_region, bool, p_enabled) {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND(region == nullptr);
+
+ region->set_enabled(p_enabled);
+}
+
+bool GodotNavigationServer::region_get_enabled(RID p_region) const {
+ const NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, false);
+
+ return region->get_enabled();
+}
+
COMMAND_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled) {
NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
@@ -446,10 +460,13 @@ COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref<NavigationMesh>, p_navi
region->set_mesh(p_navigation_mesh);
}
+#ifndef DISABLE_DEPRECATED
void GodotNavigationServer::region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) {
ERR_FAIL_COND(p_navigation_mesh.is_null());
ERR_FAIL_COND(p_root_node == nullptr);
+ WARN_PRINT_ONCE("NavigationServer3D::region_bake_navigation_mesh() is deprecated due to core threading changes. To upgrade existing code, first create a NavigationMeshSourceGeometryData3D resource. Use this resource with method parse_source_geometry_data() to parse the SceneTree for nodes that should contribute to the navigation mesh baking. The SceneTree parsing needs to happen on the main thread. After the parsing is finished use the resource with method bake_from_source_geometry_data() to bake a navigation mesh..");
+
#ifndef _3D_DISABLED
NavigationMeshGenerator::get_singleton()->clear(p_navigation_mesh);
Ref<NavigationMeshSourceGeometryData3D> source_geometry_data;
@@ -458,6 +475,7 @@ void GodotNavigationServer::region_bake_navigation_mesh(Ref<NavigationMesh> p_na
NavigationMeshGenerator::get_singleton()->bake_from_source_geometry_data(p_navigation_mesh, source_geometry_data);
#endif
}
+#endif // DISABLE_DEPRECATED
int GodotNavigationServer::region_get_connections_count(RID p_region) const {
NavRegion *region = region_owner.get_or_null(p_region);
@@ -508,6 +526,20 @@ RID GodotNavigationServer::link_get_map(const RID p_link) const {
return RID();
}
+COMMAND_2(link_set_enabled, RID, p_link, bool, p_enabled) {
+ NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND(link == nullptr);
+
+ link->set_enabled(p_enabled);
+}
+
+bool GodotNavigationServer::link_get_enabled(RID p_link) const {
+ const NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND_V(link == nullptr, false);
+
+ return link->get_enabled();
+}
+
COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional) {
NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND(link == nullptr);
@@ -784,8 +816,8 @@ COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority) {
}
RID GodotNavigationServer::obstacle_create() {
- GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
- MutexLock lock(mut_this->operations_mutex);
+ MutexLock lock(operations_mutex);
+
RID rid = obstacle_owner.make_rid();
NavObstacle *obstacle = obstacle_owner.get_or_null(rid);
obstacle->set_self(rid);
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index 6b394157bc..0b3789102c 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -135,6 +135,9 @@ public:
virtual RID region_create() override;
+ COMMAND_2(region_set_enabled, RID, p_region, bool, p_enabled);
+ virtual bool region_get_enabled(RID p_region) const override;
+
COMMAND_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled);
virtual bool region_get_use_edge_connections(RID p_region) const override;
@@ -154,7 +157,9 @@ public:
virtual uint32_t region_get_navigation_layers(RID p_region) const override;
COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform);
COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref<NavigationMesh>, p_navigation_mesh);
+#ifndef DISABLE_DEPRECATED
virtual void region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) override;
+#endif // DISABLE_DEPRECATED
virtual int region_get_connections_count(RID p_region) const override;
virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override;
virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override;
@@ -162,6 +167,8 @@ public:
virtual RID link_create() override;
COMMAND_2(link_set_map, RID, p_link, RID, p_map);
virtual RID link_get_map(RID p_link) const override;
+ COMMAND_2(link_set_enabled, RID, p_link, bool, p_enabled);
+ virtual bool link_get_enabled(RID p_link) const override;
COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional);
virtual bool link_is_bidirectional(RID p_link) const override;
COMMAND_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers);
diff --git a/modules/navigation/nav_link.cpp b/modules/navigation/nav_link.cpp
index d712987a46..c693cc91c8 100644
--- a/modules/navigation/nav_link.cpp
+++ b/modules/navigation/nav_link.cpp
@@ -49,6 +49,16 @@ void NavLink::set_map(NavMap *p_map) {
}
}
+void NavLink::set_enabled(bool p_enabled) {
+ if (enabled == p_enabled) {
+ return;
+ }
+ enabled = p_enabled;
+
+ // TODO: This should not require a full rebuild as the link has not really changed.
+ link_dirty = true;
+};
+
void NavLink::set_bidirectional(bool p_bidirectional) {
if (bidirectional == p_bidirectional) {
return;
diff --git a/modules/navigation/nav_link.h b/modules/navigation/nav_link.h
index 0b8ad4db69..a7609831db 100644
--- a/modules/navigation/nav_link.h
+++ b/modules/navigation/nav_link.h
@@ -39,6 +39,7 @@ class NavLink : public NavBase {
bool bidirectional = true;
Vector3 start_position;
Vector3 end_position;
+ bool enabled = true;
bool link_dirty = true;
@@ -52,6 +53,9 @@ public:
return map;
}
+ void set_enabled(bool p_enabled);
+ bool get_enabled() const { return enabled; }
+
void set_bidirectional(bool p_bidirectional);
bool is_bidirectional() const {
return bidirectional;
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 2595a02a61..745c227fe5 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -301,6 +301,46 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
}
}
+ // Search all faces of start polygon as well.
+ bool closest_point_on_start_poly = false;
+ for (size_t point_id = 2; point_id < begin_poly->points.size(); point_id++) {
+ Face3 f(begin_poly->points[0].pos, begin_poly->points[point_id - 1].pos, begin_poly->points[point_id].pos);
+ Vector3 spoint = f.get_closest_point_to(p_destination);
+ real_t dpoint = spoint.distance_to(p_destination);
+ if (dpoint < end_d) {
+ end_point = spoint;
+ end_d = dpoint;
+ closest_point_on_start_poly = true;
+ }
+ }
+
+ if (closest_point_on_start_poly) {
+ // No point to run PostProcessing when start and end convex polygon is the same.
+ if (r_path_types) {
+ r_path_types->resize(2);
+ r_path_types->write[0] = begin_poly->owner->get_type();
+ r_path_types->write[1] = begin_poly->owner->get_type();
+ }
+
+ if (r_path_rids) {
+ r_path_rids->resize(2);
+ (*r_path_rids)[0] = begin_poly->owner->get_self();
+ (*r_path_rids)[1] = begin_poly->owner->get_self();
+ }
+
+ if (r_path_owners) {
+ r_path_owners->resize(2);
+ r_path_owners->write[0] = begin_poly->owner->get_owner_id();
+ r_path_owners->write[1] = begin_poly->owner->get_owner_id();
+ }
+
+ Vector<Vector3> path;
+ path.resize(2);
+ path.write[0] = begin_point;
+ path.write[1] = end_point;
+ return path;
+ }
+
// Reset open and navigation_polys
gd::NavigationPoly np = navigation_polys[0];
navigation_polys.clear();
@@ -346,9 +386,44 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
}
}
- // If we did not find a route, return an empty path.
+ // We did not find a route but we have both a start polygon and an end polygon at this point.
+ // Usually this happens because there was not a single external or internal connected edge, e.g. our start polygon is an isolated, single convex polygon.
if (!found_route) {
- return Vector<Vector3>();
+ end_d = FLT_MAX;
+ // Search all faces of the start polygon for the closest point to our target position.
+ for (size_t point_id = 2; point_id < begin_poly->points.size(); point_id++) {
+ Face3 f(begin_poly->points[0].pos, begin_poly->points[point_id - 1].pos, begin_poly->points[point_id].pos);
+ Vector3 spoint = f.get_closest_point_to(p_destination);
+ real_t dpoint = spoint.distance_to(p_destination);
+ if (dpoint < end_d) {
+ end_point = spoint;
+ end_d = dpoint;
+ }
+ }
+
+ if (r_path_types) {
+ r_path_types->resize(2);
+ r_path_types->write[0] = begin_poly->owner->get_type();
+ r_path_types->write[1] = begin_poly->owner->get_type();
+ }
+
+ if (r_path_rids) {
+ r_path_rids->resize(2);
+ (*r_path_rids)[0] = begin_poly->owner->get_self();
+ (*r_path_rids)[1] = begin_poly->owner->get_self();
+ }
+
+ if (r_path_owners) {
+ r_path_owners->resize(2);
+ r_path_owners->write[0] = begin_poly->owner->get_owner_id();
+ r_path_owners->write[1] = begin_poly->owner->get_owner_id();
+ }
+
+ Vector<Vector3> path;
+ path.resize(2);
+ path.write[0] = begin_point;
+ path.write[1] = end_point;
+ return path;
}
Vector<Vector3> path;
@@ -729,6 +804,9 @@ void NavMap::sync() {
// Resize the polygon count.
int count = 0;
for (const NavRegion *region : regions) {
+ if (!region->get_enabled()) {
+ continue;
+ }
count += region->get_polygons().size();
}
polygons.resize(count);
@@ -736,6 +814,9 @@ void NavMap::sync() {
// Copy all region polygons in the map.
count = 0;
for (const NavRegion *region : regions) {
+ if (!region->get_enabled()) {
+ continue;
+ }
const LocalVector<gd::Polygon> &polygons_source = region->get_polygons();
for (uint32_t n = 0; n < polygons_source.size(); n++) {
polygons[count + n] = polygons_source[n];
@@ -1042,16 +1123,16 @@ void NavMap::_update_rvo_obstacles_tree_2d() {
rvo_2d_obstacle->avoidance_layers_ = _obstacle_avoidance_layers;
if (i != 0) {
- rvo_2d_obstacle->previous_ = raw_obstacles.back();
- rvo_2d_obstacle->previous_->next_ = rvo_2d_obstacle;
+ rvo_2d_obstacle->prevObstacle_ = raw_obstacles.back();
+ rvo_2d_obstacle->prevObstacle_->nextObstacle_ = rvo_2d_obstacle;
}
if (i == rvo_2d_vertices.size() - 1) {
- rvo_2d_obstacle->next_ = raw_obstacles[obstacleNo];
- rvo_2d_obstacle->next_->previous_ = rvo_2d_obstacle;
+ rvo_2d_obstacle->nextObstacle_ = raw_obstacles[obstacleNo];
+ rvo_2d_obstacle->nextObstacle_->prevObstacle_ = rvo_2d_obstacle;
}
- rvo_2d_obstacle->direction_ = normalize(rvo_2d_vertices[(i == rvo_2d_vertices.size() - 1 ? 0 : i + 1)] - rvo_2d_vertices[i]);
+ rvo_2d_obstacle->unitDir_ = normalize(rvo_2d_vertices[(i == rvo_2d_vertices.size() - 1 ? 0 : i + 1)] - rvo_2d_vertices[i]);
if (rvo_2d_vertices.size() == 2) {
rvo_2d_obstacle->isConvex_ = true;
@@ -1099,9 +1180,9 @@ void NavMap::_update_rvo_simulation() {
}
void NavMap::compute_single_avoidance_step_2d(uint32_t index, NavAgent **agent) {
- (*(agent + index))->get_rvo_agent_2d()->computeNeighbors(rvo_simulation_2d.kdTree_);
- (*(agent + index))->get_rvo_agent_2d()->computeNewVelocity(rvo_simulation_2d.timeStep_);
- (*(agent + index))->get_rvo_agent_2d()->update(rvo_simulation_2d.timeStep_);
+ (*(agent + index))->get_rvo_agent_2d()->computeNeighbors(&rvo_simulation_2d);
+ (*(agent + index))->get_rvo_agent_2d()->computeNewVelocity(&rvo_simulation_2d);
+ (*(agent + index))->get_rvo_agent_2d()->update(&rvo_simulation_2d);
(*(agent + index))->update();
}
@@ -1124,9 +1205,9 @@ void NavMap::step(real_t p_deltatime) {
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
} else {
for (NavAgent *agent : active_2d_avoidance_agents) {
- agent->get_rvo_agent_2d()->computeNeighbors(rvo_simulation_2d.kdTree_);
- agent->get_rvo_agent_2d()->computeNewVelocity(rvo_simulation_2d.timeStep_);
- agent->get_rvo_agent_2d()->update(rvo_simulation_2d.timeStep_);
+ agent->get_rvo_agent_2d()->computeNeighbors(&rvo_simulation_2d);
+ agent->get_rvo_agent_2d()->computeNewVelocity(&rvo_simulation_2d);
+ agent->get_rvo_agent_2d()->update(&rvo_simulation_2d);
agent->update();
}
}
diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp
index 867cf5d8fc..4e7964ed76 100644
--- a/modules/navigation/nav_region.cpp
+++ b/modules/navigation/nav_region.cpp
@@ -51,6 +51,16 @@ void NavRegion::set_map(NavMap *p_map) {
}
}
+void NavRegion::set_enabled(bool p_enabled) {
+ if (enabled == p_enabled) {
+ return;
+ }
+ enabled = p_enabled;
+
+ // TODO: This should not require a full rebuild as the region has not really changed.
+ polygons_dirty = true;
+};
+
void NavRegion::set_use_edge_connections(bool p_enabled) {
if (use_edge_connections != p_enabled) {
use_edge_connections = p_enabled;
@@ -115,11 +125,11 @@ void NavRegion::update_polygons() {
#ifdef DEBUG_ENABLED
if (!Math::is_equal_approx(double(map->get_cell_size()), double(mesh->get_cell_size()))) {
- ERR_PRINT_ONCE("Navigation map synchronization error. Attempted to update a navigation region with a navigation mesh that uses a different `cell_size` than the `cell_size` set on the navigation map.");
+ ERR_PRINT_ONCE(vformat("Navigation map synchronization error. Attempted to update a navigation region with a navigation mesh that uses a `cell_size` of %s while assigned to a navigation map set to a `cell_size` of %s. The cell size for navigation maps can be changed by using the NavigationServer map_set_cell_size() function. The cell size for default navigation maps can also be changed in the ProjectSettings.", double(map->get_cell_size()), double(mesh->get_cell_size())));
}
if (!Math::is_equal_approx(double(map->get_cell_height()), double(mesh->get_cell_height()))) {
- ERR_PRINT_ONCE("Navigation map synchronization error. Attempted to update a navigation region with a navigation mesh that uses a different `cell_height` than the `cell_height` set on the navigation map.");
+ ERR_PRINT_ONCE(vformat("Navigation map synchronization error. Attempted to update a navigation region with a navigation mesh that uses a `cell_height` of %s while assigned to a navigation map set to a `cell_height` of %s. The cell height for navigation maps can be changed by using the NavigationServer map_set_cell_height() function. The cell height for default navigation maps can also be changed in the ProjectSettings.", double(map->get_cell_height()), double(mesh->get_cell_height())));
}
if (map && Math::rad_to_deg(map->get_up().angle_to(transform.basis.get_column(1))) >= 90.0f) {
diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h
index 0c3c1b56b6..6a8ebe5336 100644
--- a/modules/navigation/nav_region.h
+++ b/modules/navigation/nav_region.h
@@ -41,6 +41,7 @@ class NavRegion : public NavBase {
Transform3D transform;
Ref<NavigationMesh> mesh;
Vector<gd::Edge::Connection> connections;
+ bool enabled = true;
bool use_edge_connections = true;
@@ -58,6 +59,9 @@ public:
polygons_dirty = true;
}
+ void set_enabled(bool p_enabled);
+ bool get_enabled() const { return enabled; }
+
void set_map(NavMap *p_map);
NavMap *get_map() const {
return map;
diff --git a/modules/noise/doc_classes/FastNoiseLite.xml b/modules/noise/doc_classes/FastNoiseLite.xml
index fb4e0d4f78..4c6cdfbf12 100644
--- a/modules/noise/doc_classes/FastNoiseLite.xml
+++ b/modules/noise/doc_classes/FastNoiseLite.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="FastNoiseLite" inherits="Noise" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="FastNoiseLite" inherits="Noise" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Generates noise using the FastNoiseLite library.
</brief_description>
diff --git a/modules/noise/doc_classes/Noise.xml b/modules/noise/doc_classes/Noise.xml
index c075b5b629..dd232af1cc 100644
--- a/modules/noise/doc_classes/Noise.xml
+++ b/modules/noise/doc_classes/Noise.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Noise" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="Noise" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Abstract base class for noise generators.
</brief_description>
diff --git a/modules/noise/doc_classes/NoiseTexture2D.xml b/modules/noise/doc_classes/NoiseTexture2D.xml
index 4d3e42f3d5..e25af794d4 100644
--- a/modules/noise/doc_classes/NoiseTexture2D.xml
+++ b/modules/noise/doc_classes/NoiseTexture2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NoiseTexture2D" inherits="Texture2D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="NoiseTexture2D" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A texture filled with noise generated by a [Noise] object.
</brief_description>
diff --git a/modules/noise/doc_classes/NoiseTexture3D.xml b/modules/noise/doc_classes/NoiseTexture3D.xml
index 519e4eb8ad..0ada6942ad 100644
--- a/modules/noise/doc_classes/NoiseTexture3D.xml
+++ b/modules/noise/doc_classes/NoiseTexture3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NoiseTexture3D" inherits="Texture3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="NoiseTexture3D" inherits="Texture3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A texture filled with noise generated by a [Noise] object.
</brief_description>
diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp
index a7176e0816..1b0c5cb9e3 100644
--- a/modules/noise/noise_texture_2d.cpp
+++ b/modules/noise/noise_texture_2d.cpp
@@ -32,8 +32,6 @@
#include "noise.h"
-#include "core/core_string_names.h"
-
NoiseTexture2D::NoiseTexture2D() {
noise = Ref<Noise>();
@@ -223,11 +221,11 @@ void NoiseTexture2D::set_noise(Ref<Noise> p_noise) {
return;
}
if (noise.is_valid()) {
- noise->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update));
+ noise->disconnect_changed(callable_mp(this, &NoiseTexture2D::_queue_update));
}
noise = p_noise;
if (noise.is_valid()) {
- noise->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update));
+ noise->connect_changed(callable_mp(this, &NoiseTexture2D::_queue_update));
}
_queue_update();
}
@@ -347,11 +345,11 @@ void NoiseTexture2D::set_color_ramp(const Ref<Gradient> &p_gradient) {
return;
}
if (color_ramp.is_valid()) {
- color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update));
+ color_ramp->disconnect_changed(callable_mp(this, &NoiseTexture2D::_queue_update));
}
color_ramp = p_gradient;
if (color_ramp.is_valid()) {
- color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update));
+ color_ramp->connect_changed(callable_mp(this, &NoiseTexture2D::_queue_update));
}
_queue_update();
}
diff --git a/modules/noise/noise_texture_3d.cpp b/modules/noise/noise_texture_3d.cpp
index f6c67b0f2d..ed242e7faa 100644
--- a/modules/noise/noise_texture_3d.cpp
+++ b/modules/noise/noise_texture_3d.cpp
@@ -32,8 +32,6 @@
#include "noise.h"
-#include "core/core_string_names.h"
-
NoiseTexture3D::NoiseTexture3D() {
noise = Ref<Noise>();
@@ -214,11 +212,11 @@ void NoiseTexture3D::set_noise(Ref<Noise> p_noise) {
return;
}
if (noise.is_valid()) {
- noise->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture3D::_queue_update));
+ noise->disconnect_changed(callable_mp(this, &NoiseTexture3D::_queue_update));
}
noise = p_noise;
if (noise.is_valid()) {
- noise->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture3D::_queue_update));
+ noise->connect_changed(callable_mp(this, &NoiseTexture3D::_queue_update));
}
_queue_update();
}
@@ -297,11 +295,11 @@ void NoiseTexture3D::set_color_ramp(const Ref<Gradient> &p_gradient) {
return;
}
if (color_ramp.is_valid()) {
- color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture3D::_queue_update));
+ color_ramp->disconnect_changed(callable_mp(this, &NoiseTexture3D::_queue_update));
}
color_ramp = p_gradient;
if (color_ramp.is_valid()) {
- color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture3D::_queue_update));
+ color_ramp->connect_changed(callable_mp(this, &NoiseTexture3D::_queue_update));
}
_queue_update();
}
diff --git a/modules/noise/tests/test_noise_texture_2d.h b/modules/noise/tests/test_noise_texture_2d.h
index e2ec39ef48..938e8fd6ab 100644
--- a/modules/noise/tests/test_noise_texture_2d.h
+++ b/modules/noise/tests/test_noise_texture_2d.h
@@ -210,7 +210,7 @@ TEST_CASE("[NoiseTexture2D][SceneTree] Generating a basic noise texture with mip
noise_texture->set_generate_mipmaps(true);
Ref<NoiseTextureTester> tester = memnew(NoiseTextureTester(noise_texture.ptr()));
- noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTextureTester::check_mip_and_color_ramp));
+ noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTextureTester::check_mip_and_color_ramp));
MessageQueue::get_singleton()->flush();
}
@@ -227,7 +227,7 @@ TEST_CASE("[NoiseTexture2D][SceneTree] Generating a normal map without mipmaps")
noise_texture->set_generate_mipmaps(false);
Ref<NoiseTextureTester> tester = memnew(NoiseTextureTester(noise_texture.ptr()));
- noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTextureTester::check_normal_map));
+ noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTextureTester::check_normal_map));
MessageQueue::get_singleton()->flush();
}
@@ -245,7 +245,7 @@ TEST_CASE("[NoiseTexture2D][SceneTree] Generating a seamless noise texture") {
SUBCASE("Grayscale(L8) 16x16, with seamless blend skirt of 0.05") {
noise_texture->set_seamless_blend_skirt(0.05);
- noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTextureTester::check_seamless_texture_grayscale));
+ noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTextureTester::check_seamless_texture_grayscale));
MessageQueue::get_singleton()->flush();
}
@@ -257,7 +257,7 @@ TEST_CASE("[NoiseTexture2D][SceneTree] Generating a seamless noise texture") {
gradient->set_points(points);
noise_texture->set_color_ramp(gradient);
noise_texture->set_seamless_blend_skirt(1.0);
- noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTextureTester::check_seamless_texture_rgba));
+ noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTextureTester::check_seamless_texture_rgba));
MessageQueue::get_singleton()->flush();
}
}
diff --git a/modules/noise/tests/test_noise_texture_3d.h b/modules/noise/tests/test_noise_texture_3d.h
index a612f2920a..b708eac43b 100644
--- a/modules/noise/tests/test_noise_texture_3d.h
+++ b/modules/noise/tests/test_noise_texture_3d.h
@@ -194,7 +194,7 @@ TEST_CASE("[NoiseTexture3D][SceneTree] Generating a basic noise texture with mip
noise_texture->set_depth(16);
Ref<NoiseTexture3DTester> tester = memnew(NoiseTexture3DTester(noise_texture.ptr()));
- noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTexture3DTester::check_mip_and_color_ramp));
+ noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTexture3DTester::check_mip_and_color_ramp));
MessageQueue::get_singleton()->flush();
}
@@ -213,7 +213,7 @@ TEST_CASE("[NoiseTexture3D][SceneTree] Generating a seamless noise texture") {
SUBCASE("Grayscale(L8) 16x16x16, with seamless blend skirt of 0.05") {
noise_texture->set_seamless_blend_skirt(0.05);
- noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTexture3DTester::check_seamless_texture_grayscale));
+ noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTexture3DTester::check_seamless_texture_grayscale));
MessageQueue::get_singleton()->flush();
}
@@ -225,7 +225,7 @@ TEST_CASE("[NoiseTexture3D][SceneTree] Generating a seamless noise texture") {
gradient->set_points(points);
noise_texture->set_color_ramp(gradient);
noise_texture->set_seamless_blend_skirt(1.0);
- noise_texture->connect("changed", callable_mp(tester.ptr(), &NoiseTexture3DTester::check_seamless_texture_rgba));
+ noise_texture->connect_changed(callable_mp(tester.ptr(), &NoiseTexture3DTester::check_seamless_texture_rgba));
MessageQueue::get_singleton()->flush();
}
}
diff --git a/modules/ogg/doc_classes/OggPacketSequence.xml b/modules/ogg/doc_classes/OggPacketSequence.xml
index 2f10bedf69..75dcf5a29f 100644
--- a/modules/ogg/doc_classes/OggPacketSequence.xml
+++ b/modules/ogg/doc_classes/OggPacketSequence.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OggPacketSequence" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OggPacketSequence" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A sequence of Ogg packets.
</brief_description>
diff --git a/modules/ogg/doc_classes/OggPacketSequencePlayback.xml b/modules/ogg/doc_classes/OggPacketSequencePlayback.xml
index 338de2d6da..e363e67ee4 100644
--- a/modules/ogg/doc_classes/OggPacketSequencePlayback.xml
+++ b/modules/ogg/doc_classes/OggPacketSequencePlayback.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OggPacketSequencePlayback" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OggPacketSequencePlayback" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 0dd41675b6..f49dc390de 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -5,22 +5,13 @@ Import("env_modules")
env_openxr = env_modules.Clone()
-#################################################
-# Add in our Khronos OpenXR loader
+# Thirdparty source files
thirdparty_obj = []
-thirdparty_dir = "#thirdparty/openxr"
-
-env_openxr.Prepend(
- CPPPATH=[
- thirdparty_dir,
- thirdparty_dir + "/include",
- thirdparty_dir + "/src",
- thirdparty_dir + "/src/common",
- thirdparty_dir + "/src/external/jsoncpp/include",
- ]
-)
+# Khronos OpenXR loader
+
+# Needs even for build against shared library, at least the defines used in public headers.
if env["platform"] == "android":
# may need to set OPENXR_ANDROID_VERSION_SUFFIX
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"])
@@ -37,47 +28,66 @@ elif env["platform"] == "linuxbsd":
env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
elif env["platform"] == "windows":
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"])
+elif env["platform"] == "macos":
+ env_openxr.AppendUnique(CPPDEFINES=["XR_OS_APPLE"])
-# may need to check and set:
-# - XR_USE_TIMESPEC
-
-env_thirdparty = env_openxr.Clone()
-env_thirdparty.disable_warnings()
-env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"])
-
-if "-fno-exceptions" in env_thirdparty["CXXFLAGS"]:
- env_thirdparty["CXXFLAGS"].remove("-fno-exceptions")
-env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"])
+ # There does not seem to be a XR_USE_PLATFORM_XYZ for Apple
-# add in external jsoncpp dependency
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_reader.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_value.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_writer.cpp")
-# add in load
-if env["platform"] != "android":
- # On Android the openxr_loader is provided by separate plugins for each device
- # Build the engine using object files
- khrloader_obj = []
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c")
-
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp")
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/object_info.cpp")
-
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp")
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_core.cpp")
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_instance.cpp")
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp")
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger.cpp")
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/manifest_file.cpp")
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp")
- env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp")
- env.modules_sources += khrloader_obj
-
-env.modules_sources += thirdparty_obj
+# may need to check and set:
+# - XR_USE_TIMESPEC
-#################################################
-# And include our module source
+if env["builtin_openxr"]:
+ thirdparty_dir = "#thirdparty/openxr"
+
+ env_openxr.Prepend(
+ CPPPATH=[
+ thirdparty_dir,
+ thirdparty_dir + "/include",
+ thirdparty_dir + "/src",
+ thirdparty_dir + "/src/common",
+ thirdparty_dir + "/src/external/jsoncpp/include",
+ ]
+ )
+
+ env_thirdparty = env_openxr.Clone()
+ env_thirdparty.disable_warnings()
+ env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"])
+
+ if "-fno-exceptions" in env_thirdparty["CXXFLAGS"]:
+ env_thirdparty["CXXFLAGS"].remove("-fno-exceptions")
+ env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"])
+
+ # add in external jsoncpp dependency
+ thirdparty_jsoncpp_dir = thirdparty_dir + "/src/external/jsoncpp/src/lib_json/"
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_reader.cpp")
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_value.cpp")
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_writer.cpp")
+
+ # add in load
+ if env["platform"] != "android":
+ # On Android the openxr_loader is provided by separate plugins for each device
+ # Build the engine using object files
+ khrloader_obj = []
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c")
+
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/object_info.cpp")
+
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_core.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_instance.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/manifest_file.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp")
+ env.modules_sources += khrloader_obj
+
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
module_obj = []
@@ -90,7 +100,7 @@ if env["platform"] == "android":
env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp")
if env["vulkan"]:
env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp")
-if env["opengl3"]:
+if env["opengl3"] and env["platform"] != "macos":
env_openxr.add_source_files(module_obj, "extensions/openxr_opengl_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp")
@@ -104,6 +114,8 @@ env_openxr.add_source_files(module_obj, "extensions/openxr_fb_display_refresh_ra
env_openxr.add_source_files(module_obj, "extensions/openxr_pico_controller_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_wmr_controller_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_ml2_controller_extension.cpp")
+env_openxr.add_source_files(module_obj, "extensions/openxr_extension_wrapper_extension.cpp")
+env_openxr.add_source_files(module_obj, "extensions/openxr_api_extension.cpp")
env.modules_sources += module_obj
diff --git a/modules/openxr/config.py b/modules/openxr/config.py
index e503f12739..8ed06a1606 100644
--- a/modules/openxr/config.py
+++ b/modules/openxr/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- if platform in ("linuxbsd", "windows", "android"):
+ if platform in ("linuxbsd", "windows", "android", "macos"):
return env["openxr"] and not env["disable_3d"]
else:
# not supported on these platforms
diff --git a/modules/openxr/doc_classes/OpenXRAction.xml b/modules/openxr/doc_classes/OpenXRAction.xml
index 2696be2465..6a3529e43e 100644
--- a/modules/openxr/doc_classes/OpenXRAction.xml
+++ b/modules/openxr/doc_classes/OpenXRAction.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenXRAction" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OpenXRAction" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
An OpenXR action.
</brief_description>
diff --git a/modules/openxr/doc_classes/OpenXRActionMap.xml b/modules/openxr/doc_classes/OpenXRActionMap.xml
index 64cd5ca494..b8711635e4 100644
--- a/modules/openxr/doc_classes/OpenXRActionMap.xml
+++ b/modules/openxr/doc_classes/OpenXRActionMap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenXRActionMap" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OpenXRActionMap" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Collection of [OpenXRActionSet] and [OpenXRInteractionProfile] resources for the OpenXR module.
</brief_description>
diff --git a/modules/openxr/doc_classes/OpenXRActionSet.xml b/modules/openxr/doc_classes/OpenXRActionSet.xml
index 92e6f91e32..03dc33d743 100644
--- a/modules/openxr/doc_classes/OpenXRActionSet.xml
+++ b/modules/openxr/doc_classes/OpenXRActionSet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenXRActionSet" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OpenXRActionSet" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Collection of [OpenXRAction] resources that make up an action set.
</brief_description>
diff --git a/modules/openxr/doc_classes/OpenXRHand.xml b/modules/openxr/doc_classes/OpenXRHand.xml
index 6e258a468d..cc7766507f 100644
--- a/modules/openxr/doc_classes/OpenXRHand.xml
+++ b/modules/openxr/doc_classes/OpenXRHand.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenXRHand" inherits="Node3D" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OpenXRHand" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Node supporting finger tracking in OpenXR.
</brief_description>
diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml
index f3b14b3179..f274f0868e 100644
--- a/modules/openxr/doc_classes/OpenXRIPBinding.xml
+++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenXRIPBinding" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OpenXRIPBinding" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Defines a binding between an [OpenXRAction] and an XR input or output.
</brief_description>
diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
index 8c55a3360b..a69bb875fa 100644
--- a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
+++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenXRInteractionProfile" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OpenXRInteractionProfile" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Suggested bindings object for OpenXR.
</brief_description>
diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml
index b6d52464c0..f0ca649fe4 100644
--- a/modules/openxr/doc_classes/OpenXRInterface.xml
+++ b/modules/openxr/doc_classes/OpenXRInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenXRInterface" inherits="XRInterface" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OpenXRInterface" inherits="XRInterface" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Our OpenXR interface.
</brief_description>
diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp
index 98687d5f20..c6082ca404 100644
--- a/modules/openxr/extensions/openxr_android_extension.cpp
+++ b/modules/openxr/extensions/openxr_android_extension.cpp
@@ -53,6 +53,7 @@ OpenXRAndroidExtension::OpenXRAndroidExtension() {
HashMap<String, bool *> OpenXRAndroidExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
+ request_extensions[XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME] = &loader_init_extension_available;
request_extensions[XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME] = &create_instance_extension_available;
return request_extensions;
diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h
index 920bfe74b7..31f8d23268 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper.h
@@ -36,8 +36,6 @@
#include "core/templates/hash_map.h"
#include "core/templates/rid.h"
-#include "thirdparty/openxr/src/common/xr_linear.h"
-
#include <openxr/openxr.h>
class OpenXRAPI;
diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp
new file mode 100644
index 0000000000..81ba9c56b8
--- /dev/null
+++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp
@@ -0,0 +1,207 @@
+/**************************************************************************/
+/* openxr_extension_wrapper_extension.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 "openxr_extension_wrapper_extension.h"
+
+#include "../openxr_api.h"
+
+void OpenXRExtensionWrapperExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_requested_extensions);
+ GDVIRTUAL_BIND(_set_system_properties_and_get_next_pointer, "next_pointer");
+ GDVIRTUAL_BIND(_set_instance_create_info_and_get_next_pointer, "next_pointer");
+ GDVIRTUAL_BIND(_set_session_create_and_get_next_pointer, "next_pointer");
+ GDVIRTUAL_BIND(_set_swapchain_create_info_and_get_next_pointer, "next_pointer");
+ GDVIRTUAL_BIND(_on_register_metadata);
+ GDVIRTUAL_BIND(_on_before_instance_created);
+ GDVIRTUAL_BIND(_on_instance_created, "instance");
+ GDVIRTUAL_BIND(_on_instance_destroyed);
+ GDVIRTUAL_BIND(_on_session_created, "session");
+ GDVIRTUAL_BIND(_on_process);
+ GDVIRTUAL_BIND(_on_pre_render);
+ GDVIRTUAL_BIND(_on_session_destroyed);
+ GDVIRTUAL_BIND(_on_state_idle);
+ GDVIRTUAL_BIND(_on_state_ready);
+ GDVIRTUAL_BIND(_on_state_synchronized);
+ GDVIRTUAL_BIND(_on_state_visible);
+ GDVIRTUAL_BIND(_on_state_focused);
+ GDVIRTUAL_BIND(_on_state_stopping);
+ GDVIRTUAL_BIND(_on_state_loss_pending);
+ GDVIRTUAL_BIND(_on_state_exiting);
+ GDVIRTUAL_BIND(_on_event_polled, "event");
+
+ ClassDB::bind_method(D_METHOD("get_openxr_api"), &OpenXRExtensionWrapperExtension::get_openxr_api);
+ ClassDB::bind_method(D_METHOD("register_extension_wrapper"), &OpenXRExtensionWrapperExtension::register_extension_wrapper);
+}
+
+HashMap<String, bool *> OpenXRExtensionWrapperExtension::get_requested_extensions() {
+ Dictionary request_extension;
+
+ if (GDVIRTUAL_CALL(_get_requested_extensions, request_extension)) {
+ HashMap<String, bool *> result;
+ Array keys = request_extension.keys();
+ for (int i = 0; i < keys.size(); i++) {
+ String key = keys.get(i);
+ GDExtensionPtr<bool> value = VariantCaster<GDExtensionPtr<bool>>::cast(request_extension.get(key, GDExtensionPtr<bool>(nullptr)));
+ result.insert(key, value);
+ }
+ return result;
+ }
+
+ return HashMap<String, bool *>();
+}
+
+void *OpenXRExtensionWrapperExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) {
+ uint64_t pointer;
+
+ if (GDVIRTUAL_CALL(_set_system_properties_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
+ return reinterpret_cast<void *>(pointer);
+ }
+
+ return nullptr;
+}
+
+void *OpenXRExtensionWrapperExtension::set_instance_create_info_and_get_next_pointer(void *p_next_pointer) {
+ uint64_t pointer;
+
+ if (GDVIRTUAL_CALL(_set_instance_create_info_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
+ return reinterpret_cast<void *>(pointer);
+ }
+
+ return nullptr;
+}
+
+void *OpenXRExtensionWrapperExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {
+ uint64_t pointer;
+
+ if (GDVIRTUAL_CALL(_set_session_create_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
+ return reinterpret_cast<void *>(pointer);
+ }
+
+ return nullptr;
+}
+
+void *OpenXRExtensionWrapperExtension::set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) {
+ uint64_t pointer;
+
+ if (GDVIRTUAL_CALL(_set_swapchain_create_info_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
+ return reinterpret_cast<void *>(pointer);
+ }
+
+ return nullptr;
+}
+
+void OpenXRExtensionWrapperExtension::on_register_metadata() {
+ GDVIRTUAL_CALL(_on_register_metadata);
+}
+
+void OpenXRExtensionWrapperExtension::on_before_instance_created() {
+ GDVIRTUAL_CALL(_on_before_instance_created);
+}
+
+void OpenXRExtensionWrapperExtension::on_instance_created(const XrInstance p_instance) {
+ uint64_t instance = reinterpret_cast<uint64_t>(p_instance);
+ GDVIRTUAL_CALL(_on_instance_created, instance);
+}
+
+void OpenXRExtensionWrapperExtension::on_instance_destroyed() {
+ GDVIRTUAL_CALL(_on_instance_destroyed);
+}
+
+void OpenXRExtensionWrapperExtension::on_session_created(const XrSession p_session) {
+ uint64_t session = reinterpret_cast<uint64_t>(p_session);
+ GDVIRTUAL_CALL(_on_session_created, session);
+}
+
+void OpenXRExtensionWrapperExtension::on_process() {
+ GDVIRTUAL_CALL(_on_process);
+}
+
+void OpenXRExtensionWrapperExtension::on_pre_render() {
+ GDVIRTUAL_CALL(_on_pre_render);
+}
+
+void OpenXRExtensionWrapperExtension::on_session_destroyed() {
+ GDVIRTUAL_CALL(_on_session_destroyed);
+}
+
+void OpenXRExtensionWrapperExtension::on_state_idle() {
+ GDVIRTUAL_CALL(_on_state_idle);
+}
+
+void OpenXRExtensionWrapperExtension::on_state_ready() {
+ GDVIRTUAL_CALL(_on_state_ready);
+}
+
+void OpenXRExtensionWrapperExtension::on_state_synchronized() {
+ GDVIRTUAL_CALL(_on_state_synchronized);
+}
+
+void OpenXRExtensionWrapperExtension::on_state_visible() {
+ GDVIRTUAL_CALL(_on_state_visible);
+}
+
+void OpenXRExtensionWrapperExtension::on_state_focused() {
+ GDVIRTUAL_CALL(_on_state_focused);
+}
+
+void OpenXRExtensionWrapperExtension::on_state_stopping() {
+ GDVIRTUAL_CALL(_on_state_stopping);
+}
+
+void OpenXRExtensionWrapperExtension::on_state_loss_pending() {
+ GDVIRTUAL_CALL(_on_state_loss_pending);
+}
+
+void OpenXRExtensionWrapperExtension::on_state_exiting() {
+ GDVIRTUAL_CALL(_on_state_exiting);
+}
+
+bool OpenXRExtensionWrapperExtension::on_event_polled(const XrEventDataBuffer &p_event) {
+ bool event_polled;
+
+ if (GDVIRTUAL_CALL(_on_event_polled, GDExtensionConstPtr<void>(&p_event), event_polled)) {
+ return event_polled;
+ }
+
+ return false;
+}
+
+Ref<OpenXRAPIExtension> OpenXRExtensionWrapperExtension::get_openxr_api() {
+ return openxr_api;
+}
+
+void OpenXRExtensionWrapperExtension::register_extension_wrapper() {
+ OpenXRAPI::register_extension_wrapper(this);
+}
+
+OpenXRExtensionWrapperExtension::OpenXRExtensionWrapperExtension() :
+ Object(), OpenXRExtensionWrapper() {
+ openxr_api.instantiate();
+}
diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.h b/modules/openxr/extensions/openxr_extension_wrapper_extension.h
new file mode 100644
index 0000000000..5c5e64f927
--- /dev/null
+++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.h
@@ -0,0 +1,115 @@
+/**************************************************************************/
+/* openxr_extension_wrapper_extension.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 OPENXR_EXTENSION_WRAPPER_EXTENSION_H
+#define OPENXR_EXTENSION_WRAPPER_EXTENSION_H
+
+#include "../openxr_api_extension.h"
+#include "openxr_extension_wrapper.h"
+
+#include "core/object/ref_counted.h"
+#include "core/os/os.h"
+#include "core/os/thread_safe.h"
+#include "core/variant/native_ptr.h"
+
+class OpenXRExtensionWrapperExtension : public Object, OpenXRExtensionWrapper {
+ GDCLASS(OpenXRExtensionWrapperExtension, Object);
+
+protected:
+ _THREAD_SAFE_CLASS_
+
+ static void _bind_methods();
+
+ Ref<OpenXRAPIExtension> openxr_api;
+
+public:
+ virtual HashMap<String, bool *> get_requested_extensions() override;
+
+ GDVIRTUAL0R(Dictionary, _get_requested_extensions);
+
+ virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) override;
+ virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) override;
+ virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
+ virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override;
+
+ //TODO workaround as GDExtensionPtr<void> return type results in build error in godot-cpp
+ GDVIRTUAL1R(uint64_t, _set_system_properties_and_get_next_pointer, GDExtensionPtr<void>);
+ GDVIRTUAL1R(uint64_t, _set_instance_create_info_and_get_next_pointer, GDExtensionPtr<void>);
+ GDVIRTUAL1R(uint64_t, _set_session_create_and_get_next_pointer, GDExtensionPtr<void>);
+ GDVIRTUAL1R(uint64_t, _set_swapchain_create_info_and_get_next_pointer, GDExtensionPtr<void>);
+
+ virtual void on_register_metadata() override;
+ virtual void on_before_instance_created() override;
+ virtual void on_instance_created(const XrInstance p_instance) override;
+ virtual void on_instance_destroyed() override;
+ virtual void on_session_created(const XrSession p_session) override;
+ virtual void on_process() override;
+ virtual void on_pre_render() override;
+ virtual void on_session_destroyed() override;
+
+ GDVIRTUAL0(_on_register_metadata);
+ GDVIRTUAL0(_on_before_instance_created);
+ GDVIRTUAL1(_on_instance_created, uint64_t);
+ GDVIRTUAL0(_on_instance_destroyed);
+ GDVIRTUAL1(_on_session_created, uint64_t);
+ GDVIRTUAL0(_on_process);
+ GDVIRTUAL0(_on_pre_render);
+ GDVIRTUAL0(_on_session_destroyed);
+
+ virtual void on_state_idle() override;
+ virtual void on_state_ready() override;
+ virtual void on_state_synchronized() override;
+ virtual void on_state_visible() override;
+ virtual void on_state_focused() override;
+ virtual void on_state_stopping() override;
+ virtual void on_state_loss_pending() override;
+ virtual void on_state_exiting() override;
+
+ GDVIRTUAL0(_on_state_idle);
+ GDVIRTUAL0(_on_state_ready);
+ GDVIRTUAL0(_on_state_synchronized);
+ GDVIRTUAL0(_on_state_visible);
+ GDVIRTUAL0(_on_state_focused);
+ GDVIRTUAL0(_on_state_stopping);
+ GDVIRTUAL0(_on_state_loss_pending);
+ GDVIRTUAL0(_on_state_exiting);
+
+ virtual bool on_event_polled(const XrEventDataBuffer &p_event) override;
+
+ GDVIRTUAL1R(bool, _on_event_polled, GDExtensionConstPtr<void>);
+
+ Ref<OpenXRAPIExtension> get_openxr_api();
+
+ void register_extension_wrapper();
+
+ OpenXRExtensionWrapperExtension();
+};
+
+#endif // OPENXR_EXTENSION_WRAPPER_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
index 6fffa1ed07..65559afed0 100644
--- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
+++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
@@ -134,6 +134,10 @@ void OpenXRHandTrackingExtension::on_process() {
// process our hands
const XrTime time = OpenXRAPI::get_singleton()->get_next_frame_time(); // This data will be used for the next frame we render
+ if (time == 0) {
+ // we don't have timing info yet, or we're skipping a frame...
+ return;
+ }
XrResult result;
diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp
index 39b5c61e8e..9038e9f458 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.cpp
+++ b/modules/openxr/extensions/openxr_opengl_extension.cpp
@@ -278,8 +278,8 @@ bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
}
bool OpenXROpenGLExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) {
- XrMatrix4x4f matrix;
- XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far);
+ OpenXRUtil::XrMatrix4x4f matrix;
+ OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(&matrix, OpenXRUtil::GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far);
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 4; i++) {
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp
index 2902c16baf..9429d9e082 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.cpp
+++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp
@@ -381,8 +381,8 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
bool OpenXRVulkanExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) {
// Even though this is a Vulkan renderer we're using OpenGL coordinate systems
- XrMatrix4x4f matrix;
- XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far);
+ OpenXRUtil::XrMatrix4x4f matrix;
+ OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(&matrix, OpenXRUtil::GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far);
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 4; i++) {
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 4ab280f3c3..91684b55b9 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -30,6 +30,7 @@
#include "openxr_api.h"
+#include "extensions/openxr_extension_wrapper_extension.h"
#include "openxr_interface.h"
#include "openxr_util.h"
@@ -47,7 +48,7 @@
#ifdef VULKAN_ENABLED
#define XR_USE_GRAPHICS_API_VULKAN
#endif
-#ifdef GLES3_ENABLED
+#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
#ifdef ANDROID_ENABLED
#define XR_USE_GRAPHICS_API_OPENGL_ES
#include <EGL/egl.h>
@@ -72,7 +73,7 @@
#include "extensions/openxr_vulkan_extension.h"
#endif
-#ifdef GLES3_ENABLED
+#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
#include "extensions/openxr_opengl_extension.h"
#endif
@@ -1306,7 +1307,7 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) {
ERR_FAIL_V(false);
#endif
} else if (p_rendering_driver == "opengl3") {
-#ifdef GLES3_ENABLED
+#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
graphics_extension = memnew(OpenXROpenGLExtension);
register_extension_wrapper(graphics_extension);
#else
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 96af2bfc49..9374cb7afa 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -48,8 +48,6 @@
#include "core/templates/vector.h"
#include "servers/xr/xr_pose.h"
-#include "thirdparty/openxr/src/common/xr_linear.h"
-
#include <openxr/openxr.h>
// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initializing structs which ensures zeroing out unspecified members.
diff --git a/modules/openxr/openxr_api_extension.cpp b/modules/openxr/openxr_api_extension.cpp
new file mode 100644
index 0000000000..f0f0835f78
--- /dev/null
+++ b/modules/openxr/openxr_api_extension.cpp
@@ -0,0 +1,130 @@
+/**************************************************************************/
+/* openxr_api_extension.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 "openxr_api_extension.h"
+
+void OpenXRAPIExtension::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_instance"), &OpenXRAPIExtension::get_instance);
+ ClassDB::bind_method(D_METHOD("get_system_id"), &OpenXRAPIExtension::get_system_id);
+ ClassDB::bind_method(D_METHOD("get_session"), &OpenXRAPIExtension::get_session);
+
+ ClassDB::bind_method(D_METHOD("transform_from_pose", "pose"), &OpenXRAPIExtension::transform_from_pose);
+ ClassDB::bind_method(D_METHOD("xr_result", "result", "format", "args"), &OpenXRAPIExtension::xr_result);
+ ClassDB::bind_static_method("OpenXRAPIExtension", D_METHOD("openxr_is_enabled", "check_run_in_editor"), &OpenXRAPIExtension::openxr_is_enabled);
+ ClassDB::bind_method(D_METHOD("get_instance_proc_addr", "name"), &OpenXRAPIExtension::get_instance_proc_addr);
+ ClassDB::bind_method(D_METHOD("get_error_string", "result"), &OpenXRAPIExtension::get_error_string);
+ ClassDB::bind_method(D_METHOD("get_swapchain_format_name", "swapchain_format"), &OpenXRAPIExtension::get_swapchain_format_name);
+
+ ClassDB::bind_method(D_METHOD("is_initialized"), &OpenXRAPIExtension::is_initialized);
+ ClassDB::bind_method(D_METHOD("is_running"), &OpenXRAPIExtension::is_running);
+
+ ClassDB::bind_method(D_METHOD("get_play_space"), &OpenXRAPIExtension::get_play_space);
+ ClassDB::bind_method(D_METHOD("get_next_frame_time"), &OpenXRAPIExtension::get_next_frame_time);
+ ClassDB::bind_method(D_METHOD("can_render"), &OpenXRAPIExtension::can_render);
+}
+
+uint64_t OpenXRAPIExtension::get_instance() {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
+ return (uint64_t)OpenXRAPI::get_singleton()->get_instance();
+}
+
+uint64_t OpenXRAPIExtension::get_system_id() {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
+ return (uint64_t)OpenXRAPI::get_singleton()->get_system_id();
+}
+
+uint64_t OpenXRAPIExtension::get_session() {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
+ return (uint64_t)OpenXRAPI::get_singleton()->get_session();
+}
+
+Transform3D OpenXRAPIExtension::transform_from_pose(GDExtensionConstPtr<const void> p_pose) {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), Transform3D());
+ return OpenXRAPI::get_singleton()->transform_from_pose(*(XrPosef *)p_pose.data);
+}
+
+bool OpenXRAPIExtension::xr_result(uint64_t result, String format, Array args) {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false);
+ return OpenXRAPI::get_singleton()->xr_result((XrResult)result, format.utf8().get_data(), args);
+}
+
+bool OpenXRAPIExtension::openxr_is_enabled(bool p_check_run_in_editor) {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false);
+ return OpenXRAPI::openxr_is_enabled(p_check_run_in_editor);
+}
+
+uint64_t OpenXRAPIExtension::get_instance_proc_addr(String p_name) {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
+ CharString str = p_name.utf8();
+ PFN_xrVoidFunction addr = nullptr;
+ XrResult result = OpenXRAPI::get_singleton()->get_instance_proc_addr(str.get_data(), &addr);
+ if (result != XR_SUCCESS) {
+ return 0;
+ }
+ return reinterpret_cast<uint64_t>(addr);
+}
+
+String OpenXRAPIExtension::get_error_string(uint64_t result) {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), String());
+ return OpenXRAPI::get_singleton()->get_error_string((XrResult)result);
+}
+
+String OpenXRAPIExtension::get_swapchain_format_name(int64_t p_swapchain_format) {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), String());
+ return OpenXRAPI::get_singleton()->get_swapchain_format_name(p_swapchain_format);
+}
+
+bool OpenXRAPIExtension::is_initialized() {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false);
+ return OpenXRAPI::get_singleton()->is_initialized();
+}
+
+bool OpenXRAPIExtension::is_running() {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false);
+ return OpenXRAPI::get_singleton()->is_running();
+}
+
+uint64_t OpenXRAPIExtension::get_play_space() {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
+ return (uint64_t)OpenXRAPI::get_singleton()->get_play_space();
+}
+
+int64_t OpenXRAPIExtension::get_next_frame_time() {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
+ return (XrTime)OpenXRAPI::get_singleton()->get_next_frame_time();
+}
+
+bool OpenXRAPIExtension::can_render() {
+ ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false);
+ return OpenXRAPI::get_singleton()->can_render();
+}
+
+OpenXRAPIExtension::OpenXRAPIExtension() {
+}
diff --git a/core/os/threaded_array_processor.h b/modules/openxr/openxr_api_extension.h
index 34b417ae57..98f87c7aa1 100644
--- a/core/os/threaded_array_processor.h
+++ b/modules/openxr/openxr_api_extension.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* threaded_array_processor.h */
+/* openxr_api_extension.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,60 +28,49 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef THREADED_ARRAY_PROCESSOR_H
-#define THREADED_ARRAY_PROCESSOR_H
+#ifndef OPENXR_API_EXTENSION_H
+#define OPENXR_API_EXTENSION_H
+#include "openxr_api.h"
+
+#include "core/object/ref_counted.h"
#include "core/os/os.h"
-#include "core/os/thread.h"
#include "core/os/thread_safe.h"
-#include "core/templates/safe_refcount.h"
+#include "core/variant/native_ptr.h"
-template <class C, class U>
-struct ThreadArrayProcessData {
- uint32_t elements;
- SafeNumeric<uint32_t> index;
- C *instance;
- U userdata;
- void (C::*method)(uint32_t, U);
+class OpenXRAPIExtension : public RefCounted {
+ GDCLASS(OpenXRAPIExtension, RefCounted);
- void process(uint32_t p_index) {
- (instance->*method)(p_index, userdata);
- }
-};
+protected:
+ _THREAD_SAFE_CLASS_
+
+ static void _bind_methods();
+
+public:
+ uint64_t get_instance();
+ uint64_t get_system_id();
+ uint64_t get_session();
-template <class T>
-void process_array_thread(void *ud) {
- T &data = *(T *)ud;
- while (true) {
- uint32_t index = data.index.increment();
- if (index >= data.elements) {
- break;
- }
- data.process(index);
- }
-}
+ // Helper method to convert an XrPosef to a Transform3D.
+ Transform3D transform_from_pose(GDExtensionConstPtr<const void> p_pose);
-template <class C, class M, class U>
-void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
- ThreadArrayProcessData<C, U> data;
- data.method = p_method;
- data.instance = p_instance;
- data.userdata = p_userdata;
- data.index.set(0);
- data.elements = p_elements;
- data.process(0); //process first, let threads increment for next
+ bool xr_result(uint64_t result, String format, Array args = Array());
- int thread_count = OS::get_singleton()->get_processor_count();
- Thread *threads = memnew_arr(Thread, thread_count);
+ static bool openxr_is_enabled(bool p_check_run_in_editor = true);
- for (int i = 0; i < thread_count; i++) {
- threads[i].start(process_array_thread<ThreadArrayProcessData<C, U>>, &data);
- }
+ //TODO workaround as GDExtensionPtr<void> return type results in build error in godot-cpp
+ uint64_t get_instance_proc_addr(String p_name);
+ String get_error_string(uint64_t result);
+ String get_swapchain_format_name(int64_t p_swapchain_format);
- for (int i = 0; i < thread_count; i++) {
- threads[i].wait_to_finish();
- }
- memdelete_arr(threads);
-}
+ bool is_initialized();
+ bool is_running();
+
+ uint64_t get_play_space();
+ int64_t get_next_frame_time();
+ bool can_render();
+
+ OpenXRAPIExtension();
+};
-#endif // THREADED_ARRAY_PROCESSOR_H
+#endif // OPENXR_API_EXTENSION_H
diff --git a/modules/openxr/openxr_util.cpp b/modules/openxr/openxr_util.cpp
index 0c5cdd7113..1d44233337 100644
--- a/modules/openxr/openxr_util.cpp
+++ b/modules/openxr/openxr_util.cpp
@@ -32,6 +32,8 @@
#include <openxr/openxr_reflection.h>
+#include <math.h>
+
#define XR_ENUM_CASE_STR(name, val) \
case name: \
return #name;
@@ -75,3 +77,89 @@ String OpenXRUtil::make_xr_version_string(XrVersion p_version) {
return version;
}
+
+// Copied from OpenXR xr_linear.h private header, so we can still link against
+// system-provided packages without relying on our `thirdparty` code.
+
+// Copyright (c) 2017 The Khronos Group Inc.
+// Copyright (c) 2016 Oculus VR, LLC.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+// Creates a projection matrix based on the specified dimensions.
+// The projection matrix transforms -Z=forward, +Y=up, +X=right to the appropriate clip space for the graphics API.
+// The far plane is placed at infinity if farZ <= nearZ.
+// An infinite projection matrix is preferred for rasterization because, except for
+// things *right* up against the near plane, it always provides better precision:
+// "Tightening the Precision of Perspective Rendering"
+// Paul Upchurch, Mathieu Desbrun
+// Journal of Graphics Tools, Volume 16, Issue 1, 2012
+void OpenXRUtil::XrMatrix4x4f_CreateProjection(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const float tanAngleLeft,
+ const float tanAngleRight, const float tanAngleUp, float const tanAngleDown,
+ const float nearZ, const float farZ) {
+ const float tanAngleWidth = tanAngleRight - tanAngleLeft;
+
+ // Set to tanAngleDown - tanAngleUp for a clip space with positive Y down (Vulkan).
+ // Set to tanAngleUp - tanAngleDown for a clip space with positive Y up (OpenGL / D3D / Metal).
+ const float tanAngleHeight = graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown);
+
+ // Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES).
+ // Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal).
+ const float offsetZ = (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0;
+
+ if (farZ <= nearZ) {
+ // place the far plane at infinity
+ result->m[0] = 2.0f / tanAngleWidth;
+ result->m[4] = 0.0f;
+ result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
+ result->m[12] = 0.0f;
+
+ result->m[1] = 0.0f;
+ result->m[5] = 2.0f / tanAngleHeight;
+ result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
+ result->m[13] = 0.0f;
+
+ result->m[2] = 0.0f;
+ result->m[6] = 0.0f;
+ result->m[10] = -1.0f;
+ result->m[14] = -(nearZ + offsetZ);
+
+ result->m[3] = 0.0f;
+ result->m[7] = 0.0f;
+ result->m[11] = -1.0f;
+ result->m[15] = 0.0f;
+ } else {
+ // normal projection
+ result->m[0] = 2.0f / tanAngleWidth;
+ result->m[4] = 0.0f;
+ result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
+ result->m[12] = 0.0f;
+
+ result->m[1] = 0.0f;
+ result->m[5] = 2.0f / tanAngleHeight;
+ result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
+ result->m[13] = 0.0f;
+
+ result->m[2] = 0.0f;
+ result->m[6] = 0.0f;
+ result->m[10] = -(farZ + offsetZ) / (farZ - nearZ);
+ result->m[14] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ);
+
+ result->m[3] = 0.0f;
+ result->m[7] = 0.0f;
+ result->m[11] = -1.0f;
+ result->m[15] = 0.0f;
+ }
+}
+
+// Creates a projection matrix based on the specified FOV.
+void OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const XrFovf fov,
+ const float nearZ, const float farZ) {
+ const float tanLeft = tanf(fov.angleLeft);
+ const float tanRight = tanf(fov.angleRight);
+
+ const float tanDown = tanf(fov.angleDown);
+ const float tanUp = tanf(fov.angleUp);
+
+ XrMatrix4x4f_CreateProjection(result, graphicsApi, tanLeft, tanRight, tanUp, tanDown, nearZ, farZ);
+}
diff --git a/modules/openxr/openxr_util.h b/modules/openxr/openxr_util.h
index 8ad68c0b02..3f36ab9fca 100644
--- a/modules/openxr/openxr_util.h
+++ b/modules/openxr/openxr_util.h
@@ -44,6 +44,27 @@ public:
static String get_action_type_name(XrActionType p_action_type);
static String get_environment_blend_mode_name(XrEnvironmentBlendMode p_blend_mode);
static String make_xr_version_string(XrVersion p_version);
+
+ // Copied from OpenXR xr_linear.h private header, so we can still link against
+ // system-provided packages without relying on our `thirdparty` code.
+
+ // Column-major, pre-multiplied. This type does not exist in the OpenXR API and is provided for convenience.
+ typedef struct XrMatrix4x4f {
+ float m[16];
+ } XrMatrix4x4f;
+
+ typedef enum GraphicsAPI {
+ GRAPHICS_VULKAN,
+ GRAPHICS_OPENGL,
+ GRAPHICS_OPENGL_ES,
+ GRAPHICS_D3D
+ } GraphicsAPI;
+
+ static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const float tanAngleLeft,
+ const float tanAngleRight, const float tanAngleUp, float const tanAngleDown,
+ const float nearZ, const float farZ);
+ static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const XrFovf fov,
+ const float nearZ, const float farZ);
};
#endif // OPENXR_UTIL_H
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 27b179a788..5d636c2b70 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -36,6 +36,9 @@
#include "action_map/openxr_interaction_profile.h"
#include "action_map/openxr_interaction_profile_meta_data.h"
#include "openxr_interface.h"
+
+#include "extensions/openxr_extension_wrapper_extension.h"
+
#include "scene/openxr_hand.h"
#include "extensions/openxr_composition_layer_depth_extension.h"
@@ -87,6 +90,11 @@ static void _editor_init() {
#endif
void initialize_openxr_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_CORE) {
+ GDREGISTER_CLASS(OpenXRExtensionWrapperExtension);
+ GDREGISTER_CLASS(OpenXRAPIExtension);
+ }
+
if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
if (OpenXRAPI::openxr_is_enabled(false)) {
// Always register our extension wrappers even if we don't initialize OpenXR.
diff --git a/modules/openxr/util.h b/modules/openxr/util.h
index 6665d45007..d95bc3bb8e 100644
--- a/modules/openxr/util.h
+++ b/modules/openxr/util.h
@@ -58,6 +58,17 @@
#define EXT_TRY_INIT_XR_FUNC(name) TRY_INIT_XR_FUNC(OpenXRAPI::get_singleton(), name)
#define OPENXR_TRY_API_INIT_XR_FUNC(name) TRY_INIT_XR_FUNC(this, name)
+#define GDEXTENSION_INIT_XR_FUNC(name) \
+ do { \
+ name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \
+ ERR_FAIL_COND(name##_ptr == nullptr); \
+ } while (0)
+
+#define GDEXTENSION_INIT_XR_FUNC_V(name) \
+ do { \
+ name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \
+ ERR_FAIL_COND_V(name##_ptr == nullptr, false); \
+ } while (0)
#define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \
PFN_##func_name func_name##_ptr = nullptr; \
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 79c5bfe1b0..5770e7155e 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RegEx" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="RegEx" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Class for searching text for patterns using regular expressions.
</brief_description>
diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml
index fab51f1e6b..82182f0de5 100644
--- a/modules/regex/doc_classes/RegExMatch.xml
+++ b/modules/regex/doc_classes/RegExMatch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RegExMatch" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="RegExMatch" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Contains the results of a [RegEx] search.
</brief_description>
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index ad7feeda49..7639155914 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -67,12 +67,22 @@ void ImageLoaderSVG::_replace_color_property(const HashMap<Color, Color> &p_colo
}
}
-Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample) {
+Ref<Image> ImageLoaderSVG::load_mem_svg(const uint8_t *p_svg, int p_size, float p_scale) {
+ Ref<Image> img;
+ img.instantiate();
+
+ Error err = create_image_from_utf8_buffer(img, p_svg, p_size, p_scale, false);
+ ERR_FAIL_COND_V(err, Ref<Image>());
+
+ return img;
+}
+
+Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const uint8_t *p_buffer, int p_buffer_size, float p_scale, bool p_upsample) {
ERR_FAIL_COND_V_MSG(Math::is_zero_approx(p_scale), ERR_INVALID_PARAMETER, "ImageLoaderSVG: Can't load SVG with a scale of 0.");
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
- tvg::Result result = picture->load((const char *)p_buffer.ptr(), p_buffer.size(), "svg", true);
+ tvg::Result result = picture->load((const char *)p_buffer, p_buffer_size, "svg", true);
if (result != tvg::Result::Success) {
return ERR_INVALID_DATA;
}
@@ -142,6 +152,10 @@ Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const Pa
return OK;
}
+Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample) {
+ return create_image_from_utf8_buffer(p_image, p_buffer.ptr(), p_buffer.size(), p_scale, p_upsample);
+}
+
Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) {
if (p_color_map.size()) {
_replace_color_property(p_color_map, "stop-color=\"", p_string);
@@ -179,3 +193,7 @@ Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileacces
}
return OK;
}
+
+ImageLoaderSVG::ImageLoaderSVG() {
+ Image::_svg_scalable_mem_loader_func = load_mem_svg;
+}
diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h
index e0d2849a62..90e9458c37 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -36,16 +36,22 @@
class ImageLoaderSVG : public ImageFormatLoader {
static HashMap<Color, Color> forced_color_map;
- void _replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string);
+ static void _replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string);
+
+ static Ref<Image> load_mem_svg(const uint8_t *p_svg, int p_size, float p_scale);
public:
static void set_forced_color_map(const HashMap<Color, Color> &p_color_map);
- Error create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample);
- Error create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map);
+ static Error create_image_from_utf8_buffer(Ref<Image> p_image, const uint8_t *p_buffer, int p_buffer_size, float p_scale, bool p_upsample);
+ static Error create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample);
+
+ static Error create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map);
virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) override;
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+
+ ImageLoaderSVG();
};
#endif // IMAGE_LOADER_SVG_H
diff --git a/modules/text_server_adv/doc_classes/TextServerAdvanced.xml b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
index 3b2128b281..b493255917 100644
--- a/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
+++ b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextServerAdvanced" inherits="TextServerExtension" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="TextServerAdvanced" inherits="TextServerExtension" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
An advanced text server with support for BiDi, complex text layout, and contextual OpenType features. Used in Godot by default.
</brief_description>
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index 82fbae5669..af9dae84e3 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -227,7 +227,6 @@ if env["freetype_enabled"]:
"compress.c",
"crc32.c",
"deflate.c",
- "infback.c",
"inffast.c",
"inflate.c",
"inftrees.c",
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index b8010e6692..13d8a2c17a 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -52,6 +52,7 @@ using namespace godot;
#include "core/object/worker_thread_pool.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
+#include "scene/resources/image_texture.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index aba727edaa..44700e045b 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -85,7 +85,7 @@ using namespace godot;
#include "core/object/worker_thread_pool.h"
#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/image_texture.h"
#include "servers/text/text_server_extension.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
diff --git a/modules/text_server_fb/doc_classes/TextServerFallback.xml b/modules/text_server_fb/doc_classes/TextServerFallback.xml
index ddd05fa445..a9a98f8e0d 100644
--- a/modules/text_server_fb/doc_classes/TextServerFallback.xml
+++ b/modules/text_server_fb/doc_classes/TextServerFallback.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextServerFallback" inherits="TextServerExtension" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="TextServerFallback" inherits="TextServerExtension" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A fallback implementation of Godot's text server, without support for BiDi and complex text layout.
</brief_description>
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index 7b4c548a21..51a6ee06be 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -222,7 +222,6 @@ if env["freetype_enabled"]:
"compress.c",
"crc32.c",
"deflate.c",
- "infback.c",
"inffast.c",
"inflate.c",
"inftrees.c",
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index d81b50779e..54311caaf9 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -83,7 +83,7 @@ using namespace godot;
#include "core/object/worker_thread_pool.h"
#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/image_texture.h"
#include "servers/text/text_server_extension.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
diff --git a/modules/theora/doc_classes/VideoStreamTheora.xml b/modules/theora/doc_classes/VideoStreamTheora.xml
index e479963ca1..4dfc529cef 100644
--- a/modules/theora/doc_classes/VideoStreamTheora.xml
+++ b/modules/theora/doc_classes/VideoStreamTheora.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStreamTheora" inherits="VideoStream" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="VideoStreamTheora" inherits="VideoStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
[VideoStream] resource for Ogg Theora videos.
</brief_description>
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 6c961813b4..d964fd7627 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
+#include "scene/resources/image_texture.h"
#ifdef _MSC_VER
#pragma warning(push)
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index 32adc28a88..21d4caef45 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -43,6 +43,8 @@
#include <theora/theoradec.h>
#include <vorbis/codec.h>
+class ImageTexture;
+
//#define THEORA_USE_THREAD_STREAMING
class VideoStreamPlaybackTheora : public VideoStreamPlayback {
diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml
index a099a193bb..7eba3ad8ec 100644
--- a/modules/upnp/doc_classes/UPNP.xml
+++ b/modules/upnp/doc_classes/UPNP.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="UPNP" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="UPNP" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Universal Plug and Play (UPnP) functions for network device discovery, querying and port forwarding.
</brief_description>
diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml
index 98e301eb4c..a70ae1b9cc 100644
--- a/modules/upnp/doc_classes/UPNPDevice.xml
+++ b/modules/upnp/doc_classes/UPNPDevice.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="UPNPDevice" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="UPNPDevice" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Universal Plug and Play (UPnP) device.
</brief_description>
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp
index fcd717cfec..b54335b724 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp
@@ -33,6 +33,7 @@
#include "core/io/file_access.h"
#include "core/variant/typed_array.h"
+#include "modules/vorbis/resource_importer_ogg_vorbis.h"
#include <ogg/ogg.h>
int AudioStreamPlaybackOggVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
@@ -520,6 +521,9 @@ bool AudioStreamOggVorbis::is_monophonic() const {
}
void AudioStreamOggVorbis::_bind_methods() {
+ ClassDB::bind_static_method("AudioStreamOggVorbis", D_METHOD("load_from_buffer", "buffer"), &AudioStreamOggVorbis::load_from_buffer);
+ ClassDB::bind_static_method("AudioStreamOggVorbis", D_METHOD("load_from_file", "path"), &AudioStreamOggVorbis::load_from_file);
+
ClassDB::bind_method(D_METHOD("set_packet_sequence", "packet_sequence"), &AudioStreamOggVorbis::set_packet_sequence);
ClassDB::bind_method(D_METHOD("get_packet_sequence"), &AudioStreamOggVorbis::get_packet_sequence);
@@ -549,3 +553,11 @@ void AudioStreamOggVorbis::_bind_methods() {
AudioStreamOggVorbis::AudioStreamOggVorbis() {}
AudioStreamOggVorbis::~AudioStreamOggVorbis() {}
+
+Ref<AudioStreamOggVorbis> AudioStreamOggVorbis::load_from_buffer(const Vector<uint8_t> &file_data) {
+ return ResourceImporterOggVorbis::load_from_buffer(file_data);
+}
+
+Ref<AudioStreamOggVorbis> AudioStreamOggVorbis::load_from_file(const String &p_path) {
+ return ResourceImporterOggVorbis::load_from_file(p_path);
+}
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h
index c76df7f84d..41ce942eec 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.h
+++ b/modules/vorbis/audio_stream_ogg_vorbis.h
@@ -125,6 +125,8 @@ protected:
static void _bind_methods();
public:
+ static Ref<AudioStreamOggVorbis> load_from_file(const String &p_path);
+ static Ref<AudioStreamOggVorbis> load_from_buffer(const Vector<uint8_t> &file_data);
void set_loop(bool p_enable);
virtual bool has_loop() const override;
diff --git a/modules/vorbis/config.py b/modules/vorbis/config.py
index a231ef179d..9e10a58849 100644
--- a/modules/vorbis/config.py
+++ b/modules/vorbis/config.py
@@ -11,6 +11,7 @@ def get_doc_classes():
return [
"AudioStreamOggVorbis",
"AudioStreamPlaybackOggVorbis",
+ "ResourceImporterOggVorbis",
]
diff --git a/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml b/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml
index 4551d395df..7e3af6688a 100644
--- a/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml
+++ b/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml
@@ -1,11 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamOggVorbis" inherits="AudioStream" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="AudioStreamOggVorbis" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ A class representing an Ogg Vorbis audio stream.
</brief_description>
<description>
+ The AudioStreamOggVorbis class is a specialized [AudioStream] for handling Ogg Vorbis file formats. It offers functionality for loading and playing back Ogg Vorbis files, as well as managing looping and other playback properties. This class is part of the audio stream system, which also supports WAV files through the [AudioStreamWAV] class.
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="load_from_buffer" qualifiers="static">
+ <return type="AudioStreamOggVorbis" />
+ <param index="0" name="buffer" type="PackedByteArray" />
+ <description>
+ Creates a new AudioStreamOggVorbis instance from the given buffer. The buffer must contain Ogg Vorbis data.
+ </description>
+ </method>
+ <method name="load_from_file" qualifiers="static">
+ <return type="AudioStreamOggVorbis" />
+ <param index="0" name="path" type="String" />
+ <description>
+ Creates a new AudioStreamOggVorbis instance from the given file path. The file must be in Ogg Vorbis format.
+ </description>
+ </method>
+ </methods>
<members>
<member name="bar_beats" type="int" setter="set_bar_beats" getter="get_bar_beats" default="4">
</member>
@@ -14,7 +32,7 @@
<member name="bpm" type="float" setter="set_bpm" getter="get_bpm" default="0.0">
</member>
<member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false">
- If [code]true[/code], the stream will automatically loop when it reaches the end.
+ If [code]true[/code], the audio will play again from the specified [member loop_offset] once it is done playing. Useful for ambient sounds and background music.
</member>
<member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset" default="0.0">
Time in seconds at which the stream starts after being looped.
diff --git a/modules/vorbis/doc_classes/AudioStreamPlaybackOggVorbis.xml b/modules/vorbis/doc_classes/AudioStreamPlaybackOggVorbis.xml
index 6b43bd1171..54a60262a7 100644
--- a/modules/vorbis/doc_classes/AudioStreamPlaybackOggVorbis.xml
+++ b/modules/vorbis/doc_classes/AudioStreamPlaybackOggVorbis.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPlaybackOggVorbis" inherits="AudioStreamPlaybackResampled" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="AudioStreamPlaybackOggVorbis" inherits="AudioStreamPlaybackResampled" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml b/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml
new file mode 100644
index 0000000000..c2dcb832e0
--- /dev/null
+++ b/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ResourceImporterOggVorbis" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Imports an Ogg Vorbis audio file for playback.
+ </brief_description>
+ <description>
+ Ogg Vorbis is a lossy audio format, with better audio quality compared to [ResourceImporterMP3] at a given bitrate.
+ In most cases, it's recommended to use Ogg Vorbis over MP3. However, if you're using a MP3 sound source with no higher quality source available, then it's recommended to use the MP3 file directly to avoid double lossy compression.
+ Ogg Vorbis requires more CPU to decode than [ResourceImporterWAV]. If you need to play a lot of simultaneous sounds, it's recommended to use WAV for those sounds instead, especially if targeting low-end devices.
+ </description>
+ <tutorials>
+ <link title="Importing audio samples">https://docs.godotengine.org/en/latest/tutorials/assets_pipeline/importing_audio_samples.html</link>
+ </tutorials>
+ <methods>
+ <method name="load_from_buffer" qualifiers="static">
+ <return type="AudioStreamOggVorbis" />
+ <param index="0" name="buffer" type="PackedByteArray" />
+ <description>
+ This method loads audio data from a PackedByteArray buffer into an AudioStreamOggVorbis object.
+ </description>
+ </method>
+ <method name="load_from_file" qualifiers="static">
+ <return type="AudioStreamOggVorbis" />
+ <param index="0" name="path" type="String" />
+ <description>
+ This method loads audio data from a file into an AudioStreamOggVorbis object. The file path is provided as a string.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="bar_beats" type="int" setter="" getter="" default="4">
+ The number of bars within a single beat in the audio track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects.
+ A more convenient editor for [member bar_beats] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio.
+ </member>
+ <member name="beat_count" type="int" setter="" getter="" default="0">
+ The beat count of the audio track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects.
+ A more convenient editor for [member beat_count] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio.
+ </member>
+ <member name="bpm" type="float" setter="" getter="" default="0">
+ The Beats Per Minute of the audio track. This should match the BPM measure that was used to compose the track. This is only relevant for music that wishes to make use of interactive music functionality (not implemented yet), not sound effects.
+ A more convenient editor for [member bpm] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio.
+ </member>
+ <member name="loop" type="bool" setter="" getter="" default="false">
+ If enabled, the audio will begin playing at the beginning after playback ends by reaching the end of the audio.
+ [b]Note:[/b] In [AudioStreamPlayer], the [signal AudioStreamPlayer.finished] signal won't be emitted for looping audio when it reaches the end of the audio file, as the audio will keep playing indefinitely.
+ </member>
+ <member name="loop_offset" type="float" setter="" getter="" default="0">
+ Determines where audio will start to loop after playback reaches the end of the audio. This can be used to only loop a part of the audio file, which is useful for some ambient sounds or music. The value is determined in seconds relative to the beginning of the audio. A value of [code]0.0[/code] will loop the entire audio file.
+ Only has an effect if [member loop] is [code]true[/code].
+ A more convenient editor for [member loop_offset] is provided in the [b]Advanced Import Settings[/b] dialog, as it lets you preview your changes without having to reimport the audio.
+ </member>
+ </members>
+</class>
diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp
index e131ff6dc9..26af912999 100644
--- a/modules/vorbis/register_types.cpp
+++ b/modules/vorbis/register_types.cpp
@@ -31,7 +31,10 @@
#include "register_types.h"
#include "audio_stream_ogg_vorbis.h"
+
+#ifdef TOOLS_ENABLED
#include "resource_importer_ogg_vorbis.h"
+#endif
void initialize_vorbis_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
@@ -44,7 +47,11 @@ void initialize_vorbis_module(ModuleInitializationLevel p_level) {
ogg_vorbis_importer.instantiate();
ResourceFormatImporter::get_singleton()->add_importer(ogg_vorbis_importer);
}
+
+ // Required to document import options in the class reference.
+ GDREGISTER_CLASS(ResourceImporterOggVorbis);
#endif
+
GDREGISTER_CLASS(AudioStreamOggVorbis);
GDREGISTER_CLASS(AudioStreamPlaybackOggVorbis);
}
diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp
index 8392750798..b42cd20589 100644
--- a/modules/vorbis/resource_importer_ogg_vorbis.cpp
+++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp
@@ -81,18 +81,50 @@ void ResourceImporterOggVorbis::get_import_options(const String &p_path, List<Im
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "bar_beats", PROPERTY_HINT_RANGE, "2,32,or_greater"), 4));
}
-Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const String &p_path) {
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(f.is_null(), Ref<AudioStreamOggVorbis>(), "Cannot open file '" + p_path + "'.");
+#ifdef TOOLS_ENABLED
+
+bool ResourceImporterOggVorbis::has_advanced_options() const {
+ return true;
+}
+
+void ResourceImporterOggVorbis::show_advanced_options(const String &p_path) {
+ Ref<AudioStreamOggVorbis> ogg_stream = load_from_file(p_path);
+ if (ogg_stream.is_valid()) {
+ AudioStreamImportSettings::get_singleton()->edit(p_path, "oggvorbisstr", ogg_stream);
+ }
+}
+#endif
+
+Error ResourceImporterOggVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
+ bool loop = p_options["loop"];
+ float loop_offset = p_options["loop_offset"];
+ double bpm = p_options["bpm"];
+ int beat_count = p_options["beat_count"];
+ int bar_beats = p_options["bar_beats"];
- uint64_t len = f->get_length();
+ Ref<AudioStreamOggVorbis> ogg_vorbis_stream = load_from_file(p_source_file);
+ if (ogg_vorbis_stream.is_null()) {
+ return ERR_CANT_OPEN;
+ }
- Vector<uint8_t> file_data;
- file_data.resize(len);
- uint8_t *w = file_data.ptrw();
+ ogg_vorbis_stream->set_loop(loop);
+ ogg_vorbis_stream->set_loop_offset(loop_offset);
+ ogg_vorbis_stream->set_bpm(bpm);
+ ogg_vorbis_stream->set_beat_count(beat_count);
+ ogg_vorbis_stream->set_bar_beats(bar_beats);
+
+ return ResourceSaver::save(ogg_vorbis_stream, p_save_path + ".oggvorbisstr");
+}
- f->get_buffer(w, len);
+ResourceImporterOggVorbis::ResourceImporterOggVorbis() {
+}
+
+void ResourceImporterOggVorbis::_bind_methods() {
+ ClassDB::bind_static_method("ResourceImporterOggVorbis", D_METHOD("load_from_buffer", "buffer"), &ResourceImporterOggVorbis::load_from_buffer);
+ ClassDB::bind_static_method("ResourceImporterOggVorbis", D_METHOD("load_from_file", "path"), &ResourceImporterOggVorbis::load_from_file);
+}
+Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::load_from_buffer(const Vector<uint8_t> &file_data) {
Ref<AudioStreamOggVorbis> ogg_vorbis_stream;
ogg_vorbis_stream.instantiate();
@@ -114,7 +146,7 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const Str
err = ogg_sync_check(&sync_state);
ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err));
while (ogg_sync_pageout(&sync_state, &page) != 1) {
- if (cursor >= len) {
+ if (cursor >= size_t(file_data.size())) {
done = true;
break;
}
@@ -123,8 +155,8 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const Str
char *sync_buf = ogg_sync_buffer(&sync_state, OGG_SYNC_BUFFER_SIZE);
err = ogg_sync_check(&sync_state);
ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err));
- ERR_FAIL_COND_V(cursor > len, Ref<AudioStreamOggVorbis>());
- size_t copy_size = len - cursor;
+ ERR_FAIL_COND_V(cursor > size_t(file_data.size()), Ref<AudioStreamOggVorbis>());
+ size_t copy_size = file_data.size() - cursor;
if (copy_size > OGG_SYNC_BUFFER_SIZE) {
copy_size = OGG_SYNC_BUFFER_SIZE;
}
@@ -201,40 +233,8 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const Str
return ogg_vorbis_stream;
}
-#ifdef TOOLS_ENABLED
-
-bool ResourceImporterOggVorbis::has_advanced_options() const {
- return true;
-}
-
-void ResourceImporterOggVorbis::show_advanced_options(const String &p_path) {
- Ref<AudioStreamOggVorbis> ogg_stream = import_ogg_vorbis(p_path);
- if (ogg_stream.is_valid()) {
- AudioStreamImportSettings::get_singleton()->edit(p_path, "oggvorbisstr", ogg_stream);
- }
-}
-#endif
-
-Error ResourceImporterOggVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
- bool loop = p_options["loop"];
- float loop_offset = p_options["loop_offset"];
- double bpm = p_options["bpm"];
- int beat_count = p_options["beat_count"];
- int bar_beats = p_options["bar_beats"];
-
- Ref<AudioStreamOggVorbis> ogg_vorbis_stream = import_ogg_vorbis(p_source_file);
- if (ogg_vorbis_stream.is_null()) {
- return ERR_CANT_OPEN;
- }
-
- ogg_vorbis_stream->set_loop(loop);
- ogg_vorbis_stream->set_loop_offset(loop_offset);
- ogg_vorbis_stream->set_bpm(bpm);
- ogg_vorbis_stream->set_beat_count(beat_count);
- ogg_vorbis_stream->set_bar_beats(bar_beats);
-
- return ResourceSaver::save(ogg_vorbis_stream, p_save_path + ".oggvorbisstr");
-}
-
-ResourceImporterOggVorbis::ResourceImporterOggVorbis() {
+Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::load_from_file(const String &p_path) {
+ Vector<uint8_t> file_data = FileAccess::get_file_as_bytes(p_path);
+ ERR_FAIL_COND_V_MSG(file_data.is_empty(), Ref<AudioStreamOggVorbis>(), "Cannot open file '" + p_path + "'.");
+ return load_from_buffer(file_data);
}
diff --git a/modules/vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h
index 4874419834..59ae3378a0 100644
--- a/modules/vorbis/resource_importer_ogg_vorbis.h
+++ b/modules/vorbis/resource_importer_ogg_vorbis.h
@@ -42,16 +42,17 @@ class ResourceImporterOggVorbis : public ResourceImporter {
OGG_SYNC_BUFFER_SIZE = 8192,
};
-private:
- // virtual int get_samples_in_packet(Vector<uint8_t> p_packet) = 0;
-
- static Ref<AudioStreamOggVorbis> import_ogg_vorbis(const String &p_path);
+protected:
+ static void _bind_methods();
public:
#ifdef TOOLS_ENABLED
virtual bool has_advanced_options() const override;
virtual void show_advanced_options(const String &p_path) override;
#endif
+
+ static Ref<AudioStreamOggVorbis> load_from_file(const String &p_path);
+ static Ref<AudioStreamOggVorbis> load_from_buffer(const Vector<uint8_t> &file_data);
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
virtual String get_save_extension() const override;
virtual String get_resource_type() const override;
diff --git a/modules/webp/resource_saver_webp.cpp b/modules/webp/resource_saver_webp.cpp
index 92285e2eab..52289334f8 100644
--- a/modules/webp/resource_saver_webp.cpp
+++ b/modules/webp/resource_saver_webp.cpp
@@ -34,7 +34,7 @@
#include "core/io/file_access.h"
#include "core/io/image.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/image_texture.h"
Error ResourceSaverWebP::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
Ref<ImageTexture> texture = p_resource;
diff --git a/modules/webp/webp_common.cpp b/modules/webp/webp_common.cpp
index 60cb0091e1..bc34a25733 100644
--- a/modules/webp/webp_common.cpp
+++ b/modules/webp/webp_common.cpp
@@ -84,6 +84,7 @@ Vector<uint8_t> _webp_packer(const Ref<Image> &p_image, float p_quality, bool p_
}
config.method = compression_method;
config.quality = p_quality;
+ config.use_sharp_yuv = 1;
pic.use_argb = 1;
pic.width = s.width;
pic.height = s.height;
diff --git a/modules/webrtc/doc_classes/WebRTCDataChannel.xml b/modules/webrtc/doc_classes/WebRTCDataChannel.xml
index 1ab80a93cb..f24fdb4800 100644
--- a/modules/webrtc/doc_classes/WebRTCDataChannel.xml
+++ b/modules/webrtc/doc_classes/WebRTCDataChannel.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebRTCDataChannel" inherits="PacketPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="WebRTCDataChannel" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
index 7a69ceb8f6..b34fd68aee 100644
--- a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
+++ b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebRTCDataChannelExtension" inherits="WebRTCDataChannel" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="WebRTCDataChannelExtension" inherits="WebRTCDataChannel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
index fa58bf5d58..63caa9e4b9 100644
--- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
+++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebRTCMultiplayerPeer" inherits="MultiplayerPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="WebRTCMultiplayerPeer" inherits="MultiplayerPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A simple interface to create a peer-to-peer mesh network composed of [WebRTCPeerConnection] that is compatible with the [MultiplayerAPI].
</brief_description>
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
index 99a5381f0c..f8c015dd06 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebRTCPeerConnection" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="WebRTCPeerConnection" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Interface to a WebRTC peer connection.
</brief_description>
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
index dbe6033c4d..e90a36a76c 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebRTCPeerConnectionExtension" inherits="WebRTCPeerConnection" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="WebRTCPeerConnectionExtension" inherits="WebRTCPeerConnection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
index ff94d4452a..0978e1fcee 100644
--- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebSocketMultiplayerPeer" inherits="MultiplayerPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="WebSocketMultiplayerPeer" inherits="MultiplayerPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Base class for WebSocket server and client.
</brief_description>
diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml
index 61f0be22f6..4c2d0159a6 100644
--- a/modules/websocket/doc_classes/WebSocketPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebSocketPeer" inherits="PacketPeer" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="WebSocketPeer" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A WebSocket connection.
</brief_description>
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index 9591afa536..9e1167c09f 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebXRInterface" inherits="XRInterface" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="WebXRInterface" inherits="XRInterface" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
XR interface using WebXR.
</brief_description>
diff --git a/modules/zip/doc_classes/ZIPPacker.xml b/modules/zip/doc_classes/ZIPPacker.xml
index 5d5bedb773..3be7d8b6df 100644
--- a/modules/zip/doc_classes/ZIPPacker.xml
+++ b/modules/zip/doc_classes/ZIPPacker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ZIPPacker" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="ZIPPacker" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Allows the creation of zip files.
</brief_description>
diff --git a/modules/zip/doc_classes/ZIPReader.xml b/modules/zip/doc_classes/ZIPReader.xml
index 410dc6126f..0fa2672044 100644
--- a/modules/zip/doc_classes/ZIPReader.xml
+++ b/modules/zip/doc_classes/ZIPReader.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ZIPReader" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="ZIPReader" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Allows reading the content of a zip file.
</brief_description>
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index 37a019eaa4..f6a0776017 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -64,7 +64,7 @@ void AndroidInputHandler::_set_key_modifier_state(Ref<InputEventWithModifiers> e
}
}
-void AndroidInputHandler::process_key_event(int p_physical_keycode, int p_unicode, int p_key_label, bool p_pressed) {
+void AndroidInputHandler::process_key_event(int p_physical_keycode, int p_unicode, int p_key_label, bool p_pressed, bool p_echo) {
static char32_t prev_wc = 0;
char32_t unicode = p_unicode;
if ((p_unicode & 0xfffffc00) == 0xd800) {
@@ -88,7 +88,7 @@ void AndroidInputHandler::process_key_event(int p_physical_keycode, int p_unicod
ev.instantiate();
Key physical_keycode = godot_code_from_android_code(p_physical_keycode);
- Key keycode = physical_keycode;
+ Key keycode;
if (unicode == '\b') { // 0x08
keycode = Key::BACKSPACE;
} else if (unicode == '\t') { // 0x09
@@ -125,6 +125,7 @@ void AndroidInputHandler::process_key_event(int p_physical_keycode, int p_unicod
ev->set_key_label(fix_key_label(p_key_label, keycode));
ev->set_unicode(fix_unicode(unicode));
ev->set_pressed(p_pressed);
+ ev->set_echo(p_echo);
_set_key_modifier_state(ev, keycode);
diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h
index 42d1c228a8..c74c5020e3 100644
--- a/platform/android/android_input_handler.h
+++ b/platform/android/android_input_handler.h
@@ -101,7 +101,7 @@ public:
void process_magnify(Point2 p_pos, float p_factor);
void process_pan(Point2 p_pos, Vector2 p_delta);
void process_joy_event(JoypadEvent p_event);
- void process_key_event(int p_physical_keycode, int p_unicode, int p_key_label, bool p_pressed);
+ void process_key_event(int p_physical_keycode, int p_unicode, int p_key_label, bool p_pressed, bool p_echo);
};
#endif // ANDROID_INPUT_HANDLER_H
diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
index 9d68cb78f6..d61d63d242 100644
--- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml
+++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlatformAndroid" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorExportPlatformAndroid" inherits="EditorExportPlatform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for Android.
</brief_description>
@@ -104,6 +104,12 @@
<member name="package/retain_data_on_uninstall" type="bool" setter="" getter="">
If [code]true[/code], when the user uninstalls an app, a prompt to keep the app's data will be shown.
</member>
+ <member name="package/show_as_launcher_app" type="bool" setter="" getter="">
+ If [code]true[/code], the user will be able to set this app as the system launcher in Android preferences.
+ </member>
+ <member name="package/show_in_android_tv" type="bool" setter="" getter="">
+ If [code]true[/code], this app will show in Android TV launcher UI.
+ </member>
<member name="package/signed" type="bool" setter="" getter="">
If [code]true[/code], package signing is enabled.
</member>
@@ -578,12 +584,6 @@
<member name="version/name" type="String" setter="" getter="">
Application version visible to the user.
</member>
- <member name="xr_features/hand_tracking" type="int" setter="" getter="">
- </member>
- <member name="xr_features/hand_tracking_frequency" type="int" setter="" getter="">
- </member>
- <member name="xr_features/passthrough" type="int" setter="" getter="">
- </member>
<member name="xr_features/xr_mode" type="int" setter="" getter="">
</member>
</members>
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index c94119e13d..4eb516fb63 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -48,6 +48,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "main/splash.gen.h"
+#include "scene/resources/image_texture.h"
#include "modules/modules_enabled.gen.h" // For mono and svg.
#ifdef MODULE_SVG_ENABLED
@@ -260,30 +261,32 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
EditorExportPlatformAndroid *ea = static_cast<EditorExportPlatformAndroid *>(ud);
while (!ea->quit_request.is_set()) {
- // Check for plugins updates
+#ifndef DISABLE_DEPRECATED
+ // Check for android plugins updates
{
// Nothing to do if we already know the plugins have changed.
- if (!ea->plugins_changed.is_set()) {
+ if (!ea->android_plugins_changed.is_set()) {
Vector<PluginConfigAndroid> loaded_plugins = get_plugins();
- MutexLock lock(ea->plugins_lock);
+ MutexLock lock(ea->android_plugins_lock);
- if (ea->plugins.size() != loaded_plugins.size()) {
- ea->plugins_changed.set();
+ if (ea->android_plugins.size() != loaded_plugins.size()) {
+ ea->android_plugins_changed.set();
} else {
- for (int i = 0; i < ea->plugins.size(); i++) {
- if (ea->plugins[i].name != loaded_plugins[i].name) {
- ea->plugins_changed.set();
+ for (int i = 0; i < ea->android_plugins.size(); i++) {
+ if (ea->android_plugins[i].name != loaded_plugins[i].name) {
+ ea->android_plugins_changed.set();
break;
}
}
}
- if (ea->plugins_changed.is_set()) {
- ea->plugins = loaded_plugins;
+ if (ea->android_plugins_changed.is_set()) {
+ ea->android_plugins = loaded_plugins;
}
}
}
+#endif // DISABLE_DEPRECATED
// Check for devices updates
String adb = get_adb_path();
@@ -627,6 +630,7 @@ Vector<EditorExportPlatformAndroid::ABI> EditorExportPlatformAndroid::get_abis()
return abis;
}
+#ifndef DISABLE_DEPRECATED
/// List the gdap files in the directory specified by the p_path parameter.
Vector<String> EditorExportPlatformAndroid::list_gdap_files(const String &p_path) {
Vector<String> dir_files;
@@ -693,6 +697,7 @@ Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_enabled_plugins(con
return enabled_plugins;
}
+#endif // DISABLE_DEPRECATED
Error EditorExportPlatformAndroid::store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method) {
zip_fileinfo zipfi = get_zip_fileinfo();
@@ -827,16 +832,6 @@ void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset>
r_permissions.push_back("android.permission.INTERNET");
}
}
-
- int xr_mode_index = p_preset->get("xr_features/xr_mode");
- if (xr_mode_index == XR_MODE_OPENXR) {
- int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
- if (hand_tracking_index > XR_HAND_TRACKING_NONE) {
- if (r_permissions.find("com.oculus.permission.HAND_TRACKING") == -1) {
- r_permissions.push_back("com.oculus.permission.HAND_TRACKING");
- }
- }
- }
}
void EditorExportPlatformAndroid::_write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug) {
@@ -860,8 +855,23 @@ void EditorExportPlatformAndroid::_write_tmp_manifest(const Ref<EditorExportPres
}
}
- manifest_text += _get_xr_features_tag(p_preset, _uses_vulkan());
- manifest_text += _get_application_tag(p_preset, _has_read_write_storage_permission(perms));
+ if (_uses_vulkan()) {
+ manifest_text += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vulkan.level\" android:required=\"false\" android:version=\"1\" />\n";
+ manifest_text += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vulkan.version\" android:required=\"true\" android:version=\"0x400003\" />\n";
+ }
+
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ if (export_plugins[i]->supports_platform(Ref<EditorExportPlatform>(this))) {
+ const String contents = export_plugins[i]->get_android_manifest_element_contents(Ref<EditorExportPlatform>(this), p_debug);
+ if (!contents.is_empty()) {
+ manifest_text += contents;
+ manifest_text += "\n";
+ }
+ }
+ }
+
+ manifest_text += _get_application_tag(Ref<EditorExportPlatform>(this), p_preset, _has_read_write_storage_permission(perms), p_debug);
manifest_text += "</manifest>\n";
String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release"));
@@ -1720,7 +1730,7 @@ String EditorExportPlatformAndroid::get_export_option_warning(const EditorExport
}
} else if (p_name == "gradle_build/use_gradle_build") {
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
- String enabled_plugins_names = PluginConfigAndroid::get_plugins_names(get_enabled_plugins(Ref<EditorExportPreset>(p_preset)));
+ String enabled_plugins_names = _get_plugins_names(Ref<EditorExportPreset>(p_preset));
if (!enabled_plugins_names.is_empty() && !gradle_build_enabled) {
return TTR("\"Use Gradle Build\" must be enabled to use the plugins.");
}
@@ -1730,22 +1740,6 @@ String EditorExportPlatformAndroid::get_export_option_warning(const EditorExport
if (xr_mode_index == XR_MODE_OPENXR && !gradle_build_enabled) {
return TTR("OpenXR requires \"Use Gradle Build\" to be enabled");
}
- } else if (p_name == "xr_features/hand_tracking") {
- int xr_mode_index = p_preset->get("xr_features/xr_mode");
- int hand_tracking = p_preset->get("xr_features/hand_tracking");
- if (xr_mode_index != XR_MODE_OPENXR) {
- if (hand_tracking > XR_HAND_TRACKING_NONE) {
- return TTR("\"Hand Tracking\" is only valid when \"XR Mode\" is \"OpenXR\".");
- }
- }
- } else if (p_name == "xr_features/passthrough") {
- int xr_mode_index = p_preset->get("xr_features/xr_mode");
- int passthrough_mode = p_preset->get("xr_features/passthrough");
- if (xr_mode_index != XR_MODE_OPENXR) {
- if (passthrough_mode > XR_PASSTHROUGH_NONE) {
- return TTR("\"Passthrough\" is only valid when \"XR Mode\" is \"OpenXR\".");
- }
- }
} else if (p_name == "gradle_build/export_format") {
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
if (int(p_preset->get("gradle_build/export_format")) == EXPORT_FORMAT_AAB && !gradle_build_enabled) {
@@ -1807,12 +1801,14 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/min_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", VULKAN_MIN_SDK_VERSION)), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/target_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_TARGET_SDK_VERSION)), "", false, true));
+#ifndef DISABLE_DEPRECATED
Vector<PluginConfigAndroid> plugins_configs = get_plugins();
for (int i = 0; i < plugins_configs.size(); i++) {
print_verbose("Found Android plugin " + plugins_configs[i].name);
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("plugins"), plugins_configs[i].name)), false));
}
- plugins_changed.clear();
+ android_plugins_changed.clear();
+#endif // DISABLE_DEPRECATED
// Android supports multiple architectures in an app bundle, so
// we expose each option as a checkbox in the export dialog.
@@ -1841,6 +1837,8 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
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));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/retain_data_on_uninstall"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/exclude_from_recents"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/show_in_android_tv"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/show_as_launcher_app"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icon_option, PROPERTY_HINT_FILE, "*.png"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_foreground_option, PROPERTY_HINT_FILE, "*.png"), ""));
@@ -1849,9 +1847,6 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,OpenXR"), XR_MODE_REGULAR, false, true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), XR_HAND_TRACKING_NONE, false, true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking_frequency", PROPERTY_HINT_ENUM, "Low,High"), XR_HAND_TRACKING_FREQUENCY_LOW));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/passthrough", PROPERTY_HINT_ENUM, "None,Optional,Required"), XR_PASSTHROUGH_NONE, false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true));
@@ -1889,12 +1884,14 @@ Ref<Texture2D> EditorExportPlatformAndroid::get_logo() const {
}
bool EditorExportPlatformAndroid::should_update_export_options() {
- bool export_options_changed = plugins_changed.is_set();
- if (export_options_changed) {
+#ifndef DISABLE_DEPRECATED
+ if (android_plugins_changed.is_set()) {
// don't clear unless we're reporting true, to avoid race
- plugins_changed.clear();
+ android_plugins_changed.clear();
+ return true;
}
- return export_options_changed;
+#endif // DISABLE_DEPRECATED
+ return false;
}
bool EditorExportPlatformAndroid::poll_export() {
@@ -2228,17 +2225,16 @@ String EditorExportPlatformAndroid::get_apksigner_path(int p_target_sdk, bool p_
}
bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
- String err;
- bool valid = false;
- const bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
-
#ifdef MODULE_MONO_ENABLED
- err += TTR("Exporting to Android is currently not supported in Godot 4 when using C#/.NET. Use Godot 3 to target Android with C#/Mono instead.") + "\n";
- err += TTR("If this project does not use C#, use a non-C# editor build to export the project.") + "\n";
// Don't check for additional errors, as this particular error cannot be resolved.
- r_error = err;
+ r_error += TTR("Exporting to Android is currently not supported in Godot 4 when using C#/.NET. Use Godot 3 to target Android with C#/Mono instead.") + "\n";
+ r_error += TTR("If this project does not use C#, use a non-C# editor build to export the project.") + "\n";
return false;
-#endif
+#else
+
+ String err;
+ bool valid = false;
+ const bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
// Look for export templates (first official, and if defined custom templates).
@@ -2369,6 +2365,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
}
return valid;
+#endif // !MODULE_MONO_ENABLED
}
bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
@@ -2694,6 +2691,64 @@ String EditorExportPlatformAndroid::join_abis(const Vector<EditorExportPlatformA
return ret;
}
+String EditorExportPlatformAndroid::_get_plugins_names(const Ref<EditorExportPreset> &p_preset) const {
+ Vector<String> names;
+
+#ifndef DISABLE_DEPRECATED
+ PluginConfigAndroid::get_plugins_names(get_enabled_plugins(p_preset), names);
+#endif // DISABLE_DEPRECATED
+
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ if (export_plugins[i]->supports_platform(Ref<EditorExportPlatform>(this))) {
+ names.push_back(export_plugins[i]->get_name());
+ }
+ }
+
+ String plugins_names = String("|").join(names);
+ return plugins_names;
+}
+
+String EditorExportPlatformAndroid::_resolve_export_plugin_android_library_path(const String &p_android_library_path) const {
+ String absolute_path;
+ if (!p_android_library_path.is_empty()) {
+ if (p_android_library_path.is_absolute_path()) {
+ absolute_path = ProjectSettings::get_singleton()->globalize_path(p_android_library_path);
+ } else {
+ const String export_plugin_absolute_path = String("res://addons/").path_join(p_android_library_path);
+ absolute_path = ProjectSettings::get_singleton()->globalize_path(export_plugin_absolute_path);
+ }
+ }
+ return absolute_path;
+}
+
+bool EditorExportPlatformAndroid::_is_clean_build_required(const Ref<EditorExportPreset> &p_preset) {
+ bool first_build = last_gradle_build_time == 0;
+ bool have_plugins_changed = false;
+
+ String plugin_names = _get_plugins_names(p_preset);
+
+ if (!first_build) {
+ have_plugins_changed = plugin_names != last_plugin_names;
+#ifndef DISABLE_DEPRECATED
+ if (!have_plugins_changed) {
+ Vector<PluginConfigAndroid> enabled_plugins = get_enabled_plugins(p_preset);
+ for (int i = 0; i < enabled_plugins.size(); i++) {
+ if (enabled_plugins.get(i).last_updated > last_gradle_build_time) {
+ have_plugins_changed = true;
+ break;
+ }
+ }
+ }
+#endif // DISABLE_DEPRECATED
+ }
+
+ last_gradle_build_time = OS::get_singleton()->get_unix_time();
+ last_plugin_names = plugin_names;
+
+ return have_plugins_changed || first_build;
+}
+
Error EditorExportPlatformAndroid::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
int export_format = int(p_preset->get("gradle_build/export_format"));
bool should_sign = p_preset->get("package/signed");
@@ -2851,11 +2906,40 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String sign_flag = should_sign ? "true" : "false";
String zipalign_flag = "true";
+ Vector<String> android_libraries;
+ Vector<String> android_dependencies;
+ Vector<String> android_dependencies_maven_repos;
+
+#ifndef DISABLE_DEPRECATED
Vector<PluginConfigAndroid> enabled_plugins = get_enabled_plugins(p_preset);
- String local_plugins_binaries = PluginConfigAndroid::get_plugins_binaries(PluginConfigAndroid::BINARY_TYPE_LOCAL, enabled_plugins);
- String remote_plugins_binaries = PluginConfigAndroid::get_plugins_binaries(PluginConfigAndroid::BINARY_TYPE_REMOTE, enabled_plugins);
- String custom_maven_repos = PluginConfigAndroid::get_plugins_custom_maven_repos(enabled_plugins);
- bool clean_build_required = is_clean_build_required(enabled_plugins);
+ PluginConfigAndroid::get_plugins_binaries(PluginConfigAndroid::BINARY_TYPE_LOCAL, enabled_plugins, android_libraries);
+ PluginConfigAndroid::get_plugins_binaries(PluginConfigAndroid::BINARY_TYPE_REMOTE, enabled_plugins, android_dependencies);
+ PluginConfigAndroid::get_plugins_custom_maven_repos(enabled_plugins, android_dependencies_maven_repos);
+#endif // DISABLE_DEPRECATED
+
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ if (export_plugins[i]->supports_platform(Ref<EditorExportPlatform>(this))) {
+ PackedStringArray export_plugin_android_libraries = export_plugins[i]->get_android_libraries(Ref<EditorExportPlatform>(this), p_debug);
+ for (int k = 0; k < export_plugin_android_libraries.size(); k++) {
+ const String resolved_android_library_path = _resolve_export_plugin_android_library_path(export_plugin_android_libraries[k]);
+ if (!resolved_android_library_path.is_empty()) {
+ android_libraries.push_back(resolved_android_library_path);
+ }
+ }
+
+ PackedStringArray export_plugin_android_dependencies = export_plugins[i]->get_android_dependencies(Ref<EditorExportPlatform>(this), p_debug);
+ android_dependencies.append_array(export_plugin_android_dependencies);
+
+ PackedStringArray export_plugin_android_dependencies_maven_repos = export_plugins[i]->get_android_dependencies_maven_repos(Ref<EditorExportPlatform>(this), p_debug);
+ android_dependencies_maven_repos.append_array(export_plugin_android_dependencies_maven_repos);
+ }
+ }
+
+ bool clean_build_required = _is_clean_build_required(p_preset);
+ String combined_android_libraries = String("|").join(android_libraries);
+ String combined_android_dependencies = String("|").join(android_dependencies);
+ String combined_android_dependencies_maven_repos = String("|").join(android_dependencies_maven_repos);
List<String> cmdline;
if (clean_build_required) {
@@ -2879,9 +2963,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
cmdline.push_back("-Pexport_version_min_sdk=" + min_sdk_version); // argument to specify the min sdk.
cmdline.push_back("-Pexport_version_target_sdk=" + target_sdk_version); // argument to specify the target sdk.
cmdline.push_back("-Pexport_enabled_abis=" + enabled_abi_string); // argument to specify enabled ABIs.
- cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies.
- cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies.
- cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies.
+ cmdline.push_back("-Pplugins_local_binaries=" + combined_android_libraries); // argument to specify the list of android libraries provided by plugins.
+ cmdline.push_back("-Pplugins_remote_binaries=" + combined_android_dependencies); // argument to specify the list of android dependencies provided by plugins.
+ cmdline.push_back("-Pplugins_maven_repos=" + combined_android_dependencies_maven_repos); // argument to specify the list of maven repos for android dependencies provided by plugins.
cmdline.push_back("-Pperform_zipalign=" + zipalign_flag); // argument to specify whether the build should be zipaligned.
cmdline.push_back("-Pperform_signing=" + sign_flag); // argument to specify whether the build should be signed.
cmdline.push_back("-Pgodot_editor_version=" + String(VERSION_FULL_CONFIG));
@@ -3299,16 +3383,17 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
- ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false);
logo = ImageTexture::create_from_image(img);
- img_loader.create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img);
#endif
devices_changed.set();
- plugins_changed.set();
+#ifndef DISABLE_DEPRECATED
+ android_plugins_changed.set();
+#endif // DISABLE_DEPRECATED
#ifndef ANDROID_ENABLED
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
#endif
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 0ac0fbb10b..a2d0417c5d 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -31,7 +31,9 @@
#ifndef ANDROID_EXPORT_PLUGIN_H
#define ANDROID_EXPORT_PLUGIN_H
+#ifndef DISABLE_DEPRECATED
#include "godot_plugin_config.h"
+#endif // DISABLE_DEPRECATED
#include "core/io/zip_io.h"
#include "core/os/os.h"
@@ -81,11 +83,14 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
EditorProgress *ep = nullptr;
};
- mutable Vector<PluginConfigAndroid> plugins;
+#ifndef DISABLE_DEPRECATED
+ mutable Vector<PluginConfigAndroid> android_plugins;
+ mutable SafeFlag android_plugins_changed;
+ Mutex android_plugins_lock;
+#endif // DISABLE_DEPRECATED
String last_plugin_names;
uint64_t last_gradle_build_time = 0;
- mutable SafeFlag plugins_changed;
- Mutex plugins_lock;
+
Vector<Device> devices;
SafeFlag devices_changed;
Mutex device_lock;
@@ -128,12 +133,14 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
static Vector<ABI> get_abis();
+#ifndef DISABLE_DEPRECATED
/// List the gdap files in the directory specified by the p_path parameter.
static Vector<String> list_gdap_files(const String &p_path);
static Vector<PluginConfigAndroid> get_plugins();
static Vector<PluginConfigAndroid> get_enabled_plugins(const Ref<EditorExportPreset> &p_presets);
+#endif // DISABLE_DEPRECATED
static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method = Z_DEFLATED);
@@ -224,28 +231,11 @@ public:
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
- inline bool is_clean_build_required(Vector<PluginConfigAndroid> enabled_plugins) {
- String plugin_names = PluginConfigAndroid::get_plugins_names(enabled_plugins);
- bool first_build = last_gradle_build_time == 0;
- bool have_plugins_changed = false;
-
- if (!first_build) {
- have_plugins_changed = plugin_names != last_plugin_names;
- if (!have_plugins_changed) {
- for (int i = 0; i < enabled_plugins.size(); i++) {
- if (enabled_plugins.get(i).last_updated > last_gradle_build_time) {
- have_plugins_changed = true;
- break;
- }
- }
- }
- }
+ String _get_plugins_names(const Ref<EditorExportPreset> &p_preset) const;
- last_gradle_build_time = OS::get_singleton()->get_unix_time();
- last_plugin_names = plugin_names;
+ String _resolve_export_plugin_android_library_path(const String &p_android_library_path) const;
- return have_plugins_changed || first_build;
- }
+ bool _is_clean_build_required(const Ref<EditorExportPreset> &p_preset);
String get_apk_expansion_fullpath(const Ref<EditorExportPreset> &p_preset, const String &p_path);
diff --git a/platform/android/export/godot_plugin_config.cpp b/platform/android/export/godot_plugin_config.cpp
index b64cca3254..cdec5f55b7 100644
--- a/platform/android/export/godot_plugin_config.cpp
+++ b/platform/android/export/godot_plugin_config.cpp
@@ -30,6 +30,8 @@
#include "godot_plugin_config.h"
+#ifndef DISABLE_DEPRECATED
+
/*
* Set of prebuilt plugins.
* Currently unused, this is just for future reference:
@@ -145,10 +147,8 @@ PluginConfigAndroid PluginConfigAndroid::load_plugin_config(Ref<ConfigFile> conf
return plugin_config;
}
-String PluginConfigAndroid::get_plugins_binaries(String binary_type, Vector<PluginConfigAndroid> plugins_configs) {
- String plugins_binaries;
+void PluginConfigAndroid::get_plugins_binaries(String binary_type, Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result) {
if (!plugins_configs.is_empty()) {
- Vector<String> binaries;
for (int i = 0; i < plugins_configs.size(); i++) {
PluginConfigAndroid config = plugins_configs[i];
if (!config.valid_config) {
@@ -156,56 +156,44 @@ String PluginConfigAndroid::get_plugins_binaries(String binary_type, Vector<Plug
}
if (config.binary_type == binary_type) {
- binaries.push_back(config.binary);
+ r_result.push_back(config.binary);
}
if (binary_type == PluginConfigAndroid::BINARY_TYPE_LOCAL) {
- binaries.append_array(config.local_dependencies);
+ r_result.append_array(config.local_dependencies);
}
if (binary_type == PluginConfigAndroid::BINARY_TYPE_REMOTE) {
- binaries.append_array(config.remote_dependencies);
+ r_result.append_array(config.remote_dependencies);
}
}
-
- plugins_binaries = String(PluginConfigAndroid::PLUGIN_VALUE_SEPARATOR).join(binaries);
}
-
- return plugins_binaries;
}
-String PluginConfigAndroid::get_plugins_custom_maven_repos(Vector<PluginConfigAndroid> plugins_configs) {
- String custom_maven_repos;
+void PluginConfigAndroid::get_plugins_custom_maven_repos(Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result) {
if (!plugins_configs.is_empty()) {
- Vector<String> repos_urls;
for (int i = 0; i < plugins_configs.size(); i++) {
PluginConfigAndroid config = plugins_configs[i];
if (!config.valid_config) {
continue;
}
- repos_urls.append_array(config.custom_maven_repos);
+ r_result.append_array(config.custom_maven_repos);
}
-
- custom_maven_repos = String(PluginConfigAndroid::PLUGIN_VALUE_SEPARATOR).join(repos_urls);
}
- return custom_maven_repos;
}
-String PluginConfigAndroid::get_plugins_names(Vector<PluginConfigAndroid> plugins_configs) {
- String plugins_names;
+void PluginConfigAndroid::get_plugins_names(Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result) {
if (!plugins_configs.is_empty()) {
- Vector<String> names;
for (int i = 0; i < plugins_configs.size(); i++) {
PluginConfigAndroid config = plugins_configs[i];
if (!config.valid_config) {
continue;
}
- names.push_back(config.name);
+ r_result.push_back(config.name);
}
- plugins_names = String(PluginConfigAndroid::PLUGIN_VALUE_SEPARATOR).join(names);
}
-
- return plugins_names;
}
+
+#endif // DISABLE_DEPRECATED
diff --git a/platform/android/export/godot_plugin_config.h b/platform/android/export/godot_plugin_config.h
index bef00979a9..8c56d00187 100644
--- a/platform/android/export/godot_plugin_config.h
+++ b/platform/android/export/godot_plugin_config.h
@@ -31,6 +31,8 @@
#ifndef ANDROID_GODOT_PLUGIN_CONFIG_H
#define ANDROID_GODOT_PLUGIN_CONFIG_H
+#ifndef DISABLE_DEPRECATED
+
#include "core/config/project_settings.h"
#include "core/error/error_list.h"
#include "core/io/config_file.h"
@@ -67,8 +69,6 @@ struct PluginConfigAndroid {
inline static const char *BINARY_TYPE_LOCAL = "local";
inline static const char *BINARY_TYPE_REMOTE = "remote";
- inline static const char *PLUGIN_VALUE_SEPARATOR = "|";
-
// Set to true when the config file is properly loaded.
bool valid_config = false;
// Unix timestamp of last change to this plugin.
@@ -96,11 +96,13 @@ struct PluginConfigAndroid {
static PluginConfigAndroid load_plugin_config(Ref<ConfigFile> config_file, const String &path);
- static String get_plugins_binaries(String binary_type, Vector<PluginConfigAndroid> plugins_configs);
+ static void get_plugins_binaries(String binary_type, Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result);
- static String get_plugins_custom_maven_repos(Vector<PluginConfigAndroid> plugins_configs);
+ static void get_plugins_custom_maven_repos(Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result);
- static String get_plugins_names(Vector<PluginConfigAndroid> plugins_configs);
+ static void get_plugins_names(Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result);
};
+#endif // DISABLE_DEPRECATED
+
#endif // ANDROID_GODOT_PLUGIN_CONFIG_H
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index ba4487cc4d..d0d0c34bb4 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -254,34 +254,7 @@ String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {
return manifest_screen_sizes;
}
-String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_vulkan) {
- String manifest_xr_features;
- int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode"));
- bool uses_xr = xr_mode_index == XR_MODE_OPENXR;
- if (uses_xr) {
- int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
- if (hand_tracking_index == XR_HAND_TRACKING_OPTIONAL) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n";
- } else if (hand_tracking_index == XR_HAND_TRACKING_REQUIRED) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"true\" />\n";
- }
-
- int passthrough_mode = p_preset->get("xr_features/passthrough");
- if (passthrough_mode == XR_PASSTHROUGH_OPTIONAL) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.PASSTHROUGH\" android:required=\"false\" />\n";
- } else if (passthrough_mode == XR_PASSTHROUGH_REQUIRED) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.PASSTHROUGH\" android:required=\"true\" />\n";
- }
- }
-
- if (p_uses_vulkan) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vulkan.level\" android:required=\"false\" android:version=\"1\" />\n";
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vulkan.version\" android:required=\"true\" android:version=\"0x400003\" />\n";
- }
- return manifest_xr_features;
-}
-
-String _get_activity_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_xr) {
+String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug) {
String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
String manifest_activity_text = vformat(
" <activity android:name=\"com.godot.game.GodotApp\" "
@@ -294,40 +267,42 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_xr
orientation,
bool_to_string(bool(GLOBAL_GET("display/window/size/resizable"))));
- if (p_uses_xr) {
- manifest_activity_text += " <intent-filter>\n"
- " <action android:name=\"android.intent.action.MAIN\" />\n"
- " <category android:name=\"android.intent.category.LAUNCHER\" />\n"
- "\n"
- " <!-- Enable access to OpenXR on Oculus mobile devices, no-op on other Android\n"
- " platforms. -->\n"
- " <category android:name=\"com.oculus.intent.category.VR\" />\n"
- "\n"
- " <!-- OpenXR category tag to indicate the activity starts in an immersive OpenXR mode. \n"
- " See https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#android-runtime-category. -->\n"
- " <category android:name=\"org.khronos.openxr.intent.category.IMMERSIVE_HMD\" />\n"
- "\n"
- " <!-- Enable VR access on HTC Vive Focus devices. -->\n"
- " <category android:name=\"com.htc.intent.category.VRAPP\" />\n"
- " </intent-filter>\n";
- } else {
- manifest_activity_text += " <intent-filter>\n"
- " <action android:name=\"android.intent.action.MAIN\" />\n"
- " <category android:name=\"android.intent.category.LAUNCHER\" />\n"
- " </intent-filter>\n";
+ manifest_activity_text += " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.MAIN\" />\n"
+ " <category android:name=\"android.intent.category.LAUNCHER\" />\n";
+
+ bool uses_leanback_category = p_preset->get("package/show_in_android_tv");
+ if (uses_leanback_category) {
+ manifest_activity_text += " <category android:name=\"android.intent.category.LEANBACK_LAUNCHER\" />\n";
+ }
+
+ bool uses_home_category = p_preset->get("package/show_as_launcher_app");
+ if (uses_home_category) {
+ manifest_activity_text += " <category android:name=\"android.intent.category.HOME\" />\n";
+ manifest_activity_text += " <category android:name=\"android.intent.category.DEFAULT\" />\n";
+ }
+
+ manifest_activity_text += " </intent-filter>\n";
+
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ if (export_plugins[i]->supports_platform(p_export_platform)) {
+ const String contents = export_plugins[i]->get_android_manifest_activity_element_contents(p_export_platform, p_debug);
+ if (!contents.is_empty()) {
+ manifest_activity_text += contents;
+ manifest_activity_text += "\n";
+ }
+ }
}
manifest_activity_text += " </activity>\n";
return manifest_activity_text;
}
-String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission) {
+String _get_application_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission, bool p_debug) {
int app_category_index = (int)(p_preset->get("package/app_category"));
bool is_game = app_category_index == APP_CATEGORY_GAME;
- int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode"));
- bool uses_xr = xr_mode_index == XR_MODE_OPENXR;
-
String manifest_application_text = vformat(
" <application android:label=\"@string/godot_project_name_string\"\n"
" android:allowBackup=\"%s\"\n"
@@ -344,18 +319,18 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_
bool_to_string(p_preset->get("package/retain_data_on_uninstall")),
bool_to_string(p_has_read_write_storage_permission));
- if (uses_xr) {
- bool hand_tracking_enabled = (int)(p_preset->get("xr_features/hand_tracking")) > XR_HAND_TRACKING_NONE;
- if (hand_tracking_enabled) {
- int hand_tracking_frequency_index = p_preset->get("xr_features/hand_tracking_frequency");
- String hand_tracking_frequency = hand_tracking_frequency_index == XR_HAND_TRACKING_FREQUENCY_LOW ? "LOW" : "HIGH";
- manifest_application_text += vformat(
- " <meta-data tools:node=\"replace\" android:name=\"com.oculus.handtracking.frequency\" android:value=\"%s\" />\n",
- hand_tracking_frequency);
- manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.oculus.handtracking.version\" android:value=\"V2.0\" />\n";
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ if (export_plugins[i]->supports_platform(p_export_platform)) {
+ const String contents = export_plugins[i]->get_android_manifest_application_element_contents(p_export_platform, p_debug);
+ if (!contents.is_empty()) {
+ manifest_application_text += contents;
+ manifest_application_text += "\n";
+ }
}
}
- manifest_application_text += _get_activity_tag(p_preset, uses_xr);
+
+ manifest_application_text += _get_activity_tag(p_export_platform, p_preset, p_debug);
manifest_application_text += " </application>\n";
return manifest_application_text;
}
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 8a885a0d12..2498394add 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -61,20 +61,6 @@ static const int APP_CATEGORY_VIDEO = 8;
static const int XR_MODE_REGULAR = 0;
static const int XR_MODE_OPENXR = 1;
-// Supported XR hand tracking modes.
-static const int XR_HAND_TRACKING_NONE = 0;
-static const int XR_HAND_TRACKING_OPTIONAL = 1;
-static const int XR_HAND_TRACKING_REQUIRED = 2;
-
-// Supported XR hand tracking frequencies.
-static const int XR_HAND_TRACKING_FREQUENCY_LOW = 0;
-static const int XR_HAND_TRACKING_FREQUENCY_HIGH = 1;
-
-// Supported XR passthrough modes.
-static const int XR_PASSTHROUGH_NONE = 0;
-static const int XR_PASSTHROUGH_OPTIONAL = 1;
-static const int XR_PASSTHROUGH_REQUIRED = 2;
-
struct CustomExportData {
String assets_directory;
bool debug;
@@ -116,10 +102,8 @@ String _get_gles_tag();
String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset);
-String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_vulkan);
-
-String _get_activity_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_xr);
+String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug);
-String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission);
+String _get_application_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission, bool p_debug);
#endif // ANDROID_GRADLE_EXPORT_UTIL_H
diff --git a/platform/android/java/app/src/com/godot/game/GodotApp.java b/platform/android/java/app/src/com/godot/game/GodotApp.java
index 1d2cc05715..9142d767b4 100644
--- a/platform/android/java/app/src/com/godot/game/GodotApp.java
+++ b/platform/android/java/app/src/com/godot/game/GodotApp.java
@@ -30,7 +30,7 @@
package com.godot.game;
-import org.godotengine.godot.FullScreenGodotApp;
+import org.godotengine.godot.GodotActivity;
import android.os.Bundle;
@@ -38,7 +38,7 @@ import android.os.Bundle;
* Template activity for Godot Android builds.
* Feel free to extend and modify this class for your custom logic.
*/
-public class GodotApp extends FullScreenGodotApp {
+public class GodotApp extends GodotActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(R.style.GodotAppMainTheme);
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
index 64d3d4eca1..7cedfa6888 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
@@ -39,7 +39,7 @@ import android.os.*
import android.util.Log
import android.widget.Toast
import androidx.window.layout.WindowMetricsCalculator
-import org.godotengine.godot.FullScreenGodotApp
+import org.godotengine.godot.GodotActivity
import org.godotengine.godot.GodotLib
import org.godotengine.godot.utils.PermissionsUtil
import org.godotengine.godot.utils.ProcessPhoenix
@@ -55,7 +55,7 @@ import kotlin.math.min
*
* It also plays the role of the primary editor window.
*/
-open class GodotEditor : FullScreenGodotApp() {
+open class GodotEditor : GodotActivity() {
companion object {
private val TAG = GodotEditor::class.java.simpleName
@@ -115,7 +115,7 @@ open class GodotEditor : FullScreenGodotApp() {
runOnUiThread {
// Enable long press, panning and scaling gestures
- godotFragment?.renderView?.inputHandler?.apply {
+ godotFragment?.godot?.renderView?.inputHandler?.apply {
enableLongPress(longPressEnabled)
enablePanningAndScalingGestures(panScaleEnabled)
}
@@ -318,7 +318,7 @@ open class GodotEditor : FullScreenGodotApp() {
override fun onRequestPermissionsResult(
requestCode: Int,
- permissions: Array<String?>,
+ permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
diff --git a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
index 3e975449d8..91d272735e 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
@@ -30,156 +30,10 @@
package org.godotengine.godot;
-import org.godotengine.godot.utils.ProcessPhoenix;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-
-import androidx.annotation.CallSuper;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-
/**
- * Base activity for Android apps intending to use Godot as the primary and only screen.
+ * Base abstract activity for Android apps intending to use Godot as the primary screen.
*
- * It's also a reference implementation for how to setup and use the {@link Godot} fragment
- * within an Android app.
+ * @deprecated Use {@link GodotActivity}
*/
-public abstract class FullScreenGodotApp extends FragmentActivity implements GodotHost {
- private static final String TAG = FullScreenGodotApp.class.getSimpleName();
-
- protected static final String EXTRA_FORCE_QUIT = "force_quit_requested";
- protected static final String EXTRA_NEW_LAUNCH = "new_launch_requested";
-
- @Nullable
- private Godot godotFragment;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.godot_app_layout);
-
- handleStartIntent(getIntent(), true);
-
- Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.godot_fragment_container);
- if (currentFragment instanceof Godot) {
- Log.v(TAG, "Reusing existing Godot fragment instance.");
- godotFragment = (Godot)currentFragment;
- } else {
- Log.v(TAG, "Creating new Godot fragment instance.");
- godotFragment = initGodotInstance();
- getSupportFragmentManager().beginTransaction().replace(R.id.godot_fragment_container, godotFragment).setPrimaryNavigationFragment(godotFragment).commitNowAllowingStateLoss();
- }
- }
-
- @Override
- public void onDestroy() {
- Log.v(TAG, "Destroying Godot app...");
- super.onDestroy();
- terminateGodotInstance(godotFragment);
- }
-
- @Override
- public final void onGodotForceQuit(Godot instance) {
- runOnUiThread(() -> {
- terminateGodotInstance(instance);
- });
- }
-
- private void terminateGodotInstance(Godot instance) {
- if (instance == godotFragment) {
- Log.v(TAG, "Force quitting Godot instance");
- ProcessPhoenix.forceQuit(FullScreenGodotApp.this);
- }
- }
-
- @Override
- public final void onGodotRestartRequested(Godot instance) {
- runOnUiThread(() -> {
- if (instance == godotFragment) {
- // It's very hard to properly de-initialize Godot on Android to restart the game
- // from scratch. Therefore, we need to kill the whole app process and relaunch it.
- //
- // Restarting only the activity, wouldn't be enough unless it did proper cleanup (including
- // releasing and reloading native libs or resetting their state somehow and clearing static data).
- Log.v(TAG, "Restarting Godot instance...");
- ProcessPhoenix.triggerRebirth(FullScreenGodotApp.this);
- }
- });
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- setIntent(intent);
-
- handleStartIntent(intent, false);
-
- if (godotFragment != null) {
- godotFragment.onNewIntent(intent);
- }
- }
-
- private void handleStartIntent(Intent intent, boolean newLaunch) {
- boolean forceQuitRequested = intent.getBooleanExtra(EXTRA_FORCE_QUIT, false);
- if (forceQuitRequested) {
- Log.d(TAG, "Force quit requested, terminating..");
- ProcessPhoenix.forceQuit(this);
- return;
- }
-
- if (!newLaunch) {
- boolean newLaunchRequested = intent.getBooleanExtra(EXTRA_NEW_LAUNCH, false);
- if (newLaunchRequested) {
- Log.d(TAG, "New launch requested, restarting..");
-
- Intent restartIntent = new Intent(intent).putExtra(EXTRA_NEW_LAUNCH, false);
- ProcessPhoenix.triggerRebirth(this, restartIntent);
- return;
- }
- }
- }
-
- @CallSuper
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (godotFragment != null) {
- godotFragment.onActivityResult(requestCode, resultCode, data);
- }
- }
-
- @CallSuper
- @Override
- public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- if (godotFragment != null) {
- godotFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
- }
- }
-
- @Override
- public void onBackPressed() {
- if (godotFragment != null) {
- godotFragment.onBackPressed();
- } else {
- super.onBackPressed();
- }
- }
-
- /**
- * Used to initialize the Godot fragment instance in {@link FullScreenGodotApp#onCreate(Bundle)}.
- */
- @NonNull
- protected Godot initGodotInstance() {
- return new Godot();
- }
-
- @Nullable
- protected final Godot getGodotFragment() {
- return godotFragment;
- }
-}
+@Deprecated
+public abstract class FullScreenGodotApp extends GodotActivity {}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
deleted file mode 100644
index 9f2dec7317..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ /dev/null
@@ -1,1195 +0,0 @@
-/**************************************************************************/
-/* Godot.java */
-/**************************************************************************/
-/* 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. */
-/**************************************************************************/
-
-package org.godotengine.godot;
-
-import static android.content.Context.MODE_PRIVATE;
-import static android.content.Context.WINDOW_SERVICE;
-
-import org.godotengine.godot.input.GodotEditText;
-import org.godotengine.godot.io.directory.DirectoryAccessHandler;
-import org.godotengine.godot.io.file.FileAccessHandler;
-import org.godotengine.godot.plugin.GodotPlugin;
-import org.godotengine.godot.plugin.GodotPluginRegistry;
-import org.godotengine.godot.tts.GodotTTS;
-import org.godotengine.godot.utils.BenchmarkUtils;
-import org.godotengine.godot.utils.GodotNetUtils;
-import org.godotengine.godot.utils.PermissionsUtil;
-import org.godotengine.godot.xr.XRMode;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.PendingIntent;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Messenger;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.util.Log;
-import android.view.Display;
-import android.view.LayoutInflater;
-import android.view.Surface;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.ViewTreeObserver;
-import android.view.Window;
-import android.view.WindowInsets;
-import android.view.WindowInsetsAnimation;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.annotation.CallSuper;
-import androidx.annotation.Keep;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-import androidx.fragment.app.Fragment;
-
-import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
-import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
-import com.google.android.vending.expansion.downloader.DownloaderServiceMarshaller;
-import com.google.android.vending.expansion.downloader.Helpers;
-import com.google.android.vending.expansion.downloader.IDownloaderClient;
-import com.google.android.vending.expansion.downloader.IDownloaderService;
-import com.google.android.vending.expansion.downloader.IStub;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.security.MessageDigest;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-
-public class Godot extends Fragment implements SensorEventListener, IDownloaderClient {
- private static final String TAG = Godot.class.getSimpleName();
-
- private IStub mDownloaderClientStub;
- private TextView mStatusText;
- private TextView mProgressFraction;
- private TextView mProgressPercent;
- private TextView mAverageSpeed;
- private TextView mTimeRemaining;
- private ProgressBar mPB;
- private ClipboardManager mClipboard;
-
- private View mDashboard;
- private View mCellMessage;
-
- private Button mPauseButton;
- private Button mWiFiSettingsButton;
-
- private XRMode xrMode = XRMode.REGULAR;
- private boolean use_immersive = false;
- private boolean use_debug_opengl = false;
- private boolean mStatePaused;
- private boolean activityResumed;
- private int mState;
-
- private GodotHost godotHost;
- private GodotPluginRegistry pluginRegistry;
-
- static private Intent mCurrentIntent;
-
- public void onNewIntent(Intent intent) {
- mCurrentIntent = intent;
- }
-
- static public Intent getCurrentIntent() {
- return mCurrentIntent;
- }
-
- private void setState(int newState) {
- if (mState != newState) {
- mState = newState;
- mStatusText.setText(Helpers.getDownloaderStringResourceIDFromState(newState));
- }
- }
-
- private void setButtonPausedState(boolean paused) {
- mStatePaused = paused;
- int stringResourceID = paused ? R.string.text_button_resume : R.string.text_button_pause;
- mPauseButton.setText(stringResourceID);
- }
-
- private String[] command_line;
- private boolean use_apk_expansion;
-
- private ViewGroup containerLayout;
- public GodotRenderView mRenderView;
- private boolean godot_initialized = false;
-
- private SensorManager mSensorManager;
- private Sensor mAccelerometer;
- private Sensor mGravity;
- private Sensor mMagnetometer;
- private Sensor mGyroscope;
-
- public GodotIO io;
- public GodotNetUtils netUtils;
- public GodotTTS tts;
- private DirectoryAccessHandler directoryAccessHandler;
- private FileAccessHandler fileAccessHandler;
-
- public interface ResultCallback {
- void callback(int requestCode, int resultCode, Intent data);
- }
- public ResultCallback result_callback;
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (getParentFragment() instanceof GodotHost) {
- godotHost = (GodotHost)getParentFragment();
- } else if (getActivity() instanceof GodotHost) {
- godotHost = (GodotHost)getActivity();
- }
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- godotHost = null;
- }
-
- @CallSuper
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (result_callback != null) {
- result_callback.callback(requestCode, resultCode, data);
- result_callback = null;
- }
-
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onMainActivityResult(requestCode, resultCode, data);
- }
- }
-
- @CallSuper
- @Override
- public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onMainRequestPermissionsResult(requestCode, permissions, grantResults);
- }
-
- for (int i = 0; i < permissions.length; i++) {
- GodotLib.requestPermissionResult(permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED);
- }
- }
-
- /**
- * Invoked on the render thread when the Godot setup is complete.
- */
- @CallSuper
- protected void onGodotSetupCompleted() {
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onGodotSetupCompleted();
- }
-
- if (godotHost != null) {
- godotHost.onGodotSetupCompleted();
- }
- }
-
- /**
- * Invoked on the render thread when the Godot main loop has started.
- */
- @CallSuper
- protected void onGodotMainLoopStarted() {
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onGodotMainLoopStarted();
- }
-
- if (godotHost != null) {
- godotHost.onGodotMainLoopStarted();
- }
- }
-
- /**
- * Used by the native code (java_godot_lib_jni.cpp) to complete initialization of the GLSurfaceView view and renderer.
- */
- @Keep
- private boolean onVideoInit() {
- final Activity activity = requireActivity();
- containerLayout = new FrameLayout(activity);
- containerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-
- // GodotEditText layout
- GodotEditText editText = new GodotEditText(activity);
- editText.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
- (int)getResources().getDimension(R.dimen.text_edit_height)));
- // ...add to FrameLayout
- containerLayout.addView(editText);
-
- tts = new GodotTTS(activity);
-
- if (!GodotLib.setup(command_line, tts)) {
- Log.e(TAG, "Unable to setup the Godot engine! Aborting...");
- alert(R.string.error_engine_setup_message, R.string.text_error_title, this::forceQuit);
- return false;
- }
-
- if (usesVulkan()) {
- if (!meetsVulkanRequirements(activity.getPackageManager())) {
- alert(R.string.error_missing_vulkan_requirements_message, R.string.text_error_title, this::forceQuit);
- return false;
- }
- mRenderView = new GodotVulkanRenderView(activity, this);
- } else {
- // Fallback to openGl
- mRenderView = new GodotGLRenderView(activity, this, xrMode, use_debug_opengl);
- }
-
- View view = mRenderView.getView();
- containerLayout.addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- editText.setView(mRenderView);
- io.setEdit(editText);
-
- // Listeners for keyboard height.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- // Report the height of virtual keyboard as it changes during the animation.
- final View decorView = activity.getWindow().getDecorView();
- decorView.setWindowInsetsAnimationCallback(new WindowInsetsAnimation.Callback(WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP) {
- int startBottom, endBottom;
- @Override
- public void onPrepare(@NonNull WindowInsetsAnimation animation) {
- startBottom = decorView.getRootWindowInsets().getInsets(WindowInsets.Type.ime()).bottom;
- }
-
- @NonNull
- @Override
- public WindowInsetsAnimation.Bounds onStart(@NonNull WindowInsetsAnimation animation, @NonNull WindowInsetsAnimation.Bounds bounds) {
- endBottom = decorView.getRootWindowInsets().getInsets(WindowInsets.Type.ime()).bottom;
- return bounds;
- }
-
- @NonNull
- @Override
- public WindowInsets onProgress(@NonNull WindowInsets windowInsets, @NonNull List<WindowInsetsAnimation> list) {
- // Find the IME animation.
- WindowInsetsAnimation imeAnimation = null;
- for (WindowInsetsAnimation animation : list) {
- if ((animation.getTypeMask() & WindowInsets.Type.ime()) != 0) {
- imeAnimation = animation;
- break;
- }
- }
- // Update keyboard height based on IME animation.
- if (imeAnimation != null) {
- float interpolatedFraction = imeAnimation.getInterpolatedFraction();
- // Linear interpolation between start and end values.
- float keyboardHeight = startBottom * (1.0f - interpolatedFraction) + endBottom * interpolatedFraction;
- GodotLib.setVirtualKeyboardHeight((int)keyboardHeight);
- }
- return windowInsets;
- }
-
- @Override
- public void onEnd(@NonNull WindowInsetsAnimation animation) {
- }
- });
- } else {
- // Infer the virtual keyboard height using visible area.
- view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- // Don't allocate a new Rect every time the callback is called.
- final Rect visibleSize = new Rect();
-
- @Override
- public void onGlobalLayout() {
- final SurfaceView view = mRenderView.getView();
- view.getWindowVisibleDisplayFrame(visibleSize);
- final int keyboardHeight = view.getHeight() - visibleSize.bottom;
- GodotLib.setVirtualKeyboardHeight(keyboardHeight);
- }
- });
- }
-
- mRenderView.queueOnRenderThread(() -> {
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onRegisterPluginWithGodotNative();
- }
- setKeepScreenOn(Boolean.parseBoolean(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")));
- });
-
- // Include the returned non-null views in the Godot view hierarchy.
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- View pluginView = plugin.onMainCreate(activity);
- if (pluginView != null) {
- if (plugin.shouldBeOnTop()) {
- containerLayout.addView(pluginView);
- } else {
- containerLayout.addView(pluginView, 0);
- }
- }
- }
- return true;
- }
-
- /**
- * Returns true if `Vulkan` is used for rendering.
- */
- private boolean usesVulkan() {
- final String renderer = GodotLib.getGlobal("rendering/renderer/rendering_method");
- final String renderingDevice = GodotLib.getGlobal("rendering/rendering_device/driver");
- return ("forward_plus".equals(renderer) || "mobile".equals(renderer)) && "vulkan".equals(renderingDevice);
- }
-
- /**
- * Returns true if the device meets the base requirements for Vulkan support, false otherwise.
- */
- private boolean meetsVulkanRequirements(@Nullable PackageManager packageManager) {
- if (packageManager == null) {
- return false;
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- if (!packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 1)) {
- // Optional requirements.. log as warning if missing
- Log.w(TAG, "The vulkan hardware level does not meet the minimum requirement: 1");
- }
-
- // Check for api version 1.0
- return packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x400003);
- }
-
- return false;
- }
-
- public void setKeepScreenOn(final boolean p_enabled) {
- runOnUiThread(() -> {
- if (p_enabled) {
- getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- } else {
- getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
- });
- }
-
- /**
- * Used by the native code (java_godot_wrapper.h) to vibrate the device.
- * @param durationMs
- */
- @SuppressLint("MissingPermission")
- @Keep
- private void vibrate(int durationMs) {
- if (durationMs > 0 && requestPermission("VIBRATE")) {
- Vibrator v = (Vibrator)getContext().getSystemService(Context.VIBRATOR_SERVICE);
- if (v != null) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- v.vibrate(VibrationEffect.createOneShot(durationMs, VibrationEffect.DEFAULT_AMPLITUDE));
- } else {
- // deprecated in API 26
- v.vibrate(durationMs);
- }
- }
- }
- }
-
- public void restart() {
- if (godotHost != null) {
- godotHost.onGodotRestartRequested(this);
- }
- }
-
- public void alert(final String message, final String title) {
- alert(message, title, null);
- }
-
- private void alert(@StringRes int messageResId, @StringRes int titleResId, @Nullable Runnable okCallback) {
- Resources res = getResources();
- alert(res.getString(messageResId), res.getString(titleResId), okCallback);
- }
-
- private void alert(final String message, final String title, @Nullable Runnable okCallback) {
- final Activity activity = getActivity();
- runOnUiThread(() -> {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setMessage(message).setTitle(title);
- builder.setPositiveButton(
- "OK",
- (dialog, id) -> {
- if (okCallback != null) {
- okCallback.run();
- }
- dialog.cancel();
- });
- AlertDialog dialog = builder.create();
- dialog.show();
- });
- }
-
- public int getGLESVersionCode() {
- ActivityManager am = (ActivityManager)getContext().getSystemService(Context.ACTIVITY_SERVICE);
- ConfigurationInfo deviceInfo = am.getDeviceConfigurationInfo();
- return deviceInfo.reqGlEsVersion;
- }
-
- @CallSuper
- protected String[] getCommandLine() {
- String[] original = parseCommandLine();
- String[] updated;
- List<String> hostCommandLine = godotHost != null ? godotHost.getCommandLine() : null;
- if (hostCommandLine == null || hostCommandLine.isEmpty()) {
- updated = original;
- } else {
- updated = Arrays.copyOf(original, original.length + hostCommandLine.size());
- for (int i = 0; i < hostCommandLine.size(); i++) {
- updated[original.length + i] = hostCommandLine.get(i);
- }
- }
- return updated;
- }
-
- private String[] parseCommandLine() {
- InputStream is;
- try {
- is = getActivity().getAssets().open("_cl_");
- byte[] len = new byte[4];
- int r = is.read(len);
- if (r < 4) {
- return new String[0];
- }
- int argc = ((int)(len[3] & 0xFF) << 24) | ((int)(len[2] & 0xFF) << 16) | ((int)(len[1] & 0xFF) << 8) | ((int)(len[0] & 0xFF));
- String[] cmdline = new String[argc];
-
- for (int i = 0; i < argc; i++) {
- r = is.read(len);
- if (r < 4) {
- return new String[0];
- }
- int strlen = ((int)(len[3] & 0xFF) << 24) | ((int)(len[2] & 0xFF) << 16) | ((int)(len[1] & 0xFF) << 8) | ((int)(len[0] & 0xFF));
- if (strlen > 65535) {
- return new String[0];
- }
- byte[] arg = new byte[strlen];
- r = is.read(arg);
- if (r == strlen) {
- cmdline[i] = new String(arg, "UTF-8");
- }
- }
- return cmdline;
- } catch (Exception e) {
- // The _cl_ file can be missing with no adverse effect
- return new String[0];
- }
- }
-
- /**
- * Used by the native code (java_godot_wrapper.h) to check whether the activity is resumed or paused.
- */
- @Keep
- private boolean isActivityResumed() {
- return activityResumed;
- }
-
- /**
- * Used by the native code (java_godot_wrapper.h) to access the Android surface.
- */
- @Keep
- private Surface getSurface() {
- return mRenderView.getView().getHolder().getSurface();
- }
-
- /**
- * Used by the native code (java_godot_wrapper.h) to access the input fallback mapping.
- * @return The input fallback mapping for the current XR mode.
- */
- @Keep
- private String getInputFallbackMapping() {
- return xrMode.inputFallbackMapping;
- }
-
- String expansion_pack_path;
-
- private void initializeGodot() {
- if (expansion_pack_path != null) {
- String[] new_cmdline;
- int cll = 0;
- if (command_line != null) {
- new_cmdline = new String[command_line.length + 2];
- cll = command_line.length;
- for (int i = 0; i < command_line.length; i++) {
- new_cmdline[i] = command_line[i];
- }
- } else {
- new_cmdline = new String[2];
- }
-
- new_cmdline[cll] = "--main-pack";
- new_cmdline[cll + 1] = expansion_pack_path;
- command_line = new_cmdline;
- }
-
- final Activity activity = getActivity();
- io = new GodotIO(activity);
- netUtils = new GodotNetUtils(activity);
- Context context = getContext();
- directoryAccessHandler = new DirectoryAccessHandler(context);
- fileAccessHandler = new FileAccessHandler(context);
- mSensorManager = (SensorManager)activity.getSystemService(Context.SENSOR_SERVICE);
- mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- mGravity = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
- mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
- mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
-
- godot_initialized = GodotLib.initialize(activity,
- this,
- activity.getAssets(),
- io,
- netUtils,
- directoryAccessHandler,
- fileAccessHandler,
- use_apk_expansion);
-
- result_callback = null;
- }
-
- @Override
- public void onServiceConnected(Messenger m) {
- IDownloaderService remoteService = DownloaderServiceMarshaller.CreateProxy(m);
- remoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- BenchmarkUtils.beginBenchmarkMeasure("Godot::onCreate");
- super.onCreate(icicle);
-
- final Activity activity = getActivity();
- Window window = activity.getWindow();
- window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
- mClipboard = (ClipboardManager)activity.getSystemService(Context.CLIPBOARD_SERVICE);
- pluginRegistry = GodotPluginRegistry.initializePluginRegistry(this);
-
- // check for apk expansion API
- boolean md5mismatch = false;
- command_line = getCommandLine();
- String main_pack_md5 = null;
- String main_pack_key = null;
-
- List<String> new_args = new LinkedList<>();
-
- for (int i = 0; i < command_line.length; i++) {
- boolean has_extra = i < command_line.length - 1;
- if (command_line[i].equals(XRMode.REGULAR.cmdLineArg)) {
- xrMode = XRMode.REGULAR;
- } else if (command_line[i].equals(XRMode.OPENXR.cmdLineArg)) {
- xrMode = XRMode.OPENXR;
- } else if (command_line[i].equals("--debug_opengl")) {
- use_debug_opengl = true;
- } else if (command_line[i].equals("--use_immersive")) {
- use_immersive = true;
- window.getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | // hide nav bar
- View.SYSTEM_UI_FLAG_FULLSCREEN | // hide status bar
- View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
- UiChangeListener();
- } else if (command_line[i].equals("--use_apk_expansion")) {
- use_apk_expansion = true;
- } else if (has_extra && command_line[i].equals("--apk_expansion_md5")) {
- main_pack_md5 = command_line[i + 1];
- i++;
- } else if (has_extra && command_line[i].equals("--apk_expansion_key")) {
- main_pack_key = command_line[i + 1];
- SharedPreferences prefs = activity.getSharedPreferences("app_data_keys",
- MODE_PRIVATE);
- Editor editor = prefs.edit();
- editor.putString("store_public_key", main_pack_key);
-
- editor.apply();
- i++;
- } else if (command_line[i].equals("--benchmark")) {
- BenchmarkUtils.setUseBenchmark(true);
- new_args.add(command_line[i]);
- } else if (has_extra && command_line[i].equals("--benchmark-file")) {
- BenchmarkUtils.setUseBenchmark(true);
- new_args.add(command_line[i]);
-
- // Retrieve the filepath
- BenchmarkUtils.setBenchmarkFile(command_line[i + 1]);
- new_args.add(command_line[i + 1]);
-
- i++;
- } else if (command_line[i].trim().length() != 0) {
- new_args.add(command_line[i]);
- }
- }
-
- if (new_args.isEmpty()) {
- command_line = null;
- } else {
- command_line = new_args.toArray(new String[new_args.size()]);
- }
- if (use_apk_expansion && main_pack_md5 != null && main_pack_key != null) {
- // check that environment is ok!
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- // show popup and die
- }
-
- // Build the full path to the app's expansion files
- try {
- expansion_pack_path = Helpers.getSaveFilePath(getContext());
- expansion_pack_path += "/main." + activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode + "." + activity.getPackageName() + ".obb";
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- File f = new File(expansion_pack_path);
-
- boolean pack_valid = true;
-
- if (!f.exists()) {
- pack_valid = false;
-
- } else if (obbIsCorrupted(expansion_pack_path, main_pack_md5)) {
- pack_valid = false;
- try {
- f.delete();
- } catch (Exception e) {
- }
- }
-
- if (!pack_valid) {
- Intent notifierIntent = new Intent(activity, activity.getClass());
- notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-
- PendingIntent pendingIntent;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- pendingIntent = PendingIntent.getActivity(activity, 0,
- notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- } else {
- pendingIntent = PendingIntent.getActivity(activity, 0,
- notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- }
-
- int startResult;
- try {
- startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(
- getContext(),
- pendingIntent,
- GodotDownloaderService.class);
-
- if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
- // This is where you do set up to display the download
- // progress (next step in onCreateView)
- mDownloaderClientStub = DownloaderClientMarshaller.CreateStub(this,
- GodotDownloaderService.class);
-
- return;
- }
- } catch (NameNotFoundException e) {
- // TODO Auto-generated catch block
- }
- }
- }
-
- mCurrentIntent = activity.getIntent();
-
- initializeGodot();
- BenchmarkUtils.endBenchmarkMeasure("Godot::onCreate");
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle) {
- if (mDownloaderClientStub != null) {
- View downloadingExpansionView =
- inflater.inflate(R.layout.downloading_expansion, container, false);
- mPB = (ProgressBar)downloadingExpansionView.findViewById(R.id.progressBar);
- mStatusText = (TextView)downloadingExpansionView.findViewById(R.id.statusText);
- mProgressFraction = (TextView)downloadingExpansionView.findViewById(R.id.progressAsFraction);
- mProgressPercent = (TextView)downloadingExpansionView.findViewById(R.id.progressAsPercentage);
- mAverageSpeed = (TextView)downloadingExpansionView.findViewById(R.id.progressAverageSpeed);
- mTimeRemaining = (TextView)downloadingExpansionView.findViewById(R.id.progressTimeRemaining);
- mDashboard = downloadingExpansionView.findViewById(R.id.downloaderDashboard);
- mCellMessage = downloadingExpansionView.findViewById(R.id.approveCellular);
- mPauseButton = (Button)downloadingExpansionView.findViewById(R.id.pauseButton);
- mWiFiSettingsButton = (Button)downloadingExpansionView.findViewById(R.id.wifiSettingsButton);
-
- return downloadingExpansionView;
- }
-
- return containerLayout;
- }
-
- @Override
- public void onDestroy() {
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onMainDestroy();
- }
-
- GodotLib.ondestroy();
-
- super.onDestroy();
-
- forceQuit();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- activityResumed = false;
-
- if (!godot_initialized) {
- if (null != mDownloaderClientStub) {
- mDownloaderClientStub.disconnect(getActivity());
- }
- return;
- }
- mRenderView.onActivityPaused();
-
- mSensorManager.unregisterListener(this);
-
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onMainPause();
- }
- }
-
- public boolean hasClipboard() {
- return mClipboard.hasPrimaryClip();
- }
-
- public String getClipboard() {
- ClipData clipData = mClipboard.getPrimaryClip();
- if (clipData == null)
- return "";
- CharSequence text = clipData.getItemAt(0).getText();
- if (text == null)
- return "";
- return text.toString();
- }
-
- public void setClipboard(String p_text) {
- ClipData clip = ClipData.newPlainText("myLabel", p_text);
- mClipboard.setPrimaryClip(clip);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- activityResumed = true;
- if (!godot_initialized) {
- if (null != mDownloaderClientStub) {
- mDownloaderClientStub.connect(getActivity());
- }
- return;
- }
-
- mRenderView.onActivityResumed();
-
- mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
- mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME);
- mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
- mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME);
-
- if (use_immersive) {
- Window window = getActivity().getWindow();
- window.getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | // hide nav bar
- View.SYSTEM_UI_FLAG_FULLSCREEN | // hide status bar
- View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
- }
-
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onMainResume();
- }
- }
-
- public void UiChangeListener() {
- final View decorView = getActivity().getWindow().getDecorView();
- decorView.setOnSystemUiVisibilityChangeListener(visibility -> {
- if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
- decorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
- }
- });
- }
-
- public float[] getRotatedValues(float values[]) {
- if (values == null || values.length != 3) {
- return values;
- }
-
- Display display =
- ((WindowManager)getActivity().getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
- int displayRotation = display.getRotation();
-
- float[] rotatedValues = new float[3];
- switch (displayRotation) {
- case Surface.ROTATION_0:
- rotatedValues[0] = values[0];
- rotatedValues[1] = values[1];
- rotatedValues[2] = values[2];
- break;
- case Surface.ROTATION_90:
- rotatedValues[0] = -values[1];
- rotatedValues[1] = values[0];
- rotatedValues[2] = values[2];
- break;
- case Surface.ROTATION_180:
- rotatedValues[0] = -values[0];
- rotatedValues[1] = -values[1];
- rotatedValues[2] = values[2];
- break;
- case Surface.ROTATION_270:
- rotatedValues[0] = values[1];
- rotatedValues[1] = -values[0];
- rotatedValues[2] = values[2];
- break;
- }
-
- return rotatedValues;
- }
-
- @Override
- public void onSensorChanged(SensorEvent event) {
- if (mRenderView == null) {
- return;
- }
-
- final int typeOfSensor = event.sensor.getType();
- switch (typeOfSensor) {
- case Sensor.TYPE_ACCELEROMETER: {
- float[] rotatedValues = getRotatedValues(event.values);
- mRenderView.queueOnRenderThread(() -> {
- GodotLib.accelerometer(-rotatedValues[0], -rotatedValues[1], -rotatedValues[2]);
- });
- break;
- }
- case Sensor.TYPE_GRAVITY: {
- float[] rotatedValues = getRotatedValues(event.values);
- mRenderView.queueOnRenderThread(() -> {
- GodotLib.gravity(-rotatedValues[0], -rotatedValues[1], -rotatedValues[2]);
- });
- break;
- }
- case Sensor.TYPE_MAGNETIC_FIELD: {
- float[] rotatedValues = getRotatedValues(event.values);
- mRenderView.queueOnRenderThread(() -> {
- GodotLib.magnetometer(-rotatedValues[0], -rotatedValues[1], -rotatedValues[2]);
- });
- break;
- }
- case Sensor.TYPE_GYROSCOPE: {
- float[] rotatedValues = getRotatedValues(event.values);
- mRenderView.queueOnRenderThread(() -> {
- GodotLib.gyroscope(rotatedValues[0], rotatedValues[1], rotatedValues[2]);
- });
- break;
- }
- }
- }
-
- @Override
- public final void onAccuracyChanged(Sensor sensor, int accuracy) {
- // Do something here if sensor accuracy changes.
- }
-
- public void onBackPressed() {
- boolean shouldQuit = true;
-
- for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- if (plugin.onMainBackPressed()) {
- shouldQuit = false;
- }
- }
-
- if (shouldQuit && mRenderView != null) {
- mRenderView.queueOnRenderThread(GodotLib::back);
- }
- }
-
- /**
- * Queue a runnable to be run on the render thread.
- * <p>
- * This must be called after the render thread has started.
- */
- public final void runOnRenderThread(@NonNull Runnable action) {
- if (mRenderView != null) {
- mRenderView.queueOnRenderThread(action);
- }
- }
-
- public final void runOnUiThread(@NonNull Runnable action) {
- if (getActivity() != null) {
- getActivity().runOnUiThread(action);
- }
- }
-
- private void forceQuit() {
- // TODO: This is a temp solution. The proper fix will involve tracking down and properly shutting down each
- // native Godot components that is started in Godot#onVideoInit.
- forceQuit(0);
- }
-
- @Keep
- private boolean forceQuit(int instanceId) {
- if (godotHost == null) {
- return false;
- }
- if (instanceId == 0) {
- godotHost.onGodotForceQuit(this);
- return true;
- } else {
- return godotHost.onGodotForceQuit(instanceId);
- }
- }
-
- private boolean obbIsCorrupted(String f, String main_pack_md5) {
- try {
- InputStream fis = new FileInputStream(f);
-
- // Create MD5 Hash
- byte[] buffer = new byte[16384];
-
- MessageDigest complete = MessageDigest.getInstance("MD5");
- int numRead;
- do {
- numRead = fis.read(buffer);
- if (numRead > 0) {
- complete.update(buffer, 0, numRead);
- }
- } while (numRead != -1);
-
- fis.close();
- byte[] messageDigest = complete.digest();
-
- // Create Hex String
- StringBuilder hexString = new StringBuilder();
- for (byte b : messageDigest) {
- String s = Integer.toHexString(0xFF & b);
- if (s.length() == 1) {
- s = "0" + s;
- }
- hexString.append(s);
- }
- String md5str = hexString.toString();
-
- if (!md5str.equals(main_pack_md5)) {
- return true;
- }
- return false;
- } catch (Exception e) {
- e.printStackTrace();
- return true;
- }
- }
-
- public boolean requestPermission(String p_name) {
- return PermissionsUtil.requestPermission(p_name, getActivity());
- }
-
- public boolean requestPermissions() {
- return PermissionsUtil.requestManifestPermissions(getActivity());
- }
-
- public String[] getGrantedPermissions() {
- return PermissionsUtil.getGrantedPermissions(getActivity());
- }
-
- @Keep
- private String getCACertificates() {
- return GodotNetUtils.getCACertificates();
- }
-
- /**
- * The download state should trigger changes in the UI --- it may be useful
- * to show the state as being indeterminate at times. This sample can be
- * considered a guideline.
- */
- @Override
- public void onDownloadStateChanged(int newState) {
- setState(newState);
- boolean showDashboard = true;
- boolean showCellMessage = false;
- boolean paused;
- boolean indeterminate;
- switch (newState) {
- case IDownloaderClient.STATE_IDLE:
- // STATE_IDLE means the service is listening, so it's
- // safe to start making remote service calls.
- paused = false;
- indeterminate = true;
- break;
- case IDownloaderClient.STATE_CONNECTING:
- case IDownloaderClient.STATE_FETCHING_URL:
- showDashboard = true;
- paused = false;
- indeterminate = true;
- break;
- case IDownloaderClient.STATE_DOWNLOADING:
- paused = false;
- showDashboard = true;
- indeterminate = false;
- break;
-
- case IDownloaderClient.STATE_FAILED_CANCELED:
- case IDownloaderClient.STATE_FAILED:
- case IDownloaderClient.STATE_FAILED_FETCHING_URL:
- case IDownloaderClient.STATE_FAILED_UNLICENSED:
- paused = true;
- showDashboard = false;
- indeterminate = false;
- break;
- case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION:
- case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION:
- showDashboard = false;
- paused = true;
- indeterminate = false;
- showCellMessage = true;
- break;
-
- case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
- paused = true;
- indeterminate = false;
- break;
- case IDownloaderClient.STATE_PAUSED_ROAMING:
- case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE:
- paused = true;
- indeterminate = false;
- break;
- case IDownloaderClient.STATE_COMPLETED:
- showDashboard = false;
- paused = false;
- indeterminate = false;
- initializeGodot();
- return;
- default:
- paused = true;
- indeterminate = true;
- showDashboard = true;
- }
- int newDashboardVisibility = showDashboard ? View.VISIBLE : View.GONE;
- if (mDashboard.getVisibility() != newDashboardVisibility) {
- mDashboard.setVisibility(newDashboardVisibility);
- }
- int cellMessageVisibility = showCellMessage ? View.VISIBLE : View.GONE;
- if (mCellMessage.getVisibility() != cellMessageVisibility) {
- mCellMessage.setVisibility(cellMessageVisibility);
- }
-
- mPB.setIndeterminate(indeterminate);
- setButtonPausedState(paused);
- }
-
- @Override
- public void onDownloadProgress(DownloadProgressInfo progress) {
- mAverageSpeed.setText(getString(R.string.kilobytes_per_second,
- Helpers.getSpeedString(progress.mCurrentSpeed)));
- mTimeRemaining.setText(getString(R.string.time_remaining,
- Helpers.getTimeRemaining(progress.mTimeRemaining)));
-
- mPB.setMax((int)(progress.mOverallTotal >> 8));
- mPB.setProgress((int)(progress.mOverallProgress >> 8));
- mProgressPercent.setText(String.format(Locale.ENGLISH, "%d %%", progress.mOverallProgress * 100 / progress.mOverallTotal));
- mProgressFraction.setText(Helpers.getDownloadProgressString(progress.mOverallProgress,
- progress.mOverallTotal));
- }
-
- public void initInputDevices() {
- mRenderView.initInputDevices();
- }
-
- @Keep
- public GodotRenderView getRenderView() { // used by native side to get renderView
- return mRenderView;
- }
-
- @Keep
- public DirectoryAccessHandler getDirectoryAccessHandler() {
- return directoryAccessHandler;
- }
-
- @Keep
- public FileAccessHandler getFileAccessHandler() {
- return fileAccessHandler;
- }
-
- @Keep
- private int createNewGodotInstance(String[] args) {
- if (godotHost != null) {
- return godotHost.onNewGodotInstanceRequested(args);
- }
- return 0;
- }
-
- @Keep
- private void beginBenchmarkMeasure(String label) {
- BenchmarkUtils.beginBenchmarkMeasure(label);
- }
-
- @Keep
- private void endBenchmarkMeasure(String label) {
- BenchmarkUtils.endBenchmarkMeasure(label);
- }
-
- @Keep
- private void dumpBenchmark(String benchmarkFile) {
- BenchmarkUtils.dumpBenchmark(fileAccessHandler, benchmarkFile);
- }
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
new file mode 100644
index 0000000000..23de01a191
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
@@ -0,0 +1,965 @@
+/**************************************************************************/
+/* Godot.kt */
+/**************************************************************************/
+/* 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. */
+/**************************************************************************/
+
+package org.godotengine.godot
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.app.AlertDialog
+import android.content.*
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import android.graphics.Rect
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.os.*
+import android.util.Log
+import android.view.*
+import android.view.ViewTreeObserver.OnGlobalLayoutListener
+import android.widget.FrameLayout
+import androidx.annotation.Keep
+import androidx.annotation.StringRes
+import com.google.android.vending.expansion.downloader.*
+import org.godotengine.godot.input.GodotEditText
+import org.godotengine.godot.io.directory.DirectoryAccessHandler
+import org.godotengine.godot.io.file.FileAccessHandler
+import org.godotengine.godot.plugin.GodotPluginRegistry
+import org.godotengine.godot.tts.GodotTTS
+import org.godotengine.godot.utils.GodotNetUtils
+import org.godotengine.godot.utils.PermissionsUtil
+import org.godotengine.godot.utils.PermissionsUtil.requestPermission
+import org.godotengine.godot.utils.beginBenchmarkMeasure
+import org.godotengine.godot.utils.benchmarkFile
+import org.godotengine.godot.utils.dumpBenchmark
+import org.godotengine.godot.utils.endBenchmarkMeasure
+import org.godotengine.godot.utils.useBenchmark
+import org.godotengine.godot.xr.XRMode
+import java.io.File
+import java.io.FileInputStream
+import java.io.InputStream
+import java.nio.charset.StandardCharsets
+import java.security.MessageDigest
+import java.util.*
+
+/**
+ * Core component used to interface with the native layer of the engine.
+ *
+ * Can be hosted by [Activity], [Fragment] or [Service] android components, so long as its
+ * lifecycle methods are properly invoked.
+ */
+class Godot(private val context: Context) : SensorEventListener {
+
+ private companion object {
+ private val TAG = Godot::class.java.simpleName
+ }
+
+ private val pluginRegistry: GodotPluginRegistry by lazy {
+ GodotPluginRegistry.initializePluginRegistry(this)
+ }
+ private val mSensorManager: SensorManager by lazy {
+ requireActivity().getSystemService(Context.SENSOR_SERVICE) as SensorManager
+ }
+ private val mAccelerometer: Sensor by lazy {
+ mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
+ }
+ private val mGravity: Sensor by lazy {
+ mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)
+ }
+ private val mMagnetometer: Sensor by lazy {
+ mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
+ }
+ private val mGyroscope: Sensor by lazy {
+ mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
+ }
+ private val mClipboard: ClipboardManager by lazy {
+ requireActivity().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ }
+
+ private val uiChangeListener = View.OnSystemUiVisibilityChangeListener { visibility: Int ->
+ if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
+ val decorView = requireActivity().window.decorView
+ decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
+ View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ }}
+
+ val tts = GodotTTS(context)
+ val directoryAccessHandler = DirectoryAccessHandler(context)
+ val fileAccessHandler = FileAccessHandler(context)
+ val netUtils = GodotNetUtils(context)
+
+ /**
+ * Tracks whether [onCreate] was completed successfully.
+ */
+ private var initializationStarted = false
+
+ /**
+ * Tracks whether [GodotLib.initialize] was completed successfully.
+ */
+ private var nativeLayerInitializeCompleted = false
+
+ /**
+ * Tracks whether [GodotLib.setup] was completed successfully.
+ */
+ private var nativeLayerSetupCompleted = false
+
+ /**
+ * Tracks whether [onInitRenderView] was completed successfully.
+ */
+ private var renderViewInitialized = false
+ private var primaryHost: GodotHost? = null
+
+ var io: GodotIO? = null
+
+ private var commandLine : MutableList<String> = ArrayList<String>()
+ private var xrMode = XRMode.REGULAR
+ private var expansionPackPath: String = ""
+ private var useApkExpansion = false
+ private var useImmersive = false
+ private var useDebugOpengl = false
+
+ private var containerLayout: FrameLayout? = null
+ var renderView: GodotRenderView? = null
+
+ /**
+ * Returns true if the native engine has been initialized through [onInitNativeLayer], false otherwise.
+ */
+ private fun isNativeInitialized() = nativeLayerInitializeCompleted && nativeLayerSetupCompleted
+
+ /**
+ * Returns true if the engine has been initialized, false otherwise.
+ */
+ fun isInitialized() = initializationStarted && isNativeInitialized() && renderViewInitialized
+
+ /**
+ * Provides access to the primary host [Activity]
+ */
+ fun getActivity() = primaryHost?.activity
+ private fun requireActivity() = getActivity() ?: throw IllegalStateException("Host activity must be non-null")
+
+ /**
+ * Start initialization of the Godot engine.
+ *
+ * This must be followed by [onInitNativeLayer] and [onInitRenderView] in that order to complete
+ * initialization of the engine.
+ *
+ * @throws IllegalArgumentException exception if the specified expansion pack (if any)
+ * is invalid.
+ */
+ fun onCreate(primaryHost: GodotHost) {
+ if (this.primaryHost != null || initializationStarted) {
+ Log.d(TAG, "OnCreate already invoked")
+ return
+ }
+
+ beginBenchmarkMeasure("Godot::onCreate")
+ try {
+ this.primaryHost = primaryHost
+ val activity = requireActivity()
+ val window = activity.window
+ window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
+ GodotPluginRegistry.initializePluginRegistry(this)
+ if (io == null) {
+ io = GodotIO(activity)
+ }
+
+ // check for apk expansion API
+ commandLine = getCommandLine()
+ var mainPackMd5: String? = null
+ var mainPackKey: String? = null
+ val newArgs: MutableList<String> = ArrayList()
+ var i = 0
+ while (i < commandLine.size) {
+ val hasExtra: Boolean = i < commandLine.size - 1
+ if (commandLine[i] == XRMode.REGULAR.cmdLineArg) {
+ xrMode = XRMode.REGULAR
+ } else if (commandLine[i] == XRMode.OPENXR.cmdLineArg) {
+ xrMode = XRMode.OPENXR
+ } else if (commandLine[i] == "--debug_opengl") {
+ useDebugOpengl = true
+ } else if (commandLine[i] == "--use_immersive") {
+ useImmersive = true
+ window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or // hide nav bar
+ View.SYSTEM_UI_FLAG_FULLSCREEN or // hide status bar
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ registerUiChangeListener()
+ } else if (commandLine[i] == "--use_apk_expansion") {
+ useApkExpansion = true
+ } else if (hasExtra && commandLine[i] == "--apk_expansion_md5") {
+ mainPackMd5 = commandLine[i + 1]
+ i++
+ } else if (hasExtra && commandLine[i] == "--apk_expansion_key") {
+ mainPackKey = commandLine[i + 1]
+ val prefs = activity.getSharedPreferences(
+ "app_data_keys",
+ Context.MODE_PRIVATE
+ )
+ val editor = prefs.edit()
+ editor.putString("store_public_key", mainPackKey)
+ editor.apply()
+ i++
+ } else if (commandLine[i] == "--benchmark") {
+ useBenchmark = true
+ newArgs.add(commandLine[i])
+ } else if (hasExtra && commandLine[i] == "--benchmark-file") {
+ useBenchmark = true
+ newArgs.add(commandLine[i])
+
+ // Retrieve the filepath
+ benchmarkFile = commandLine[i + 1]
+ newArgs.add(commandLine[i + 1])
+
+ i++
+ } else if (commandLine[i].trim().isNotEmpty()) {
+ newArgs.add(commandLine[i])
+ }
+ i++
+ }
+ if (newArgs.isEmpty()) {
+ commandLine = mutableListOf()
+ } else {
+ commandLine = newArgs
+ }
+ if (useApkExpansion && mainPackMd5 != null && mainPackKey != null) {
+ // Build the full path to the app's expansion files
+ try {
+ expansionPackPath = Helpers.getSaveFilePath(context)
+ expansionPackPath += "/main." + activity.packageManager.getPackageInfo(
+ activity.packageName,
+ 0
+ ).versionCode + "." + activity.packageName + ".obb"
+ } catch (e: java.lang.Exception) {
+ Log.e(TAG, "Unable to build full path to the app's expansion files", e)
+ }
+ val f = File(expansionPackPath)
+ var packValid = true
+ if (!f.exists()) {
+ packValid = false
+ } else if (obbIsCorrupted(expansionPackPath, mainPackMd5)) {
+ packValid = false
+ try {
+ f.delete()
+ } catch (_: java.lang.Exception) {
+ }
+ }
+ if (!packValid) {
+ // Aborting engine initialization
+ throw IllegalArgumentException("Invalid expansion pack")
+ }
+ }
+
+ initializationStarted = true
+ } catch (e: java.lang.Exception) {
+ // Clear the primary host and rethrow
+ this.primaryHost = null
+ initializationStarted = false
+ throw e
+ } finally {
+ endBenchmarkMeasure("Godot::onCreate");
+ }
+ }
+
+ /**
+ * Initializes the native layer of the Godot engine.
+ *
+ * This must be preceded by [onCreate] and followed by [onInitRenderView] to complete
+ * initialization of the engine.
+ *
+ * @return false if initialization of the native layer fails, true otherwise.
+ *
+ * @throws IllegalStateException if [onCreate] has not been called.
+ */
+ fun onInitNativeLayer(host: GodotHost): Boolean {
+ if (!initializationStarted) {
+ throw IllegalStateException("OnCreate must be invoked successfully prior to initializing the native layer")
+ }
+ if (isNativeInitialized()) {
+ Log.d(TAG, "OnInitNativeLayer already invoked")
+ return true
+ }
+ if (host != primaryHost) {
+ Log.e(TAG, "Native initialization is only supported for the primary host")
+ return false
+ }
+
+ if (expansionPackPath.isNotEmpty()) {
+ commandLine.add("--main-pack")
+ commandLine.add(expansionPackPath)
+ }
+ val activity = requireActivity()
+ if (!nativeLayerInitializeCompleted) {
+ nativeLayerInitializeCompleted = GodotLib.initialize(
+ activity,
+ this,
+ activity.assets,
+ io,
+ netUtils,
+ directoryAccessHandler,
+ fileAccessHandler,
+ useApkExpansion,
+ )
+ }
+
+ if (nativeLayerInitializeCompleted && !nativeLayerSetupCompleted) {
+ nativeLayerSetupCompleted = GodotLib.setup(commandLine.toTypedArray(), tts)
+ if (!nativeLayerSetupCompleted) {
+ Log.e(TAG, "Unable to setup the Godot engine! Aborting...")
+ alert(R.string.error_engine_setup_message, R.string.text_error_title, this::forceQuit)
+ }
+ }
+ return isNativeInitialized()
+ }
+
+ /**
+ * Used to complete initialization of the view used by the engine for rendering.
+ *
+ * This must be preceded by [onCreate] and [onInitNativeLayer] in that order to properly
+ * initialize the engine.
+ *
+ * @param host The [GodotHost] that's initializing the render views
+ * @param providedContainerLayout Optional argument; if provided, this is reused to host the Godot's render views
+ *
+ * @return A [FrameLayout] instance containing Godot's render views if initialization is successful, null otherwise.
+ *
+ * @throws IllegalStateException if [onInitNativeLayer] has not been called
+ */
+ @JvmOverloads
+ fun onInitRenderView(host: GodotHost, providedContainerLayout: FrameLayout = FrameLayout(host.activity)): FrameLayout? {
+ if (!isNativeInitialized()) {
+ throw IllegalStateException("onInitNativeLayer() must be invoked successfully prior to initializing the render view")
+ }
+
+ try {
+ val activity: Activity = host.activity
+ containerLayout = providedContainerLayout
+ containerLayout?.removeAllViews()
+ containerLayout?.layoutParams = ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+
+ // GodotEditText layout
+ val editText = GodotEditText(activity)
+ editText.layoutParams =
+ ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ activity.resources.getDimension(R.dimen.text_edit_height).toInt()
+ )
+ // ...add to FrameLayout
+ containerLayout?.addView(editText)
+ renderView = if (usesVulkan()) {
+ if (!meetsVulkanRequirements(activity.packageManager)) {
+ alert(R.string.error_missing_vulkan_requirements_message, R.string.text_error_title, this::forceQuit)
+ return null
+ }
+ GodotVulkanRenderView(host, this)
+ } else {
+ // Fallback to openGl
+ GodotGLRenderView(host, this, xrMode, useDebugOpengl)
+ }
+ if (host == primaryHost) {
+ renderView!!.startRenderer()
+ }
+ val view: View = renderView!!.view
+ containerLayout?.addView(
+ view,
+ ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ )
+ editText.setView(renderView)
+ io?.setEdit(editText)
+
+ // Listeners for keyboard height.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ // Report the height of virtual keyboard as it changes during the animation.
+ val decorView = activity.window.decorView
+ decorView.setWindowInsetsAnimationCallback(object : WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
+ var startBottom = 0
+ var endBottom = 0
+ override fun onPrepare(animation: WindowInsetsAnimation) {
+ startBottom = decorView.rootWindowInsets.getInsets(WindowInsets.Type.ime()).bottom
+ }
+
+ override fun onStart(animation: WindowInsetsAnimation, bounds: WindowInsetsAnimation.Bounds): WindowInsetsAnimation.Bounds {
+ endBottom = decorView.rootWindowInsets.getInsets(WindowInsets.Type.ime()).bottom
+ return bounds
+ }
+
+ override fun onProgress(windowInsets: WindowInsets, list: List<WindowInsetsAnimation>): WindowInsets {
+ // Find the IME animation.
+ var imeAnimation: WindowInsetsAnimation? = null
+ for (animation in list) {
+ if (animation.typeMask and WindowInsets.Type.ime() != 0) {
+ imeAnimation = animation
+ break
+ }
+ }
+ // Update keyboard height based on IME animation.
+ if (imeAnimation != null) {
+ val interpolatedFraction = imeAnimation.interpolatedFraction
+ // Linear interpolation between start and end values.
+ val keyboardHeight = startBottom * (1.0f - interpolatedFraction) + endBottom * interpolatedFraction
+ GodotLib.setVirtualKeyboardHeight(keyboardHeight.toInt())
+ }
+ return windowInsets
+ }
+
+ override fun onEnd(animation: WindowInsetsAnimation) {}
+ })
+ } else {
+ // Infer the virtual keyboard height using visible area.
+ view.viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
+ // Don't allocate a new Rect every time the callback is called.
+ val visibleSize = Rect()
+ override fun onGlobalLayout() {
+ val surfaceView = renderView!!.view
+ surfaceView.getWindowVisibleDisplayFrame(visibleSize)
+ val keyboardHeight = surfaceView.height - visibleSize.bottom
+ GodotLib.setVirtualKeyboardHeight(keyboardHeight)
+ }
+ })
+ }
+
+ if (host == primaryHost) {
+ renderView!!.queueOnRenderThread {
+ for (plugin in pluginRegistry.allPlugins) {
+ plugin.onRegisterPluginWithGodotNative()
+ }
+ setKeepScreenOn(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")))
+ }
+
+ // Include the returned non-null views in the Godot view hierarchy.
+ for (plugin in pluginRegistry.allPlugins) {
+ val pluginView = plugin.onMainCreate(activity)
+ if (pluginView != null) {
+ if (plugin.shouldBeOnTop()) {
+ containerLayout?.addView(pluginView)
+ } else {
+ containerLayout?.addView(pluginView, 0)
+ }
+ }
+ }
+ }
+ renderViewInitialized = true
+ } finally {
+ if (!renderViewInitialized) {
+ containerLayout?.removeAllViews()
+ containerLayout = null
+ }
+ }
+ return containerLayout
+ }
+
+ fun onResume(host: GodotHost) {
+ if (host != primaryHost) {
+ return
+ }
+
+ renderView!!.onActivityResumed()
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME)
+ mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME)
+ mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME)
+ mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME)
+ if (useImmersive) {
+ val window = requireActivity().window
+ window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or // hide nav bar
+ View.SYSTEM_UI_FLAG_FULLSCREEN or // hide status bar
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ }
+ for (plugin in pluginRegistry.allPlugins) {
+ plugin.onMainResume()
+ }
+ }
+
+ fun onPause(host: GodotHost) {
+ if (host != primaryHost) {
+ return
+ }
+
+ renderView!!.onActivityPaused()
+ mSensorManager.unregisterListener(this)
+ for (plugin in pluginRegistry.allPlugins) {
+ plugin.onMainPause()
+ }
+ }
+
+ fun onDestroy(primaryHost: GodotHost) {
+ if (this.primaryHost != primaryHost) {
+ return
+ }
+
+ for (plugin in pluginRegistry.allPlugins) {
+ plugin.onMainDestroy()
+ }
+ GodotLib.ondestroy()
+ forceQuit()
+ }
+
+ /**
+ * Activity result callback
+ */
+ fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ for (plugin in pluginRegistry.allPlugins) {
+ plugin.onMainActivityResult(requestCode, resultCode, data)
+ }
+ }
+
+ /**
+ * Permissions request callback
+ */
+ fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array<String?>,
+ grantResults: IntArray
+ ) {
+ for (plugin in pluginRegistry.allPlugins) {
+ plugin.onMainRequestPermissionsResult(requestCode, permissions, grantResults)
+ }
+ for (i in permissions.indices) {
+ GodotLib.requestPermissionResult(
+ permissions[i],
+ grantResults[i] == PackageManager.PERMISSION_GRANTED
+ )
+ }
+ }
+
+ /**
+ * Invoked on the render thread when the Godot setup is complete.
+ */
+ private fun onGodotSetupCompleted() {
+ for (plugin in pluginRegistry.allPlugins) {
+ plugin.onGodotSetupCompleted()
+ }
+ primaryHost?.onGodotSetupCompleted()
+ }
+
+ /**
+ * Invoked on the render thread when the Godot main loop has started.
+ */
+ private fun onGodotMainLoopStarted() {
+ for (plugin in pluginRegistry.allPlugins) {
+ plugin.onGodotMainLoopStarted()
+ }
+ primaryHost?.onGodotMainLoopStarted()
+ }
+
+ private fun restart() {
+ primaryHost?.onGodotRestartRequested(this)
+ }
+
+ private fun registerUiChangeListener() {
+ val decorView = requireActivity().window.decorView
+ decorView.setOnSystemUiVisibilityChangeListener(uiChangeListener)
+ }
+
+ @Keep
+ private fun alert(message: String, title: String) {
+ alert(message, title, null)
+ }
+
+ private fun alert(
+ @StringRes messageResId: Int,
+ @StringRes titleResId: Int,
+ okCallback: Runnable?
+ ) {
+ val res: Resources = getActivity()?.resources ?: return
+ alert(res.getString(messageResId), res.getString(titleResId), okCallback)
+ }
+
+ private fun alert(message: String, title: String, okCallback: Runnable?) {
+ val activity: Activity = getActivity() ?: return
+ runOnUiThread(Runnable {
+ val builder = AlertDialog.Builder(activity)
+ builder.setMessage(message).setTitle(title)
+ builder.setPositiveButton(
+ "OK"
+ ) { dialog: DialogInterface, id: Int ->
+ okCallback?.run()
+ dialog.cancel()
+ }
+ val dialog = builder.create()
+ dialog.show()
+ })
+ }
+
+ /**
+ * Queue a runnable to be run on the render thread.
+ *
+ * This must be called after the render thread has started.
+ */
+ fun runOnRenderThread(action: Runnable) {
+ if (renderView != null) {
+ renderView!!.queueOnRenderThread(action)
+ }
+ }
+
+ /**
+ * Runs the specified action on the UI thread.
+ * If the current thread is the UI thread, then the action is executed immediately.
+ * If the current thread is not the UI thread, the action is posted to the event queue
+ * of the UI thread.
+ */
+ fun runOnUiThread(action: Runnable) {
+ val activity: Activity = getActivity() ?: return
+ activity.runOnUiThread(action)
+ }
+
+ /**
+ * Returns true if the call is being made on the Ui thread.
+ */
+ private fun isOnUiThread() = Looper.myLooper() == Looper.getMainLooper()
+
+ /**
+ * Returns true if `Vulkan` is used for rendering.
+ */
+ private fun usesVulkan(): Boolean {
+ val renderer = GodotLib.getGlobal("rendering/renderer/rendering_method")
+ val renderingDevice = GodotLib.getGlobal("rendering/rendering_device/driver")
+ return ("forward_plus" == renderer || "mobile" == renderer) && "vulkan" == renderingDevice
+ }
+
+ /**
+ * Returns true if the device meets the base requirements for Vulkan support, false otherwise.
+ */
+ private fun meetsVulkanRequirements(packageManager: PackageManager?): Boolean {
+ if (packageManager == null) {
+ return false
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 1)) {
+ // Optional requirements.. log as warning if missing
+ Log.w(TAG, "The vulkan hardware level does not meet the minimum requirement: 1")
+ }
+
+ // Check for api version 1.0
+ return packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x400003)
+ }
+ return false
+ }
+
+ private fun setKeepScreenOn(p_enabled: Boolean) {
+ runOnUiThread {
+ if (p_enabled) {
+ getActivity()?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ } else {
+ getActivity()?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ }
+ }
+ }
+
+ fun hasClipboard(): Boolean {
+ return mClipboard.hasPrimaryClip()
+ }
+
+ fun getClipboard(): String? {
+ val clipData = mClipboard.primaryClip ?: return ""
+ val text = clipData.getItemAt(0).text ?: return ""
+ return text.toString()
+ }
+
+ fun setClipboard(text: String?) {
+ val clip = ClipData.newPlainText("myLabel", text)
+ mClipboard.setPrimaryClip(clip)
+ }
+
+ private fun forceQuit() {
+ forceQuit(0)
+ }
+
+ @Keep
+ private fun forceQuit(instanceId: Int): Boolean {
+ if (primaryHost == null) {
+ return false
+ }
+ return if (instanceId == 0) {
+ primaryHost!!.onGodotForceQuit(this)
+ true
+ } else {
+ primaryHost!!.onGodotForceQuit(instanceId)
+ }
+ }
+
+ fun onBackPressed(host: GodotHost) {
+ if (host != primaryHost) {
+ return
+ }
+
+ var shouldQuit = true
+ for (plugin in pluginRegistry.allPlugins) {
+ if (plugin.onMainBackPressed()) {
+ shouldQuit = false
+ }
+ }
+ if (shouldQuit && renderView != null) {
+ renderView!!.queueOnRenderThread { GodotLib.back() }
+ }
+ }
+
+ private fun getRotatedValues(values: FloatArray?): FloatArray? {
+ if (values == null || values.size != 3) {
+ return values
+ }
+ val display =
+ (requireActivity().getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
+ val displayRotation = display.rotation
+ val rotatedValues = FloatArray(3)
+ when (displayRotation) {
+ Surface.ROTATION_0 -> {
+ rotatedValues[0] = values[0]
+ rotatedValues[1] = values[1]
+ rotatedValues[2] = values[2]
+ }
+ Surface.ROTATION_90 -> {
+ rotatedValues[0] = -values[1]
+ rotatedValues[1] = values[0]
+ rotatedValues[2] = values[2]
+ }
+ Surface.ROTATION_180 -> {
+ rotatedValues[0] = -values[0]
+ rotatedValues[1] = -values[1]
+ rotatedValues[2] = values[2]
+ }
+ Surface.ROTATION_270 -> {
+ rotatedValues[0] = values[1]
+ rotatedValues[1] = -values[0]
+ rotatedValues[2] = values[2]
+ }
+ }
+ return rotatedValues
+ }
+
+ override fun onSensorChanged(event: SensorEvent) {
+ if (renderView == null) {
+ return
+ }
+ when (event.sensor.type) {
+ Sensor.TYPE_ACCELEROMETER -> {
+ val rotatedValues = getRotatedValues(event.values)
+ renderView!!.queueOnRenderThread {
+ GodotLib.accelerometer(
+ -rotatedValues!![0], -rotatedValues[1], -rotatedValues[2]
+ )
+ }
+ }
+ Sensor.TYPE_GRAVITY -> {
+ val rotatedValues = getRotatedValues(event.values)
+ renderView!!.queueOnRenderThread {
+ GodotLib.gravity(
+ -rotatedValues!![0], -rotatedValues[1], -rotatedValues[2]
+ )
+ }
+ }
+ Sensor.TYPE_MAGNETIC_FIELD -> {
+ val rotatedValues = getRotatedValues(event.values)
+ renderView!!.queueOnRenderThread {
+ GodotLib.magnetometer(
+ -rotatedValues!![0], -rotatedValues[1], -rotatedValues[2]
+ )
+ }
+ }
+ Sensor.TYPE_GYROSCOPE -> {
+ val rotatedValues = getRotatedValues(event.values)
+ renderView!!.queueOnRenderThread {
+ GodotLib.gyroscope(
+ rotatedValues!![0], rotatedValues[1], rotatedValues[2]
+ )
+ }
+ }
+ }
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ // Do something here if sensor accuracy changes.
+ }
+
+ /**
+ * Used by the native code (java_godot_wrapper.h) to vibrate the device.
+ * @param durationMs
+ */
+ @SuppressLint("MissingPermission")
+ @Keep
+ private fun vibrate(durationMs: Int) {
+ if (durationMs > 0 && requestPermission("VIBRATE")) {
+ val vibratorService = getActivity()?.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator? ?: return
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ vibratorService.vibrate(
+ VibrationEffect.createOneShot(
+ durationMs.toLong(),
+ VibrationEffect.DEFAULT_AMPLITUDE
+ )
+ )
+ } else {
+ // deprecated in API 26
+ vibratorService.vibrate(durationMs.toLong())
+ }
+ }
+ }
+
+ private fun getCommandLine(): MutableList<String> {
+ val original: MutableList<String> = parseCommandLine()
+ val hostCommandLine = primaryHost?.commandLine
+ if (hostCommandLine != null && hostCommandLine.isNotEmpty()) {
+ original.addAll(hostCommandLine)
+ }
+ return original
+ }
+
+ private fun parseCommandLine(): MutableList<String> {
+ val inputStream: InputStream
+ return try {
+ inputStream = requireActivity().assets.open("_cl_")
+ val len = ByteArray(4)
+ var r = inputStream.read(len)
+ if (r < 4) {
+ return mutableListOf()
+ }
+ val argc =
+ (len[3].toInt() and 0xFF) shl 24 or ((len[2].toInt() and 0xFF) shl 16) or ((len[1].toInt() and 0xFF) shl 8) or (len[0].toInt() and 0xFF)
+ val cmdline = ArrayList<String>(argc)
+ for (i in 0 until argc) {
+ r = inputStream.read(len)
+ if (r < 4) {
+ return mutableListOf()
+ }
+ val strlen =
+ (len[3].toInt() and 0xFF) shl 24 or ((len[2].toInt() and 0xFF) shl 16) or ((len[1].toInt() and 0xFF) shl 8) or (len[0].toInt() and 0xFF)
+ if (strlen > 65535) {
+ return mutableListOf()
+ }
+ val arg = ByteArray(strlen)
+ r = inputStream.read(arg)
+ if (r == strlen) {
+ cmdline[i] = String(arg, StandardCharsets.UTF_8)
+ }
+ }
+ cmdline
+ } catch (e: Exception) {
+ // The _cl_ file can be missing with no adverse effect
+ mutableListOf()
+ }
+ }
+
+ /**
+ * Used by the native code (java_godot_wrapper.h) to access the input fallback mapping.
+ * @return The input fallback mapping for the current XR mode.
+ */
+ @Keep
+ private fun getInputFallbackMapping(): String? {
+ return xrMode.inputFallbackMapping
+ }
+
+ fun requestPermission(name: String?): Boolean {
+ return requestPermission(name, getActivity())
+ }
+
+ fun requestPermissions(): Boolean {
+ return PermissionsUtil.requestManifestPermissions(getActivity())
+ }
+
+ fun getGrantedPermissions(): Array<String?>? {
+ return PermissionsUtil.getGrantedPermissions(getActivity())
+ }
+
+ @Keep
+ private fun getCACertificates(): String {
+ return GodotNetUtils.getCACertificates()
+ }
+
+ private fun obbIsCorrupted(f: String, mainPackMd5: String): Boolean {
+ return try {
+ val fis: InputStream = FileInputStream(f)
+
+ // Create MD5 Hash
+ val buffer = ByteArray(16384)
+ val complete = MessageDigest.getInstance("MD5")
+ var numRead: Int
+ do {
+ numRead = fis.read(buffer)
+ if (numRead > 0) {
+ complete.update(buffer, 0, numRead)
+ }
+ } while (numRead != -1)
+ fis.close()
+ val messageDigest = complete.digest()
+
+ // Create Hex String
+ val hexString = StringBuilder()
+ for (b in messageDigest) {
+ var s = Integer.toHexString(0xFF and b.toInt())
+ if (s.length == 1) {
+ s = "0$s"
+ }
+ hexString.append(s)
+ }
+ val md5str = hexString.toString()
+ md5str != mainPackMd5
+ } catch (e: java.lang.Exception) {
+ e.printStackTrace()
+ true
+ }
+ }
+
+ @Keep
+ private fun initInputDevices() {
+ renderView!!.initInputDevices()
+ }
+
+ @Keep
+ private fun createNewGodotInstance(args: Array<String>): Int {
+ return primaryHost?.onNewGodotInstanceRequested(args) ?: 0
+ }
+
+ @Keep
+ private fun nativeBeginBenchmarkMeasure(label: String) {
+ beginBenchmarkMeasure(label)
+ }
+
+ @Keep
+ private fun nativeEndBenchmarkMeasure(label: String) {
+ endBenchmarkMeasure(label)
+ }
+
+ @Keep
+ private fun nativeDumpBenchmark(benchmarkFile: String) {
+ dumpBenchmark(fileAccessHandler, benchmarkFile)
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt
new file mode 100644
index 0000000000..4636f753af
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt
@@ -0,0 +1,167 @@
+/**************************************************************************/
+/* GodotActivity.kt */
+/**************************************************************************/
+/* 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. */
+/**************************************************************************/
+
+package org.godotengine.godot
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import androidx.annotation.CallSuper
+import androidx.fragment.app.FragmentActivity
+import org.godotengine.godot.utils.ProcessPhoenix
+
+/**
+ * Base abstract activity for Android apps intending to use Godot as the primary screen.
+ *
+ * Also a reference implementation for how to setup and use the [GodotFragment] fragment
+ * within an Android app.
+ */
+abstract class GodotActivity : FragmentActivity(), GodotHost {
+
+ companion object {
+ private val TAG = GodotActivity::class.java.simpleName
+
+ @JvmStatic
+ protected val EXTRA_FORCE_QUIT = "force_quit_requested"
+ @JvmStatic
+ protected val EXTRA_NEW_LAUNCH = "new_launch_requested"
+ }
+
+ /**
+ * Interaction with the [Godot] object is delegated to the [GodotFragment] class.
+ */
+ protected var godotFragment: GodotFragment? = null
+ private set
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.godot_app_layout)
+
+ handleStartIntent(intent, true)
+
+ val currentFragment = supportFragmentManager.findFragmentById(R.id.godot_fragment_container)
+ if (currentFragment is GodotFragment) {
+ Log.v(TAG, "Reusing existing Godot fragment instance.")
+ godotFragment = currentFragment
+ } else {
+ Log.v(TAG, "Creating new Godot fragment instance.")
+ godotFragment = initGodotInstance()
+ supportFragmentManager.beginTransaction().replace(R.id.godot_fragment_container, godotFragment!!).setPrimaryNavigationFragment(godotFragment).commitNowAllowingStateLoss()
+ }
+ }
+
+ override fun onDestroy() {
+ Log.v(TAG, "Destroying Godot app...")
+ super.onDestroy()
+ if (godotFragment != null) {
+ terminateGodotInstance(godotFragment!!.godot)
+ }
+ }
+
+ override fun onGodotForceQuit(instance: Godot) {
+ runOnUiThread { terminateGodotInstance(instance) }
+ }
+
+ private fun terminateGodotInstance(instance: Godot) {
+ if (godotFragment != null && instance === godotFragment!!.godot) {
+ Log.v(TAG, "Force quitting Godot instance")
+ ProcessPhoenix.forceQuit(this)
+ }
+ }
+
+ override fun onGodotRestartRequested(instance: Godot) {
+ runOnUiThread {
+ if (godotFragment != null && instance === godotFragment!!.godot) {
+ // It's very hard to properly de-initialize Godot on Android to restart the game
+ // from scratch. Therefore, we need to kill the whole app process and relaunch it.
+ //
+ // Restarting only the activity, wouldn't be enough unless it did proper cleanup (including
+ // releasing and reloading native libs or resetting their state somehow and clearing static data).
+ Log.v(TAG, "Restarting Godot instance...")
+ ProcessPhoenix.triggerRebirth(this)
+ }
+ }
+ }
+
+ override fun onNewIntent(newIntent: Intent) {
+ super.onNewIntent(newIntent)
+ intent = newIntent
+
+ handleStartIntent(newIntent, false)
+
+ godotFragment?.onNewIntent(newIntent)
+ }
+
+ private fun handleStartIntent(intent: Intent, newLaunch: Boolean) {
+ val forceQuitRequested = intent.getBooleanExtra(EXTRA_FORCE_QUIT, false)
+ if (forceQuitRequested) {
+ Log.d(TAG, "Force quit requested, terminating..")
+ ProcessPhoenix.forceQuit(this)
+ return
+ }
+ if (!newLaunch) {
+ val newLaunchRequested = intent.getBooleanExtra(EXTRA_NEW_LAUNCH, false)
+ if (newLaunchRequested) {
+ Log.d(TAG, "New launch requested, restarting..")
+ val restartIntent = Intent(intent).putExtra(EXTRA_NEW_LAUNCH, false)
+ ProcessPhoenix.triggerRebirth(this, restartIntent)
+ return
+ }
+ }
+ }
+
+ @CallSuper
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ godotFragment?.onActivityResult(requestCode, resultCode, data)
+ }
+
+ @CallSuper
+ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ godotFragment?.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ }
+
+ override fun onBackPressed() {
+ godotFragment?.onBackPressed() ?: super.onBackPressed()
+ }
+
+ override fun getActivity(): Activity? {
+ return this
+ }
+
+ /**
+ * Used to initialize the Godot fragment instance in [onCreate].
+ */
+ protected open fun initGodotInstance(): GodotFragment {
+ return GodotFragment()
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java b/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java
new file mode 100644
index 0000000000..9a8b10ea3e
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java
@@ -0,0 +1,429 @@
+/**************************************************************************/
+/* GodotFragment.java */
+/**************************************************************************/
+/* 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. */
+/**************************************************************************/
+
+package org.godotengine.godot;
+
+import org.godotengine.godot.utils.BenchmarkUtils;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Messenger;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
+import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
+import com.google.android.vending.expansion.downloader.DownloaderServiceMarshaller;
+import com.google.android.vending.expansion.downloader.Helpers;
+import com.google.android.vending.expansion.downloader.IDownloaderClient;
+import com.google.android.vending.expansion.downloader.IDownloaderService;
+import com.google.android.vending.expansion.downloader.IStub;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Base fragment for Android apps intending to use Godot for part of the app's UI.
+ */
+public class GodotFragment extends Fragment implements IDownloaderClient, GodotHost {
+ private static final String TAG = GodotFragment.class.getSimpleName();
+
+ private IStub mDownloaderClientStub;
+ private TextView mStatusText;
+ private TextView mProgressFraction;
+ private TextView mProgressPercent;
+ private TextView mAverageSpeed;
+ private TextView mTimeRemaining;
+ private ProgressBar mPB;
+
+ private View mDashboard;
+ private View mCellMessage;
+
+ private Button mPauseButton;
+ private Button mWiFiSettingsButton;
+
+ private FrameLayout godotContainerLayout;
+ private boolean mStatePaused;
+ private int mState;
+
+ @Nullable
+ private GodotHost parentHost;
+ private Godot godot;
+
+ static private Intent mCurrentIntent;
+
+ public void onNewIntent(Intent intent) {
+ mCurrentIntent = intent;
+ }
+
+ static public Intent getCurrentIntent() {
+ return mCurrentIntent;
+ }
+
+ private void setState(int newState) {
+ if (mState != newState) {
+ mState = newState;
+ mStatusText.setText(Helpers.getDownloaderStringResourceIDFromState(newState));
+ }
+ }
+
+ private void setButtonPausedState(boolean paused) {
+ mStatePaused = paused;
+ int stringResourceID = paused ? R.string.text_button_resume : R.string.text_button_pause;
+ mPauseButton.setText(stringResourceID);
+ }
+
+ public interface ResultCallback {
+ void callback(int requestCode, int resultCode, Intent data);
+ }
+ public ResultCallback resultCallback;
+
+ public Godot getGodot() {
+ return godot;
+ }
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ if (getParentFragment() instanceof GodotHost) {
+ parentHost = (GodotHost)getParentFragment();
+ } else if (getActivity() instanceof GodotHost) {
+ parentHost = (GodotHost)getActivity();
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ parentHost = null;
+ }
+
+ @CallSuper
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCallback != null) {
+ resultCallback.callback(requestCode, resultCode, data);
+ resultCallback = null;
+ }
+
+ godot.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @CallSuper
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ godot.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+
+ @Override
+ public void onServiceConnected(Messenger m) {
+ IDownloaderService remoteService = DownloaderServiceMarshaller.CreateProxy(m);
+ remoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ BenchmarkUtils.beginBenchmarkMeasure("GodotFragment::onCreate");
+ super.onCreate(icicle);
+
+ final Activity activity = getActivity();
+ mCurrentIntent = activity.getIntent();
+
+ godot = new Godot(requireContext());
+ performEngineInitialization();
+ BenchmarkUtils.endBenchmarkMeasure("GodotFragment::onCreate");
+ }
+
+ private void performEngineInitialization() {
+ try {
+ godot.onCreate(this);
+
+ if (!godot.onInitNativeLayer(this)) {
+ throw new IllegalStateException("Unable to initialize engine native layer");
+ }
+
+ godotContainerLayout = godot.onInitRenderView(this);
+ if (godotContainerLayout == null) {
+ throw new IllegalStateException("Unable to initialize engine render view");
+ }
+ } catch (IllegalArgumentException ignored) {
+ final Activity activity = getActivity();
+ Intent notifierIntent = new Intent(activity, activity.getClass());
+ notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+ PendingIntent pendingIntent;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ pendingIntent = PendingIntent.getActivity(activity, 0,
+ notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ } else {
+ pendingIntent = PendingIntent.getActivity(activity, 0,
+ notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ int startResult;
+ try {
+ startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(getContext(), pendingIntent, GodotDownloaderService.class);
+
+ if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
+ // This is where you do set up to display the download
+ // progress (next step in onCreateView)
+ mDownloaderClientStub = DownloaderClientMarshaller.CreateStub(this, GodotDownloaderService.class);
+ return;
+ }
+
+ // Restart engine initialization
+ performEngineInitialization();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Unable to start download service", e);
+ }
+ }
+ }
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle icicle) {
+ if (mDownloaderClientStub != null) {
+ View downloadingExpansionView =
+ inflater.inflate(R.layout.downloading_expansion, container, false);
+ mPB = (ProgressBar)downloadingExpansionView.findViewById(R.id.progressBar);
+ mStatusText = (TextView)downloadingExpansionView.findViewById(R.id.statusText);
+ mProgressFraction = (TextView)downloadingExpansionView.findViewById(R.id.progressAsFraction);
+ mProgressPercent = (TextView)downloadingExpansionView.findViewById(R.id.progressAsPercentage);
+ mAverageSpeed = (TextView)downloadingExpansionView.findViewById(R.id.progressAverageSpeed);
+ mTimeRemaining = (TextView)downloadingExpansionView.findViewById(R.id.progressTimeRemaining);
+ mDashboard = downloadingExpansionView.findViewById(R.id.downloaderDashboard);
+ mCellMessage = downloadingExpansionView.findViewById(R.id.approveCellular);
+ mPauseButton = (Button)downloadingExpansionView.findViewById(R.id.pauseButton);
+ mWiFiSettingsButton = (Button)downloadingExpansionView.findViewById(R.id.wifiSettingsButton);
+
+ return downloadingExpansionView;
+ }
+
+ return godotContainerLayout;
+ }
+
+ @Override
+ public void onDestroy() {
+ godot.onDestroy(this);
+ super.onDestroy();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ if (!godot.isInitialized()) {
+ if (null != mDownloaderClientStub) {
+ mDownloaderClientStub.disconnect(getActivity());
+ }
+ return;
+ }
+
+ godot.onPause(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (!godot.isInitialized()) {
+ if (null != mDownloaderClientStub) {
+ mDownloaderClientStub.connect(getActivity());
+ }
+ return;
+ }
+
+ godot.onResume(this);
+ }
+
+ public void onBackPressed() {
+ godot.onBackPressed(this);
+ }
+
+ /**
+ * The download state should trigger changes in the UI --- it may be useful
+ * to show the state as being indeterminate at times. This sample can be
+ * considered a guideline.
+ */
+ @Override
+ public void onDownloadStateChanged(int newState) {
+ setState(newState);
+ boolean showDashboard = true;
+ boolean showCellMessage = false;
+ boolean paused;
+ boolean indeterminate;
+ switch (newState) {
+ case IDownloaderClient.STATE_IDLE:
+ // STATE_IDLE means the service is listening, so it's
+ // safe to start making remote service calls.
+ paused = false;
+ indeterminate = true;
+ break;
+ case IDownloaderClient.STATE_CONNECTING:
+ case IDownloaderClient.STATE_FETCHING_URL:
+ showDashboard = true;
+ paused = false;
+ indeterminate = true;
+ break;
+ case IDownloaderClient.STATE_DOWNLOADING:
+ paused = false;
+ showDashboard = true;
+ indeterminate = false;
+ break;
+
+ case IDownloaderClient.STATE_FAILED_CANCELED:
+ case IDownloaderClient.STATE_FAILED:
+ case IDownloaderClient.STATE_FAILED_FETCHING_URL:
+ case IDownloaderClient.STATE_FAILED_UNLICENSED:
+ paused = true;
+ showDashboard = false;
+ indeterminate = false;
+ break;
+ case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION:
+ case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION:
+ showDashboard = false;
+ paused = true;
+ indeterminate = false;
+ showCellMessage = true;
+ break;
+
+ case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
+ paused = true;
+ indeterminate = false;
+ break;
+ case IDownloaderClient.STATE_PAUSED_ROAMING:
+ case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE:
+ paused = true;
+ indeterminate = false;
+ break;
+ case IDownloaderClient.STATE_COMPLETED:
+ showDashboard = false;
+ paused = false;
+ indeterminate = false;
+ performEngineInitialization();
+ return;
+ default:
+ paused = true;
+ indeterminate = true;
+ showDashboard = true;
+ }
+ int newDashboardVisibility = showDashboard ? View.VISIBLE : View.GONE;
+ if (mDashboard.getVisibility() != newDashboardVisibility) {
+ mDashboard.setVisibility(newDashboardVisibility);
+ }
+ int cellMessageVisibility = showCellMessage ? View.VISIBLE : View.GONE;
+ if (mCellMessage.getVisibility() != cellMessageVisibility) {
+ mCellMessage.setVisibility(cellMessageVisibility);
+ }
+
+ mPB.setIndeterminate(indeterminate);
+ setButtonPausedState(paused);
+ }
+
+ @Override
+ public void onDownloadProgress(DownloadProgressInfo progress) {
+ mAverageSpeed.setText(getString(R.string.kilobytes_per_second,
+ Helpers.getSpeedString(progress.mCurrentSpeed)));
+ mTimeRemaining.setText(getString(R.string.time_remaining,
+ Helpers.getTimeRemaining(progress.mTimeRemaining)));
+
+ mPB.setMax((int)(progress.mOverallTotal >> 8));
+ mPB.setProgress((int)(progress.mOverallProgress >> 8));
+ mProgressPercent.setText(String.format(Locale.ENGLISH, "%d %%", progress.mOverallProgress * 100 / progress.mOverallTotal));
+ mProgressFraction.setText(Helpers.getDownloadProgressString(progress.mOverallProgress,
+ progress.mOverallTotal));
+ }
+
+ @CallSuper
+ @Override
+ public List<String> getCommandLine() {
+ return parentHost != null ? parentHost.getCommandLine() : Collections.emptyList();
+ }
+
+ @CallSuper
+ @Override
+ public void onGodotSetupCompleted() {
+ if (parentHost != null) {
+ parentHost.onGodotSetupCompleted();
+ }
+ }
+
+ @CallSuper
+ @Override
+ public void onGodotMainLoopStarted() {
+ if (parentHost != null) {
+ parentHost.onGodotMainLoopStarted();
+ }
+ }
+
+ @Override
+ public void onGodotForceQuit(Godot instance) {
+ if (parentHost != null) {
+ parentHost.onGodotForceQuit(instance);
+ }
+ }
+
+ @Override
+ public boolean onGodotForceQuit(int godotInstanceId) {
+ return parentHost != null && parentHost.onGodotForceQuit(godotInstanceId);
+ }
+
+ @Override
+ public void onGodotRestartRequested(Godot instance) {
+ if (parentHost != null) {
+ parentHost.onGodotRestartRequested(instance);
+ }
+ }
+
+ @Override
+ public int onNewGodotInstanceRequested(String[] args) {
+ if (parentHost != null) {
+ return parentHost.onNewGodotInstanceRequested(args);
+ }
+ return 0;
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
index b465377743..52350c12a6 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
@@ -29,10 +29,10 @@
/**************************************************************************/
package org.godotengine.godot;
+
import org.godotengine.godot.gl.GLSurfaceView;
import org.godotengine.godot.gl.GodotRenderer;
import org.godotengine.godot.input.GodotInputHandler;
-import org.godotengine.godot.utils.GLUtils;
import org.godotengine.godot.xr.XRMode;
import org.godotengine.godot.xr.ovr.OvrConfigChooser;
import org.godotengine.godot.xr.ovr.OvrContextFactory;
@@ -78,22 +78,23 @@ import java.io.InputStream;
* bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
*/
public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
+ private final GodotHost host;
private final Godot godot;
private final GodotInputHandler inputHandler;
private final GodotRenderer godotRenderer;
private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>();
- public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_debug_opengl) {
- super(context);
- GLUtils.use_debug_opengl = p_use_debug_opengl;
+ public GodotGLRenderView(GodotHost host, Godot godot, XRMode xrMode, boolean useDebugOpengl) {
+ super(host.getActivity());
+ this.host = host;
this.godot = godot;
this.inputHandler = new GodotInputHandler(this);
this.godotRenderer = new GodotRenderer();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
}
- init(xrMode, false);
+ init(xrMode, false, useDebugOpengl);
}
@Override
@@ -123,7 +124,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
@Override
public void onBackPressed() {
- godot.onBackPressed();
+ godot.onBackPressed(host);
}
@Override
@@ -233,7 +234,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
return super.onResolvePointerIcon(me, pointerIndex);
}
- private void init(XRMode xrMode, boolean translucent) {
+ private void init(XRMode xrMode, boolean translucent, boolean useDebugOpengl) {
setPreserveEGLContextOnPause(true);
setFocusableInTouchMode(true);
switch (xrMode) {
@@ -262,7 +263,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
/* Setup the context factory for 2.0 rendering.
* See ContextFactory class definition below
*/
- setEGLContextFactory(new RegularContextFactory());
+ setEGLContextFactory(new RegularContextFactory(useDebugOpengl));
/* We need to choose an EGLConfig that matches the format of
* our surface exactly. This is going to be done in our
@@ -275,7 +276,10 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
new RegularConfigChooser(8, 8, 8, 8, 16, 0)));
break;
}
+ }
+ @Override
+ public void startRenderer() {
/* Set the renderer responsible for frame rendering */
setRenderer(godotRenderer);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java b/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
index 7700b9b628..e5333085dd 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
@@ -30,11 +30,13 @@
package org.godotengine.godot;
+import android.app.Activity;
+
import java.util.Collections;
import java.util.List;
/**
- * Denotate a component (e.g: Activity, Fragment) that hosts the {@link Godot} fragment.
+ * Denotate a component (e.g: Activity, Fragment) that hosts the {@link Godot} engine.
*/
public interface GodotHost {
/**
@@ -86,4 +88,9 @@ public interface GodotHost {
default int onNewGodotInstanceRequested(String[] args) {
return 0;
}
+
+ /**
+ * Provide access to the Activity hosting the Godot engine.
+ */
+ Activity getActivity();
}
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 c725b1a7c9..b9ecd6971d 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -147,7 +147,7 @@ public class GodotLib {
/**
* Forward regular key events.
*/
- public static native void key(int p_physical_keycode, int p_unicode, int p_key_label, boolean p_pressed);
+ public static native void key(int p_physical_keycode, int p_unicode, int p_key_label, boolean p_pressed, boolean p_echo);
/**
* Forward game device's key events.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java
index 00243dab2a..ebf3a6b2fb 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java
@@ -39,6 +39,11 @@ public interface GodotRenderView {
void initInputDevices();
+ /**
+ * Starts the thread that will drive Godot's rendering.
+ */
+ void startRenderer();
+
void queueOnRenderThread(Runnable event);
void onActivityPaused();
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotService.kt b/platform/android/java/lib/src/org/godotengine/godot/GodotService.kt
new file mode 100644
index 0000000000..68cd2c1358
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotService.kt
@@ -0,0 +1,54 @@
+package org.godotengine.godot
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+import android.util.Log
+
+/**
+ * Godot service responsible for hosting the Godot engine instance.
+ */
+class GodotService : Service() {
+
+ companion object {
+ private val TAG = GodotService::class.java.simpleName
+ }
+
+ private var boundIntent: Intent? = null
+ private val godot by lazy {
+ Godot(applicationContext)
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ }
+
+ override fun onBind(intent: Intent?): IBinder? {
+ if (boundIntent != null) {
+ Log.d(TAG, "GodotService already bound")
+ return null
+ }
+
+ boundIntent = intent
+ return GodotHandle(godot)
+ }
+
+ override fun onRebind(intent: Intent?) {
+ super.onRebind(intent)
+ }
+
+ override fun onUnbind(intent: Intent?): Boolean {
+ return super.onUnbind(intent)
+ }
+
+ override fun onTaskRemoved(rootIntent: Intent?) {
+ super.onTaskRemoved(rootIntent)
+ }
+
+ class GodotHandle(val godot: Godot) : Binder()
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
index 681e182adb..48708152be 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
@@ -35,7 +35,6 @@ import org.godotengine.godot.vulkan.VkRenderer;
import org.godotengine.godot.vulkan.VkSurfaceView;
import android.annotation.SuppressLint;
-import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -52,14 +51,16 @@ import androidx.annotation.Keep;
import java.io.InputStream;
public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
+ private final GodotHost host;
private final Godot godot;
private final GodotInputHandler mInputHandler;
private final VkRenderer mRenderer;
private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>();
- public GodotVulkanRenderView(Context context, Godot godot) {
- super(context);
+ public GodotVulkanRenderView(GodotHost host, Godot godot) {
+ super(host.getActivity());
+ this.host = host;
this.godot = godot;
mInputHandler = new GodotInputHandler(this);
mRenderer = new VkRenderer();
@@ -67,6 +68,10 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
}
setFocusableInTouchMode(true);
+ }
+
+ @Override
+ public void startRenderer() {
startRenderer(mRenderer);
}
@@ -97,7 +102,7 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
@Override
public void onBackPressed() {
- godot.onBackPressed();
+ godot.onBackPressed(host);
}
@Override
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 317344f2a5..185d03fe39 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
@@ -141,7 +141,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
final int physical_keycode = event.getKeyCode();
final int unicode = event.getUnicodeChar();
final int key_label = event.getDisplayLabel();
- GodotLib.key(physical_keycode, unicode, key_label, false);
+ GodotLib.key(physical_keycode, unicode, key_label, false, event.getRepeatCount() > 0);
};
return true;
@@ -176,7 +176,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
final int physical_keycode = event.getKeyCode();
final int unicode = event.getUnicodeChar();
final int key_label = event.getDisplayLabel();
- GodotLib.key(physical_keycode, unicode, key_label, true);
+ GodotLib.key(physical_keycode, unicode, key_label, true, event.getRepeatCount() > 0);
}
return true;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
index f48dba56df..06b565c30f 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -93,8 +93,8 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
@Override
public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) {
for (int i = 0; i < count; ++i) {
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, 0, true);
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, 0, false);
+ GodotLib.key(KeyEvent.KEYCODE_DEL, 0, 0, true, false);
+ GodotLib.key(KeyEvent.KEYCODE_DEL, 0, 0, false, false);
if (mHasSelection) {
mHasSelection = false;
@@ -115,8 +115,8 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
// Return keys are handled through action events
continue;
}
- GodotLib.key(0, character, 0, true);
- GodotLib.key(0, character, 0, false);
+ GodotLib.key(0, character, 0, true, false);
+ GodotLib.key(0, character, 0, false, false);
}
}
@@ -127,8 +127,8 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
if (characters != null) {
for (int i = 0; i < characters.length(); i++) {
final int character = characters.codePointAt(i);
- GodotLib.key(0, character, 0, true);
- GodotLib.key(0, character, 0, false);
+ GodotLib.key(0, character, 0, true, false);
+ GodotLib.key(0, character, 0, false, false);
}
}
}
@@ -136,8 +136,8 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
if (pActionID == EditorInfo.IME_ACTION_DONE) {
// Enter key has been pressed
mRenderView.queueOnRenderThread(() -> {
- GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, 0, true);
- GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, 0, false);
+ GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, 0, true, false);
+ GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, 0, false, false);
});
mRenderView.getView().requestFocus();
return true;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/tts/GodotTTS.java b/platform/android/java/lib/src/org/godotengine/godot/tts/GodotTTS.java
index edace53e7f..dce6753b7a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/tts/GodotTTS.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/tts/GodotTTS.java
@@ -33,6 +33,7 @@ package org.godotengine.godot.tts;
import org.godotengine.godot.GodotLib;
import android.app.Activity;
+import android.content.Context;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
@@ -62,7 +63,7 @@ public class GodotTTS extends UtteranceProgressListener {
final private static int EVENT_CANCEL = 2;
final private static int EVENT_BOUNDARY = 3;
- final private Activity activity;
+ private final Context context;
private TextToSpeech synth;
private LinkedList<GodotUtterance> queue;
final private Object lock = new Object();
@@ -71,8 +72,8 @@ public class GodotTTS extends UtteranceProgressListener {
private boolean speaking;
private boolean paused;
- public GodotTTS(Activity p_activity) {
- activity = p_activity;
+ public GodotTTS(Context context) {
+ this.context = context;
}
private void updateTTS() {
@@ -188,7 +189,7 @@ public class GodotTTS extends UtteranceProgressListener {
* Initialize synth and query.
*/
public void init() {
- synth = new TextToSpeech(activity, null);
+ synth = new TextToSpeech(context, null);
queue = new LinkedList<GodotUtterance>();
synth.setOnUtteranceProgressListener(this);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java b/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java
index 7db02968bb..2c7b73ae4d 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java
@@ -44,8 +44,6 @@ public class GLUtils {
public static final boolean DEBUG = false;
- public static boolean use_debug_opengl = false;
-
private static final String[] ATTRIBUTES_NAMES = new String[] {
"EGL_BUFFER_SIZE",
"EGL_ALPHA_SIZE",
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java b/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java
index c31d56a3e1..dca190a2fc 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java
@@ -36,7 +36,8 @@ import android.net.wifi.WifiManager;
import android.util.Base64;
import android.util.Log;
-import java.io.StringWriter;
+import androidx.annotation.NonNull;
+
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
@@ -50,9 +51,9 @@ public class GodotNetUtils {
/* A single, reference counted, multicast lock, or null if permission CHANGE_WIFI_MULTICAST_STATE is missing */
private WifiManager.MulticastLock multicastLock;
- public GodotNetUtils(Activity p_activity) {
- if (PermissionsUtil.hasManifestPermission(p_activity, "android.permission.CHANGE_WIFI_MULTICAST_STATE")) {
- WifiManager wifi = (WifiManager)p_activity.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+ public GodotNetUtils(Context context) {
+ if (PermissionsUtil.hasManifestPermission(context, "android.permission.CHANGE_WIFI_MULTICAST_STATE")) {
+ WifiManager wifi = (WifiManager)context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
multicastLock = wifi.createMulticastLock("GodotMulticastLock");
multicastLock.setReferenceCounted(true);
}
@@ -91,7 +92,7 @@ public class GodotNetUtils {
* @see https://developer.android.com/reference/java/security/KeyStore .
* @return A string of concatenated X509 certificates in PEM format.
*/
- public static String getCACertificates() {
+ public static @NonNull String getCACertificates() {
try {
KeyStore ks = KeyStore.getInstance("AndroidCAStore");
StringBuilder writer = new StringBuilder();
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
index a94188c405..8353fc8dc6 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
@@ -32,6 +32,7 @@ package org.godotengine.godot.utils;
import android.Manifest;
import android.app.Activity;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -52,7 +53,6 @@ import java.util.Set;
/**
* This class includes utility functions for Android permissions related operations.
*/
-
public final class PermissionsUtil {
private static final String TAG = PermissionsUtil.class.getSimpleName();
@@ -193,13 +193,13 @@ public final class PermissionsUtil {
/**
* With this function you can get the list of dangerous permissions that have been granted to the Android application.
- * @param activity the caller activity for this method.
+ * @param context the caller context for this method.
* @return granted permissions list
*/
- public static String[] getGrantedPermissions(Activity activity) {
+ public static String[] getGrantedPermissions(Context context) {
String[] manifestPermissions;
try {
- manifestPermissions = getManifestPermissions(activity);
+ manifestPermissions = getManifestPermissions(context);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return new String[0];
@@ -215,9 +215,9 @@ public final class PermissionsUtil {
grantedPermissions.add(manifestPermission);
}
} else {
- PermissionInfo permissionInfo = getPermissionInfo(activity, manifestPermission);
+ PermissionInfo permissionInfo = getPermissionInfo(context, manifestPermission);
int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel;
- if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, manifestPermission) == PackageManager.PERMISSION_GRANTED) {
+ if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(context, manifestPermission) == PackageManager.PERMISSION_GRANTED) {
grantedPermissions.add(manifestPermission);
}
}
@@ -232,13 +232,13 @@ public final class PermissionsUtil {
/**
* Check if the given permission is in the AndroidManifest.xml file.
- * @param activity the caller activity for this method.
+ * @param context the caller context for this method.
* @param permission the permession to look for in the manifest file.
* @return "true" if the permission is in the manifest file of the activity, "false" otherwise.
*/
- public static boolean hasManifestPermission(Activity activity, String permission) {
+ public static boolean hasManifestPermission(Context context, String permission) {
try {
- for (String p : getManifestPermissions(activity)) {
+ for (String p : getManifestPermissions(context)) {
if (permission.equals(p))
return true;
}
@@ -250,13 +250,13 @@ public final class PermissionsUtil {
/**
* Returns the permissions defined in the AndroidManifest.xml file.
- * @param activity the caller activity for this method.
+ * @param context the caller context for this method.
* @return manifest permissions list
* @throws PackageManager.NameNotFoundException the exception is thrown when a given package, application, or component name cannot be found.
*/
- private static String[] getManifestPermissions(Activity activity) throws PackageManager.NameNotFoundException {
- PackageManager packageManager = activity.getPackageManager();
- PackageInfo packageInfo = packageManager.getPackageInfo(activity.getPackageName(), PackageManager.GET_PERMISSIONS);
+ private static String[] getManifestPermissions(Context context) throws PackageManager.NameNotFoundException {
+ PackageManager packageManager = context.getPackageManager();
+ PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
if (packageInfo.requestedPermissions == null)
return new String[0];
return packageInfo.requestedPermissions;
@@ -264,13 +264,13 @@ public final class PermissionsUtil {
/**
* Returns the information of the desired permission.
- * @param activity the caller activity for this method.
+ * @param context the caller context for this method.
* @param permission the name of the permission.
* @return permission info object
* @throws PackageManager.NameNotFoundException the exception is thrown when a given package, application, or component name cannot be found.
*/
- private static PermissionInfo getPermissionInfo(Activity activity, String permission) throws PackageManager.NameNotFoundException {
- PackageManager packageManager = activity.getPackageManager();
+ private static PermissionInfo getPermissionInfo(Context context, String permission) throws PackageManager.NameNotFoundException {
+ PackageManager packageManager = context.getPackageManager();
return packageManager.getPermissionInfo(permission, 0);
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java
index 1a126ff765..01ee41e30b 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java
@@ -51,12 +51,22 @@ public class RegularContextFactory implements GLSurfaceView.EGLContextFactory {
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ private final boolean mUseDebugOpengl;
+
+ public RegularContextFactory() {
+ this(false);
+ }
+
+ public RegularContextFactory(boolean useDebugOpengl) {
+ this.mUseDebugOpengl = useDebugOpengl;
+ }
+
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
Log.w(TAG, "creating OpenGL ES 3.0 context :");
GLUtils.checkEglError(TAG, "Before eglCreateContext", egl);
EGLContext context;
- if (GLUtils.use_debug_opengl) {
+ if (mUseDebugOpengl) {
int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE };
context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
} else {
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 7c1b6023c7..74605e3377 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -135,7 +135,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv
os_android = new OS_Android(godot_java, godot_io_java, p_use_apk_expansion);
- return godot_java->on_video_init(env);
+ return true;
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz) {
@@ -385,11 +385,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_physical_keycode, jint p_unicode, jint p_key_label, jboolean p_pressed) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_physical_keycode, jint p_unicode, jint p_key_label, jboolean p_pressed, jboolean p_echo) {
if (step.get() <= 0) {
return;
}
- input_handler->process_key_event(p_physical_keycode, p_unicode, p_key_label, p_pressed);
+ input_handler->process_key_event(p_physical_keycode, p_unicode, p_key_label, p_pressed, p_echo);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 9158e89c13..ee6a19034c 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -49,7 +49,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JN
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);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_physical_keycode, jint p_unicode, jint p_key_label, jboolean p_pressed);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_physical_keycode, jint p_unicode, jint p_key_label, jboolean p_pressed, jboolean p_echo);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y);
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 862d9f0436..79ba2528ba 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -58,12 +58,10 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
}
// get some Godot method pointers...
- _on_video_init = p_env->GetMethodID(godot_class, "onVideoInit", "()Z");
_restart = p_env->GetMethodID(godot_class, "restart", "()V");
_finish = p_env->GetMethodID(godot_class, "forceQuit", "(I)Z");
_set_keep_screen_on = p_env->GetMethodID(godot_class, "setKeepScreenOn", "(Z)V");
_alert = p_env->GetMethodID(godot_class, "alert", "(Ljava/lang/String;Ljava/lang/String;)V");
- _get_GLES_version_code = p_env->GetMethodID(godot_class, "getGLESVersionCode", "()I");
_get_clipboard = p_env->GetMethodID(godot_class, "getClipboard", "()Ljava/lang/String;");
_set_clipboard = p_env->GetMethodID(godot_class, "setClipboard", "(Ljava/lang/String;)V");
_has_clipboard = p_env->GetMethodID(godot_class, "hasClipboard", "()Z");
@@ -72,20 +70,15 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
_get_granted_permissions = p_env->GetMethodID(godot_class, "getGrantedPermissions", "()[Ljava/lang/String;");
_get_ca_certificates = p_env->GetMethodID(godot_class, "getCACertificates", "()Ljava/lang/String;");
_init_input_devices = p_env->GetMethodID(godot_class, "initInputDevices", "()V");
- _get_surface = p_env->GetMethodID(godot_class, "getSurface", "()Landroid/view/Surface;");
- _is_activity_resumed = p_env->GetMethodID(godot_class, "isActivityResumed", "()Z");
_vibrate = p_env->GetMethodID(godot_class, "vibrate", "(I)V");
_get_input_fallback_mapping = p_env->GetMethodID(godot_class, "getInputFallbackMapping", "()Ljava/lang/String;");
_on_godot_setup_completed = p_env->GetMethodID(godot_class, "onGodotSetupCompleted", "()V");
_on_godot_main_loop_started = p_env->GetMethodID(godot_class, "onGodotMainLoopStarted", "()V");
_create_new_godot_instance = p_env->GetMethodID(godot_class, "createNewGodotInstance", "([Ljava/lang/String;)I");
_get_render_view = p_env->GetMethodID(godot_class, "getRenderView", "()Lorg/godotengine/godot/GodotRenderView;");
- _begin_benchmark_measure = p_env->GetMethodID(godot_class, "beginBenchmarkMeasure", "(Ljava/lang/String;)V");
- _end_benchmark_measure = p_env->GetMethodID(godot_class, "endBenchmarkMeasure", "(Ljava/lang/String;)V");
- _dump_benchmark = p_env->GetMethodID(godot_class, "dumpBenchmark", "(Ljava/lang/String;)V");
-
- // get some Activity method pointers...
- _get_class_loader = p_env->GetMethodID(activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;");
+ _begin_benchmark_measure = p_env->GetMethodID(godot_class, "nativeBeginBenchmarkMeasure", "(Ljava/lang/String;)V");
+ _end_benchmark_measure = p_env->GetMethodID(godot_class, "nativeEndBenchmarkMeasure", "(Ljava/lang/String;)V");
+ _dump_benchmark = p_env->GetMethodID(godot_class, "nativeDumpBenchmark", "(Ljava/lang/String;)V");
}
GodotJavaWrapper::~GodotJavaWrapper() {
@@ -105,29 +98,6 @@ jobject GodotJavaWrapper::get_activity() {
return activity;
}
-jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env) {
- if (godot_class) {
- if (p_env == nullptr) {
- p_env = get_jni_env();
- }
- ERR_FAIL_NULL_V(p_env, nullptr);
- jfieldID fid = p_env->GetStaticFieldID(godot_class, p_name, p_class);
- return p_env->GetStaticObjectField(godot_class, fid);
- } else {
- return nullptr;
- }
-}
-
-jobject GodotJavaWrapper::get_class_loader() {
- if (_get_class_loader) {
- JNIEnv *env = get_jni_env();
- ERR_FAIL_NULL_V(env, nullptr);
- return env->CallObjectMethod(activity, _get_class_loader);
- } else {
- return nullptr;
- }
-}
-
GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() {
if (godot_view != nullptr) {
return godot_view;
@@ -143,17 +113,6 @@ GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() {
return godot_view;
}
-bool GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
- if (_on_video_init) {
- if (p_env == nullptr) {
- p_env = get_jni_env();
- }
- ERR_FAIL_NULL_V(p_env, false);
- return p_env->CallBooleanMethod(godot_instance, _on_video_init);
- }
- return false;
-}
-
void GodotJavaWrapper::on_godot_setup_completed(JNIEnv *p_env) {
if (_on_godot_setup_completed) {
if (p_env == nullptr) {
@@ -212,15 +171,6 @@ void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
}
}
-int GodotJavaWrapper::get_gles_version_code() {
- JNIEnv *env = get_jni_env();
- ERR_FAIL_NULL_V(env, 0);
- if (_get_GLES_version_code) {
- return env->CallIntMethod(godot_instance, _get_GLES_version_code);
- }
- return 0;
-}
-
bool GodotJavaWrapper::has_get_clipboard() {
return _get_clipboard != nullptr;
}
@@ -333,26 +283,6 @@ void GodotJavaWrapper::init_input_devices() {
}
}
-jobject GodotJavaWrapper::get_surface() {
- if (_get_surface) {
- JNIEnv *env = get_jni_env();
- ERR_FAIL_NULL_V(env, nullptr);
- return env->CallObjectMethod(godot_instance, _get_surface);
- } else {
- return nullptr;
- }
-}
-
-bool GodotJavaWrapper::is_activity_resumed() {
- if (_is_activity_resumed) {
- JNIEnv *env = get_jni_env();
- ERR_FAIL_NULL_V(env, false);
- return env->CallBooleanMethod(godot_instance, _is_activity_resumed);
- } else {
- return false;
- }
-}
-
void GodotJavaWrapper::vibrate(int p_duration_ms) {
if (_vibrate) {
JNIEnv *env = get_jni_env();
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index 1efdffd71b..ba42d5dccd 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -49,12 +49,10 @@ private:
GodotJavaViewWrapper *godot_view = nullptr;
- jmethodID _on_video_init = nullptr;
jmethodID _restart = nullptr;
jmethodID _finish = nullptr;
jmethodID _set_keep_screen_on = nullptr;
jmethodID _alert = nullptr;
- jmethodID _get_GLES_version_code = nullptr;
jmethodID _get_clipboard = nullptr;
jmethodID _set_clipboard = nullptr;
jmethodID _has_clipboard = nullptr;
@@ -63,13 +61,10 @@ private:
jmethodID _get_granted_permissions = nullptr;
jmethodID _get_ca_certificates = nullptr;
jmethodID _init_input_devices = nullptr;
- jmethodID _get_surface = nullptr;
- jmethodID _is_activity_resumed = nullptr;
jmethodID _vibrate = nullptr;
jmethodID _get_input_fallback_mapping = nullptr;
jmethodID _on_godot_setup_completed = nullptr;
jmethodID _on_godot_main_loop_started = nullptr;
- jmethodID _get_class_loader = nullptr;
jmethodID _create_new_godot_instance = nullptr;
jmethodID _get_render_view = nullptr;
jmethodID _begin_benchmark_measure = nullptr;
@@ -81,19 +76,15 @@ public:
~GodotJavaWrapper();
jobject get_activity();
- jobject get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env = nullptr);
- jobject get_class_loader();
GodotJavaViewWrapper *get_godot_view();
- bool on_video_init(JNIEnv *p_env = nullptr);
void on_godot_setup_completed(JNIEnv *p_env = nullptr);
void on_godot_main_loop_started(JNIEnv *p_env = nullptr);
void restart(JNIEnv *p_env = nullptr);
bool force_quit(JNIEnv *p_env = nullptr, int p_instance_id = 0);
void set_keep_screen_on(bool p_enabled);
void alert(const String &p_message, const String &p_title);
- int get_gles_version_code();
bool has_get_clipboard();
String get_clipboard();
bool has_set_clipboard();
@@ -105,8 +96,6 @@ public:
Vector<String> get_granted_permissions() const;
String get_ca_certificates() const;
void init_input_devices();
- jobject get_surface();
- bool is_activity_resumed();
void vibrate(int p_duration_ms);
String get_input_fallback_mapping();
int create_new_godot_instance(List<String> args);
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index c3a7d70034..c040d8c4c6 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -167,7 +167,7 @@ Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_han
}
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
- ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + 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/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
index b37868e543..84bc0e1277 100644
--- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml
+++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlatformIOS" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorExportPlatformIOS" inherits="EditorExportPlatform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for iOS.
</brief_description>
@@ -27,6 +27,9 @@
<member name="application/export_method_release" type="int" setter="" getter="">
Application distribution target (release export).
</member>
+ <member name="application/export_project_only" type="bool" setter="" getter="">
+ If [code]true[/code], exports iOS project files without building an XCArchive or [code].ipa[/code] file. If [code]false[/code], exports iOS project files and builds an XCArchive and [code].ipa[/code] file at the same time. When combining Godot with Fastlane or other build pipelines, you may want to set this to [code]true[/code].
+ </member>
<member name="application/icon_interpolation" type="int" setter="" getter="">
Interpolation method used to resize application icon.
</member>
diff --git a/platform/ios/export/export.cpp b/platform/ios/export/export.cpp
index e07a135861..98cc80e4a0 100644
--- a/platform/ios/export/export.cpp
+++ b/platform/ios/export/export.cpp
@@ -39,6 +39,11 @@ void register_ios_exporter_types() {
}
void register_ios_exporter() {
+#ifdef MACOS_ENABLED
+ EDITOR_DEF("export/ios/ios_deploy", "");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/ios/ios_deploy", PROPERTY_HINT_GLOBAL_FILE, "*"));
+#endif
+
Ref<EditorExportPlatformIOS> platform;
platform.instantiate();
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index edc850e74f..544bfb71e0 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -31,11 +31,15 @@
#include "export_plugin.h"
#include "logo_svg.gen.h"
+#include "run_icon_svg.gen.h"
+#include "core/io/json.h"
#include "core/string/translation.h"
#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
#include "editor/export/editor_export.h"
+#include "editor/plugins/script_editor_plugin.h"
#include "modules/modules_enabled.gen.h" // For mono and svg.
#ifdef MODULE_SVG_ENABLED
@@ -178,6 +182,8 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/launch_screens_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/export_project_only"), false));
+
Vector<PluginConfigIOS> found_plugins = get_plugins();
for (int i = 0; i < found_plugins.size(); i++) {
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("plugins"), found_plugins[i].name)), false));
@@ -1475,13 +1481,19 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
}
Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ return _export_project_helper(p_preset, p_debug, p_path, p_flags, false, false);
+}
+
+Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags, bool p_simulator, bool p_skip_ipa) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
String src_pkg_name;
String dest_dir = p_path.get_base_dir() + "/";
String binary_name = p_path.get_file().get_basename();
- EditorProgress ep("export", "Exporting for iOS", 5, true);
+ bool export_project_only = p_preset->get("application/export_project_only");
+
+ EditorProgress ep("export", export_project_only ? TTR("Exporting for iOS (Project Files Only)") : TTR("Exporting for iOS"), export_project_only ? 2 : 5, true);
String team_id = p_preset->get("application/app_store_team_id");
ERR_FAIL_COND_V_MSG(team_id.length() == 0, ERR_CANT_OPEN, "App Store Team ID not specified - cannot configure the project.");
@@ -1843,6 +1855,10 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
}
}
+ if (export_project_only) {
+ return OK;
+ }
+
if (ep.step("Making .xcarchive", 3)) {
return ERR_SKIP;
}
@@ -1853,11 +1869,19 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
archive_args.push_back("-scheme");
archive_args.push_back(binary_name);
archive_args.push_back("-sdk");
- archive_args.push_back("iphoneos");
+ if (p_simulator) {
+ archive_args.push_back("iphonesimulator");
+ } else {
+ archive_args.push_back("iphoneos");
+ }
archive_args.push_back("-configuration");
archive_args.push_back(p_debug ? "Debug" : "Release");
archive_args.push_back("-destination");
- archive_args.push_back("generic/platform=iOS");
+ if (p_simulator) {
+ archive_args.push_back("generic/platform=iOS Simulator");
+ } else {
+ archive_args.push_back("generic/platform=iOS");
+ }
archive_args.push_back("archive");
archive_args.push_back("-allowProvisioningUpdates");
archive_args.push_back("-archivePath");
@@ -1871,26 +1895,27 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
return FAILED;
}
- if (ep.step("Making .ipa", 4)) {
- return ERR_SKIP;
- }
- List<String> export_args;
- export_args.push_back("-exportArchive");
- export_args.push_back("-archivePath");
- export_args.push_back(archive_path);
- export_args.push_back("-exportOptionsPlist");
- export_args.push_back(dest_dir + binary_name + "/export_options.plist");
- export_args.push_back("-allowProvisioningUpdates");
- export_args.push_back("-exportPath");
- export_args.push_back(dest_dir);
- String export_str;
- err = OS::get_singleton()->execute("xcodebuild", export_args, &export_str, nullptr, true);
- ERR_FAIL_COND_V(err, err);
-
- print_line("xcodebuild (.ipa):\n" + export_str);
- if (!export_str.contains("** EXPORT SUCCEEDED **")) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), TTR(".ipa export failed, see editor log for details."));
- return FAILED;
+ if (!p_skip_ipa) {
+ if (ep.step("Making .ipa", 4)) {
+ return ERR_SKIP;
+ }
+ List<String> export_args;
+ export_args.push_back("-exportArchive");
+ export_args.push_back("-archivePath");
+ export_args.push_back(archive_path);
+ export_args.push_back("-exportOptionsPlist");
+ export_args.push_back(dest_dir + binary_name + "/export_options.plist");
+ export_args.push_back("-allowProvisioningUpdates");
+ export_args.push_back("-exportPath");
+ export_args.push_back(dest_dir);
+ String export_str;
+ err = OS::get_singleton()->execute("xcodebuild", export_args, &export_str, nullptr, true);
+ ERR_FAIL_COND_V(err, err);
+ print_line("xcodebuild (.ipa):\n" + export_str);
+ if (!export_str.contains("** EXPORT SUCCEEDED **")) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), TTR(".ipa export failed, see editor log for details."));
+ return FAILED;
+ }
}
#else
add_message(EXPORT_MESSAGE_WARNING, TTR("Xcode Build"), TTR(".ipa can only be built on macOS. Leaving Xcode project without building the package."));
@@ -1900,16 +1925,15 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
}
bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
- String err;
- bool valid = false;
-
#ifdef MODULE_MONO_ENABLED
- err += TTR("Exporting to iOS is currently not supported in Godot 4 when using C#/.NET. Use Godot 3 to target iOS with C#/Mono instead.") + "\n";
- err += TTR("If this project does not use C#, use a non-C# editor build to export the project.") + "\n";
// Don't check for additional errors, as this particular error cannot be resolved.
- r_error = err;
+ r_error += TTR("Exporting to iOS is currently not supported in Godot 4 when using C#/.NET. Use Godot 3 to target iOS with C#/Mono instead.") + "\n";
+ r_error += TTR("If this project does not use C#, use a non-C# editor build to export the project.") + "\n";
return false;
-#endif
+#else
+
+ String err;
+ bool valid = false;
// Look for export templates (first official, and if defined custom templates).
@@ -1937,6 +1961,7 @@ bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExp
}
return valid;
+#endif // !MODULE_MONO_ENABLED
}
bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
@@ -1972,26 +1997,419 @@ bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref<EditorEx
return valid;
}
+int EditorExportPlatformIOS::get_options_count() const {
+ MutexLock lock(device_lock);
+ return devices.size();
+}
+
+String EditorExportPlatformIOS::get_options_tooltip() const {
+ return TTR("Select device from the list");
+}
+
+Ref<ImageTexture> EditorExportPlatformIOS::get_option_icon(int p_index) const {
+ MutexLock lock(device_lock);
+
+ Ref<ImageTexture> icon;
+ if (p_index >= 0 || p_index < devices.size()) {
+ Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
+ if (theme.is_valid()) {
+ if (devices[p_index].simulator) {
+ icon = theme->get_icon("IOSSimulator", "EditorIcons");
+ } else if (devices[p_index].wifi) {
+ icon = theme->get_icon("IOSDeviceWireless", "EditorIcons");
+ } else {
+ icon = theme->get_icon("IOSDeviceWired", "EditorIcons");
+ }
+ }
+ }
+ return icon;
+}
+
+String EditorExportPlatformIOS::get_option_label(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, devices.size(), "");
+ MutexLock lock(device_lock);
+ return devices[p_index].name;
+}
+
+String EditorExportPlatformIOS::get_option_tooltip(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, devices.size(), "");
+ MutexLock lock(device_lock);
+ return "UUID: " + devices[p_index].id;
+}
+
+bool EditorExportPlatformIOS::is_package_name_valid(const String &p_package, String *r_error) const {
+ String pname = p_package;
+
+ if (pname.length() == 0) {
+ if (r_error) {
+ *r_error = TTR("Identifier is missing.");
+ }
+ return false;
+ }
+
+ for (int i = 0; i < pname.length(); i++) {
+ char32_t c = pname[i];
+ if (!(is_ascii_alphanumeric_char(c) || c == '-' || c == '.')) {
+ if (r_error) {
+ *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#ifdef MACOS_ENABLED
+void EditorExportPlatformIOS::_check_for_changes_poll_thread(void *ud) {
+ EditorExportPlatformIOS *ea = static_cast<EditorExportPlatformIOS *>(ud);
+
+ while (!ea->quit_request.is_set()) {
+ // Nothing to do if we already know the plugins have changed.
+ if (!ea->plugins_changed.is_set()) {
+ MutexLock lock(ea->plugins_lock);
+
+ Vector<PluginConfigIOS> loaded_plugins = get_plugins();
+
+ if (ea->plugins.size() != loaded_plugins.size()) {
+ ea->plugins_changed.set();
+ } else {
+ for (int i = 0; i < ea->plugins.size(); i++) {
+ if (ea->plugins[i].name != loaded_plugins[i].name || ea->plugins[i].last_updated != loaded_plugins[i].last_updated) {
+ ea->plugins_changed.set();
+ break;
+ }
+ }
+ }
+ }
+
+ // Check for devices updates.
+ Vector<Device> ldevices;
+
+ // Enum real devices.
+ String idepl = EDITOR_GET("export/ios/ios_deploy");
+ if (idepl.is_empty()) {
+ idepl = "ios-deploy";
+ }
+ {
+ String devices;
+ List<String> args;
+ args.push_back("-c");
+ args.push_back("-timeout");
+ args.push_back("1");
+ args.push_back("-j");
+ args.push_back("-u");
+ args.push_back("-I");
+
+ int ec = 0;
+ Error err = OS::get_singleton()->execute(idepl, args, &devices, &ec, true);
+ if (err == OK && ec == 0) {
+ Ref<JSON> json;
+ json.instantiate();
+ devices = "{ \"devices\":[" + devices.replace("}{", "},{") + "]}";
+ err = json->parse(devices);
+ if (err == OK) {
+ Dictionary data = json->get_data();
+ Array devices = data["devices"];
+ for (int i = 0; i < devices.size(); i++) {
+ Dictionary device_event = devices[i];
+ if (device_event["Event"] == "DeviceDetected") {
+ Dictionary device_info = device_event["Device"];
+ Device nd;
+ nd.id = device_info["DeviceIdentifier"];
+ nd.name = device_info["DeviceName"].operator String() + " (connected through " + device_event["Interface"].operator String() + ")";
+ nd.wifi = device_event["Interface"] == "WIFI";
+ nd.simulator = false;
+ ldevices.push_back(nd);
+ }
+ }
+ }
+ }
+ }
+
+ // Enum simulators
+ if (FileAccess::exists("/usr/bin/xcrun") || FileAccess::exists("/bin/xcrun")) {
+ String devices;
+ List<String> args;
+ args.push_back("simctl");
+ args.push_back("list");
+ args.push_back("devices");
+ args.push_back("-j");
+
+ int ec = 0;
+ Error err = OS::get_singleton()->execute("xcrun", args, &devices, &ec, true);
+ if (err == OK && ec == 0) {
+ Ref<JSON> json;
+ json.instantiate();
+ err = json->parse(devices);
+ if (err == OK) {
+ Dictionary data = json->get_data();
+ Dictionary devices = data["devices"];
+ for (const Variant *key = devices.next(nullptr); key; key = devices.next(key)) {
+ Array os_devices = devices[*key];
+ for (int i = 0; i < os_devices.size(); i++) {
+ Dictionary device_info = os_devices[i];
+ if (device_info["isAvailable"].operator bool() && device_info["state"] == "Booted") {
+ Device nd;
+ nd.id = device_info["udid"];
+ nd.name = device_info["name"].operator String() + " (simulator)";
+ nd.simulator = true;
+ ldevices.push_back(nd);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Update device list.
+ {
+ MutexLock lock(ea->device_lock);
+
+ bool different = false;
+
+ if (ea->devices.size() != ldevices.size()) {
+ different = true;
+ } else {
+ for (int i = 0; i < ea->devices.size(); i++) {
+ if (ea->devices[i].id != ldevices[i].id) {
+ different = true;
+ break;
+ }
+ }
+ }
+
+ if (different) {
+ ea->devices = ldevices;
+ ea->devices_changed.set();
+ }
+ }
+
+ uint64_t sleep = 200;
+ uint64_t wait = 3000000;
+ uint64_t time = OS::get_singleton()->get_ticks_usec();
+ while (OS::get_singleton()->get_ticks_usec() - time < wait) {
+ OS::get_singleton()->delay_usec(1000 * sleep);
+ if (ea->quit_request.is_set()) {
+ break;
+ }
+ }
+ }
+}
+#endif
+
+Error EditorExportPlatformIOS::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
+#ifdef MACOS_ENABLED
+ ERR_FAIL_INDEX_V(p_device, devices.size(), ERR_INVALID_PARAMETER);
+
+ String can_export_error;
+ bool can_export_missing_templates;
+ if (!can_export(p_preset, can_export_error, can_export_missing_templates)) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), can_export_error);
+ return ERR_UNCONFIGURED;
+ }
+
+ MutexLock lock(device_lock);
+
+ EditorProgress ep("run", vformat(TTR("Running on %s"), devices[p_device].name), 3);
+
+ String id = "tmpexport." + uitos(OS::get_singleton()->get_unix_time());
+
+ Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + EditorPaths::get_singleton()->get_cache_dir() + "'.");
+ filesystem_da->make_dir_recursive(EditorPaths::get_singleton()->get_cache_dir().path_join(id));
+ String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().path_join(id).path_join("export.ipa");
+
+#define CLEANUP_AND_RETURN(m_err) \
+ { \
+ if (filesystem_da->change_dir(EditorPaths::get_singleton()->get_cache_dir().path_join(id)) == OK) { \
+ filesystem_da->erase_contents_recursive(); \
+ filesystem_da->change_dir(".."); \
+ filesystem_da->remove(id); \
+ } \
+ return m_err; \
+ } \
+ ((void)0)
+
+ Device dev = devices[p_device];
+
+ // Export before sending to device.
+ Error err = _export_project_helper(p_preset, true, tmp_export_path, p_debug_flags, dev.simulator, true);
+
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ Vector<String> cmd_args_list;
+ String host = EDITOR_GET("network/debug/remote_host");
+ int remote_port = (int)EDITOR_GET("network/debug/remote_port");
+
+ if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST) {
+ host = "localhost";
+ }
+
+ if (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT) {
+ int port = EDITOR_GET("filesystem/file_server/port");
+ String passwd = EDITOR_GET("filesystem/file_server/password");
+ cmd_args_list.push_back("--remote-fs");
+ cmd_args_list.push_back(host + ":" + itos(port));
+ if (!passwd.is_empty()) {
+ cmd_args_list.push_back("--remote-fs-password");
+ cmd_args_list.push_back(passwd);
+ }
+ }
+
+ if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
+ cmd_args_list.push_back("--remote-debug");
+
+ cmd_args_list.push_back(get_debug_protocol() + host + ":" + String::num(remote_port));
+
+ List<String> breakpoints;
+ ScriptEditor::get_singleton()->get_breakpoints(&breakpoints);
+
+ if (breakpoints.size()) {
+ cmd_args_list.push_back("--breakpoints");
+ String bpoints;
+ for (const List<String>::Element *E = breakpoints.front(); E; E = E->next()) {
+ bpoints += E->get().replace(" ", "%20");
+ if (E->next()) {
+ bpoints += ",";
+ }
+ }
+
+ cmd_args_list.push_back(bpoints);
+ }
+ }
+
+ if (p_debug_flags & DEBUG_FLAG_VIEW_COLLISIONS) {
+ cmd_args_list.push_back("--debug-collisions");
+ }
+
+ if (p_debug_flags & DEBUG_FLAG_VIEW_NAVIGATION) {
+ cmd_args_list.push_back("--debug-navigation");
+ }
+
+ if (dev.simulator) {
+ // Deploy and run on simulator.
+ if (ep.step("Installing to simulator...", 3)) {
+ CLEANUP_AND_RETURN(ERR_SKIP);
+ } else {
+ List<String> args;
+ args.push_back("simctl");
+ args.push_back("install");
+ args.push_back(dev.id);
+ args.push_back(EditorPaths::get_singleton()->get_cache_dir().path_join(id).path_join("export.xcarchive/Products/Applications/export.app"));
+
+ String log;
+ int ec;
+ err = OS::get_singleton()->execute("xcrun", args, &log, &ec, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Run"), TTR("Could not start simctl executable."));
+ CLEANUP_AND_RETURN(err);
+ }
+ if (ec != 0) {
+ print_line("simctl install:\n" + log);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), TTR("Installation failed, see editor log for details."));
+ CLEANUP_AND_RETURN(ERR_UNCONFIGURED);
+ }
+ }
+
+ if (ep.step("Running on simulator...", 4)) {
+ CLEANUP_AND_RETURN(ERR_SKIP);
+ } else {
+ List<String> args;
+ args.push_back("simctl");
+ args.push_back("launch");
+ args.push_back(dev.id);
+ args.push_back(p_preset->get("application/bundle_identifier"));
+ for (const String &E : cmd_args_list) {
+ args.push_back(E);
+ }
+
+ String log;
+ int ec;
+ err = OS::get_singleton()->execute("xcrun", args, &log, &ec, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Run"), TTR("Could not start simctl executable."));
+ CLEANUP_AND_RETURN(err);
+ }
+ if (ec != 0) {
+ print_line("simctl launch:\n" + log);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), TTR("Running failed, see editor log for details."));
+ }
+ }
+ } else {
+ // Deploy and run on real device.
+ if (ep.step("Installing and running on device...", 4)) {
+ CLEANUP_AND_RETURN(ERR_SKIP);
+ } else {
+ List<String> args;
+ args.push_back("-u");
+ args.push_back("-I");
+ args.push_back("--id");
+ args.push_back(dev.id);
+ args.push_back("--justlaunch");
+ args.push_back("--bundle");
+ args.push_back(EditorPaths::get_singleton()->get_cache_dir().path_join(id).path_join("export.xcarchive/Products/Applications/export.app"));
+ String app_args;
+ for (const String &E : cmd_args_list) {
+ app_args += E + " ";
+ }
+ if (!app_args.is_empty()) {
+ args.push_back("--args");
+ args.push_back(app_args);
+ }
+
+ String idepl = EDITOR_GET("export/ios/ios_deploy");
+ if (idepl.is_empty()) {
+ idepl = "ios-deploy";
+ }
+ String log;
+ int ec;
+ err = OS::get_singleton()->execute(idepl, args, &log, &ec, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Run"), TTR("Could not start ios-deploy executable."));
+ CLEANUP_AND_RETURN(err);
+ }
+ if (ec != 0) {
+ print_line("ios-deploy:\n" + log);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), TTR("Installation/running failed, see editor log for details."));
+ CLEANUP_AND_RETURN(ERR_UNCONFIGURED);
+ }
+ }
+ }
+
+ CLEANUP_AND_RETURN(OK);
+
+#undef CLEANUP_AND_RETURN
+#else
+ return ERR_UNCONFIGURED;
+#endif
+}
+
EditorExportPlatformIOS::EditorExportPlatformIOS() {
if (EditorNode::get_singleton()) {
#ifdef MODULE_SVG_ENABLED
Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
- ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false);
logo = ImageTexture::create_from_image(img);
+
+ ImageLoaderSVG::create_image_from_string(img, _ios_run_icon_svg, EDSCALE, upsample, false);
+ run_icon = ImageTexture::create_from_image(img);
#endif
plugins_changed.set();
-#ifndef ANDROID_ENABLED
+ devices_changed.set();
+#ifdef MACOS_ENABLED
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
#endif
}
}
EditorExportPlatformIOS::~EditorExportPlatformIOS() {
-#ifndef ANDROID_ENABLED
+#ifdef MACOS_ENABLED
quit_request.set();
if (check_for_changes_thread.is_started()) {
check_for_changes_thread.wait_to_finish();
diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h
index 6616bbd714..7de4c0b69d 100644
--- a/platform/ios/export/export_plugin.h
+++ b/platform/ios/export/export_plugin.h
@@ -45,6 +45,7 @@
#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform.h"
#include "main/splash.gen.h"
+#include "scene/resources/image_texture.h"
#include <string.h>
#include <sys/stat.h>
@@ -58,15 +59,30 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
GDCLASS(EditorExportPlatformIOS, EditorExportPlatform);
Ref<ImageTexture> logo;
+ Ref<ImageTexture> run_icon;
// Plugins
mutable SafeFlag plugins_changed;
-#ifndef ANDROID_ENABLED
+ SafeFlag devices_changed;
+
+ struct Device {
+ String id;
+ String name;
+ bool simulator = false;
+ bool wifi = false;
+ };
+
+ Vector<Device> devices;
+ Mutex device_lock;
+
+ Mutex plugins_lock;
+ mutable Vector<PluginConfigIOS> plugins;
+#ifdef MACOS_ENABLED
Thread check_for_changes_thread;
SafeFlag quit_request;
+
+ static void _check_for_changes_poll_thread(void *ud);
#endif
- Mutex plugins_lock;
- mutable Vector<PluginConfigIOS> plugins;
typedef Error (*FileHandler)(String p_file, void *p_userdata);
static Error _walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata);
@@ -122,64 +138,9 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
Error _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
Error _export_ios_plugins(const Ref<EditorExportPreset> &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector<IOSExportAsset> &r_exported_assets, bool p_debug);
- bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
- String pname = p_package;
-
- if (pname.length() == 0) {
- if (r_error) {
- *r_error = TTR("Identifier is missing.");
- }
- return false;
- }
-
- for (int i = 0; i < pname.length(); i++) {
- char32_t c = pname[i];
- if (!(is_ascii_alphanumeric_char(c) || c == '-' || c == '.')) {
- if (r_error) {
- *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
- }
- return false;
- }
- }
-
- return true;
- }
+ Error _export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags, bool p_simulator, bool p_skip_ipa);
-#ifndef ANDROID_ENABLED
- static void _check_for_changes_poll_thread(void *ud) {
- EditorExportPlatformIOS *ea = static_cast<EditorExportPlatformIOS *>(ud);
-
- while (!ea->quit_request.is_set()) {
- // Nothing to do if we already know the plugins have changed.
- if (!ea->plugins_changed.is_set()) {
- MutexLock lock(ea->plugins_lock);
-
- Vector<PluginConfigIOS> loaded_plugins = get_plugins();
-
- if (ea->plugins.size() != loaded_plugins.size()) {
- ea->plugins_changed.set();
- } else {
- for (int i = 0; i < ea->plugins.size(); i++) {
- if (ea->plugins[i].name != loaded_plugins[i].name || ea->plugins[i].last_updated != loaded_plugins[i].last_updated) {
- ea->plugins_changed.set();
- break;
- }
- }
- }
- }
-
- uint64_t wait = 3000000;
- uint64_t time = OS::get_singleton()->get_ticks_usec();
- while (OS::get_singleton()->get_ticks_usec() - time < wait) {
- OS::get_singleton()->delay_usec(300000);
-
- if (ea->quit_request.is_set()) {
- break;
- }
- }
- }
- }
-#endif
+ bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const;
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
@@ -191,6 +152,23 @@ public:
virtual String get_name() const override { return "iOS"; }
virtual String get_os_name() const override { return "iOS"; }
virtual Ref<Texture2D> get_logo() const override { return logo; }
+ virtual Ref<Texture2D> get_run_icon() const override { return run_icon; }
+
+ virtual int get_options_count() const override;
+ virtual String get_options_tooltip() const override;
+ virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
+ virtual String get_option_label(int p_index) const override;
+ virtual String get_option_tooltip(int p_index) const override;
+ virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
+
+ virtual bool poll_export() override {
+ bool dc = devices_changed.is_set();
+ if (dc) {
+ // don't clear unless we're reporting true, to avoid race
+ devices_changed.clear();
+ }
+ return dc;
+ }
virtual bool should_update_export_options() override {
bool export_options_changed = plugins_changed.is_set();
diff --git a/platform/ios/export/run_icon.svg b/platform/ios/export/run_icon.svg
new file mode 100644
index 0000000000..859c58409e
--- /dev/null
+++ b/platform/ios/export/run_icon.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#bfbfbf" d="M.462 11.653H1.72V6.296H.462Zm.627-6.059a.687.687 0 0 0 .702-.682.688.688 0 0 0-.702-.687.687.687 0 0 0-.698.687c0 .38.309.682.698.682zM5.91 4.24c-2.127 0-3.461 1.45-3.461 3.77 0 2.32 1.333 3.765 3.461 3.765 2.123 0 3.457-1.445 3.457-3.765 0-2.32-1.334-3.77-3.457-3.77zm0 1.112c1.299 0 2.128 1.03 2.128 2.658 0 1.622-.829 2.653-2.128 2.653-1.304 0-2.127-1.03-2.127-2.653 0-1.627.823-2.658 2.127-2.658zm3.988 4.25c.055 1.344 1.157 2.173 2.835 2.173 1.764 0 2.876-.87 2.876-2.254 0-1.086-.627-1.698-2.108-2.037l-.839-.192c-.895-.212-1.263-.495-1.263-.98 0-.607.556-1.01 1.38-1.01.834 0 1.405.408 1.465 1.09h1.244c-.03-1.283-1.092-2.152-2.699-2.152-1.587 0-2.714.874-2.714 2.168 0 1.041.637 1.688 1.981 1.997l.945.222c.92.217 1.294.52 1.294 1.046 0 .606-.611 1.041-1.49 1.041-.89 0-1.562-.44-1.643-1.112H9.899Z" style="stroke-width:.502532;fill:#fff"/></svg>
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index 461c226070..50102e02cc 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, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
+ ERR_FAIL_COND_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/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 9faa73d6d2..a723bb5d58 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -235,11 +235,15 @@ def configure(env: "Environment"):
env.ParseConfig("pkg-config libenet --cflags --libs")
if not env["builtin_squish"]:
- env.ParseConfig("pkg-config libsquish --cflags --libs")
+ # libsquish doesn't reliably install its .pc file, so some distros lack it.
+ env.Append(LIBS=["libsquish"])
if not env["builtin_zstd"]:
env.ParseConfig("pkg-config libzstd --cflags --libs")
+ if env["brotli"] and not env["builtin_brotli"]:
+ env.ParseConfig("pkg-config libbrotlicommon libbrotlidec --cflags --libs")
+
# Sound and video libraries
# Keep the order as it triggers chained dependencies (ogg needed by others, etc.)
@@ -287,6 +291,9 @@ def configure(env: "Environment"):
# No pkgconfig file so far, hardcode expected lib name.
env.Append(LIBS=["embree3"])
+ if not env["builtin_openxr"]:
+ env.ParseConfig("pkg-config openxr --cflags --libs")
+
if env["fontconfig"]:
if not env["use_sowrap"]:
if os.system("pkg-config --exists fontconfig") == 0: # 0 means found
diff --git a/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml b/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml
index 77a6ece756..07378566c3 100644
--- a/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml
+++ b/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlatformLinuxBSD" inherits="EditorExportPlatformPC" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorExportPlatformLinuxBSD" inherits="EditorExportPlatformPC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for Linux/BSD.
</brief_description>
diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp
index f74bdf3516..40151b1a02 100644
--- a/platform/linuxbsd/export/export_plugin.cpp
+++ b/platform/linuxbsd/export/export_plugin.cpp
@@ -521,11 +521,10 @@ EditorExportPlatformLinuxBSD::EditorExportPlatformLinuxBSD() {
Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
- ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false);
set_logo(ImageTexture::create_from_image(img));
- img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img);
#endif
diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h
index cef714e86e..21bd81ed2f 100644
--- a/platform/linuxbsd/export/export_plugin.h
+++ b/platform/linuxbsd/export/export_plugin.h
@@ -34,7 +34,7 @@
#include "core/io/file_access.h"
#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform_pc.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/image_texture.h"
class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC {
GDCLASS(EditorExportPlatformLinuxBSD, EditorExportPlatformPC);
diff --git a/platform/linuxbsd/export/run_icon.svg b/platform/linuxbsd/export/run_icon.svg
index 56465a0df3..ad58bcd5c7 100644
--- a/platform/linuxbsd/export/run_icon.svg
+++ b/platform/linuxbsd/export/run_icon.svg
@@ -1 +1 @@
-<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M7.941 13.966a3.62 3.62 0 0 1-.096.444 2.129 2.129 0 0 1-.31.668c.15.01.305.01.464.003.16.008.314.007.465-.003a2.129 2.129 0 0 1-.31-.668 3.62 3.62 0 0 1-.097-.444l-.058.001-.058-.001z" fill="#333" style="stroke-width:.472092;fill:#e0e0e0;fill-opacity:1"/><path d="M10.688 10.793c-.297.005-.441.299-.707.33-.328.038-.533-.34-.996-.058-.463.283-.862 3.528.212 3.97 1.074.442 3.072-2.146 2.942-2.673-.13-.527-.542-.403-.747-.66-.206-.258 0-.666-.47-.86a.588.588 0 0 0-.234-.05zm-5.411 0a.62.62 0 0 0-.199.05c-.47.193-.264.601-.47.859-.205.257-.618.133-.748.66s1.867 3.115 2.942 2.673c1.074-.442.674-3.687.211-3.97-.463-.283-.668.096-.995.058-.277-.032-.42-.349-.741-.33z" fill="#f4bb37" style="stroke-width:.472092;fill:#e0e0e0;fill-opacity:1"/><path d="M8 .914c-1.386 0-2.2.845-2.353 1.985-.153 1.14.094 1.348-.29 2.515s-2.103 3.168-2.063 5.013c.012.575.078 1.072.194 1.507a1.25 1.25 0 0 1 .503-.47 4.37 4.37 0 0 1 .204-.09c.004-.03.019-.098.046-.23.038-.182.183-.467.43-.654a4.773 4.773 0 0 1-.006-.172c-.029-1.431 1.45-2.982 1.723-3.888.272-.905.154-.998.199-1.223.045-.225.218-.487.468-.696a.11.11 0 0 1 .07-.028c.228-.003.456.826.897.827.44 0 .67-1.01.923-.799.25.21.423.471.468.696.045.225-.073.318.199 1.223.272.906 1.75 2.457 1.722 3.888-.001.058-.004.114-.007.17a1.2 1.2 0 0 1 .432.656c.027.132.042.2.046.23.027.01.085.037.204.092.153.07.36.236.502.47.115-.435.183-.933.195-1.509.04-1.845-1.681-3.846-2.065-5.013-.383-1.167-.135-1.376-.288-2.515C10.2 1.759 9.385.914 7.999.914Z" fill="#333" style="stroke-width:.472092;fill:#e0e0e0;fill-opacity:1"/></svg>
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M7.941 13.966a3.62 3.62 0 0 1-.096.444 2.129 2.129 0 0 1-.31.668c.15.01.305.01.464.003.16.008.314.007.465-.003a2.129 2.129 0 0 1-.31-.668 3.62 3.62 0 0 1-.097-.444zM8 .914c-1.386 0-2.2.845-2.353 1.985-.153 1.14.094 1.348-.29 2.515s-2.103 3.168-2.063 5.013c.012.575.078 1.072.194 1.507a1.25 1.25 0 0 1 .503-.47 4.37 4.37 0 0 1 .204-.09c.004-.03.019-.098.046-.23.038-.182.183-.467.43-.654a4.773 4.773 0 0 1-.006-.172c-.029-1.431 1.45-2.982 1.723-3.888.272-.905.154-.998.199-1.223.045-.225.218-.487.468-.696.253-.211.483.798.945.799.462 0 .692-1.01.945-.799.25.21.423.471.468.696.045.225-.073.318.199 1.223.272.906 1.75 2.457 1.722 3.888a4.773 4.773 0 0 0-.007.17 1.2 1.2 0 0 1 .432.656c.027.132.042.2.046.23.027.01.085.037.204.092.153.07.36.236.502.47.115-.435.183-.933.195-1.509.04-1.845-1.681-3.846-2.065-5.013-.383-1.167-.135-1.376-.288-2.515C10.2 1.759 9.385.914 7.999.914z" fill="#333" style="fill:#e0e0e0;fill-opacity:1"/><path d="M10.688 10.793c-.297.005-.441.299-.707.33-.328.038-.533-.34-.996-.058-.463.283-.862 3.528.212 3.97 1.074.442 3.072-2.146 2.942-2.673-.13-.527-.542-.403-.747-.66-.206-.258 0-.666-.47-.86a.588.588 0 0 0-.234-.05zm-5.411 0a.62.62 0 0 0-.199.05c-.47.193-.264.601-.47.859-.205.257-.618.133-.748.66s1.867 3.115 2.942 2.673c1.074-.442.674-3.687.211-3.97-.463-.283-.668.096-.995.058-.277-.032-.42-.349-.741-.33z" fill="#f4bb37" style="fill:#e0e0e0;fill-opacity:1"/></svg>
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index ab79885fb4..342cff82e9 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -98,19 +98,20 @@ static bool detect_sandbox() {
JoypadLinux::JoypadLinux(Input *in) {
#ifdef UDEV_ENABLED
-#ifdef SOWRAP_ENABLED
-#ifdef DEBUG_ENABLED
- int dylibloader_verbose = 1;
-#else
- int dylibloader_verbose = 0;
-#endif
if (detect_sandbox()) {
// Linux binaries in sandboxes / containers need special handling because
// libudev doesn't work there. So we need to fallback to manual parsing
// of /dev/input in such case.
use_udev = false;
print_verbose("JoypadLinux: udev enabled, but detected incompatible sandboxed mode. Falling back to /dev/input to detect joypads.");
- } else {
+ }
+#ifdef SOWRAP_ENABLED
+ else {
+#ifdef DEBUG_ENABLED
+ int dylibloader_verbose = 1;
+#else
+ int dylibloader_verbose = 0;
+#endif
use_udev = initialize_libudev(dylibloader_verbose) == 0;
if (use_udev) {
if (!udev_new || !udev_unref || !udev_enumerate_new || !udev_enumerate_add_match_subsystem || !udev_enumerate_scan_devices || !udev_enumerate_get_list_entry || !udev_list_entry_get_next || !udev_list_entry_get_name || !udev_device_new_from_syspath || !udev_device_get_devnode || !udev_device_get_action || !udev_device_unref || !udev_enumerate_unref || !udev_monitor_new_from_netlink || !udev_monitor_filter_add_match_subsystem_devtype || !udev_monitor_enable_receiving || !udev_monitor_get_fd || !udev_monitor_receive_device || !udev_monitor_unref) {
@@ -124,10 +125,11 @@ JoypadLinux::JoypadLinux(Input *in) {
print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads.");
}
}
-#endif
+#endif // SOWRAP_ENABLED
#else
print_verbose("JoypadLinux: udev disabled, parsing /dev/input to detect joypads.");
-#endif
+#endif // UDEV_ENABLED
+
input = in;
monitor_joypads_thread.start(monitor_joypads_thread_func, this);
joypad_events_thread.start(joypad_events_thread_func, this);
@@ -391,6 +393,16 @@ void JoypadLinux::open_joypad(const char *p_path) {
return;
}
+ uint16_t vendor = BSWAP16(inpid.vendor);
+ uint16_t product = BSWAP16(inpid.product);
+ uint16_t version = BSWAP16(inpid.version);
+
+ if (input->should_ignore_device(vendor, product)) {
+ // This can be true in cases where Steam is passing information into the game to ignore
+ // original gamepads when using virtual rebindings (See SteamInput).
+ return;
+ }
+
MutexLock lock(joypads_mutex[joy_num]);
Joypad &joypad = joypads[joy_num];
joypad.reset();
@@ -399,10 +411,6 @@ void JoypadLinux::open_joypad(const char *p_path) {
setup_joypad_properties(joypad);
sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0);
if (inpid.vendor && inpid.product && inpid.version) {
- uint16_t vendor = BSWAP16(inpid.vendor);
- uint16_t product = BSWAP16(inpid.product);
- uint16_t version = BSWAP16(inpid.version);
-
sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor, 0, product, 0, version, 0);
input->joy_connection_changed(joy_num, true, name, uid);
} else {
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 310778388b..14d02a73c8 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -954,45 +954,33 @@ static String get_mountpoint(const String &p_path) {
}
Error OS_LinuxBSD::move_to_trash(const String &p_path) {
- String path = p_path.rstrip("/"); // Strip trailing slash when path points to a directory
+ // We try multiple methods, until we find one that works.
+ // So we only return on success until we exhausted possibilities.
+ String path = p_path.rstrip("/"); // Strip trailing slash when path points to a directory.
int err_code;
List<String> args;
args.push_back(path);
- args.push_front("trash"); // The command is `gio trash <file_name>` so we need to add it to args.
+
+ args.push_front("trash"); // The command is `gio trash <file_name>` so we add it before the path.
Error result = execute("gio", args, nullptr, &err_code); // For GNOME based machines.
- if (result == OK) { // The `execute` function has done its job without errors.
- if (!err_code) { // The shell command has been executed without errors.
- return OK;
- } else if (err_code == 1) {
- ERR_PRINT("move_to_trash: No such file or directory as " + path + ".");
- return ERR_FILE_NOT_FOUND;
- }
+ if (result == OK && err_code == 0) { // Success.
+ return OK;
}
args.pop_front();
args.push_front("move");
args.push_back("trash:/"); // The command is `kioclient5 move <file_name> trash:/`.
result = execute("kioclient5", args, nullptr, &err_code); // For KDE based machines.
- if (result == OK) { // The `execute` function has done its job without errors.
- if (!err_code) { // The shell command has been executed without errors.
- return OK;
- } else if (err_code == 1) {
- ERR_PRINT("move_to_trash: No such file or directory as " + path + ".");
- return ERR_FILE_NOT_FOUND;
- }
+ if (result == OK && err_code == 0) {
+ return OK;
}
args.pop_front();
args.pop_back();
result = execute("gvfs-trash", args, nullptr, &err_code); // For older Linux machines.
- if (result == OK) { // The `execute` function has done its job without errors.
- if (!err_code) { // The shell command has been executed without errors.
- return OK;
- } else if (err_code == 1) {
- ERR_PRINT("move_to_trash: No such file or directory as " + path + ".");
- return ERR_FILE_NOT_FOUND;
- }
+ if (result == OK && err_code == 0) {
+ return OK;
}
// If the commands `kioclient5`, `gio` or `gvfs-trash` don't work on the system we do it manually.
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 8724bc871a..7189a1c1c9 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -40,7 +40,7 @@
#include "core/string/print_string.h"
#include "core/string/ustring.h"
#include "main/main.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/atlas_texture.h"
#if defined(VULKAN_ENABLED)
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
@@ -2980,6 +2980,30 @@ Key DisplayServerX11::keyboard_get_keycode_from_physical(Key p_keycode) const {
return (Key)(key | modifiers);
}
+Key DisplayServerX11::keyboard_get_label_from_physical(Key p_keycode) const {
+ Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
+ Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK;
+ unsigned int xkeycode = KeyMappingX11::get_xlibcode(keycode_no_mod);
+ KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, keyboard_get_current_layout(), 0);
+ if (is_ascii_lower_case(xkeysym)) {
+ xkeysym -= ('a' - 'A');
+ }
+
+ Key key = KeyMappingX11::get_keycode(xkeysym);
+#ifdef XKB_ENABLED
+ if (xkb_loaded_v08p) {
+ String keysym = String::chr(xkb_keysym_to_utf32(xkb_keysym_to_upper(xkeysym)));
+ key = fix_key_label(keysym[0], KeyMappingX11::get_keycode(xkeysym));
+ }
+#endif
+
+ // If not found, fallback to QWERTY.
+ // This should match the behavior of the event pump
+ if (key == Key::NONE) {
+ return p_keycode;
+ }
+ return (Key)(key | modifiers);
+}
DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display, Window p_window, Atom p_property) {
Atom actual_type = None;
int actual_format = 0;
@@ -4880,6 +4904,8 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
if (p_icon.is_valid()) {
+ ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0);
+
Ref<Image> img = p_icon->duplicate();
img->convert(Image::FORMAT_RGBA8);
@@ -5449,7 +5475,9 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
#else
#ifdef XKB_ENABLED
- xkb_loaded = true;
+ bool xkb_loaded = true;
+ xkb_loaded_v05p = true;
+ xkb_loaded_v08p = true;
#endif
#endif
@@ -5476,6 +5504,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
r_error = OK;
+#ifdef SOWRAP_ENABLED
{
if (!XcursorImageCreate || !XcursorImageLoadCursor || !XcursorImageDestroy || !XcursorGetDefaultSize || !XcursorGetTheme || !XcursorLibraryLoadImage) {
// There's no API to check version, check if functions are available instead.
@@ -5484,6 +5513,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
return;
}
}
+#endif
for (int i = 0; i < CURSOR_MAX; i++) {
cursors[i] = None;
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 180362923b..70703d42c3 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -502,6 +502,7 @@ public:
virtual String keyboard_get_layout_language(int p_index) const override;
virtual String keyboard_get_layout_name(int p_index) const override;
virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override;
+ virtual Key keyboard_get_label_from_physical(Key p_keycode) const override;
virtual void process_events() override;
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 93fa93b259..e5e0e53bfb 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -315,6 +315,8 @@ public:
virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) override;
virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) override;
+ virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
+
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
@@ -326,6 +328,9 @@ public:
virtual void clipboard_set(const String &p_text) override;
virtual String clipboard_get() const override;
+ virtual Ref<Image> clipboard_get_image() const override;
+ virtual bool clipboard_has() const override;
+ virtual bool clipboard_has_image() const override;
virtual int get_screen_count() const override;
virtual int get_primary_screen() const override;
@@ -433,6 +438,7 @@ public:
virtual String keyboard_get_layout_language(int p_index) const override;
virtual String keyboard_get_layout_name(int p_index) const override;
virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override;
+ virtual Key keyboard_get_label_from_physical(Key p_keycode) const override;
virtual void process_events() override;
virtual void force_process_and_drop_events() override;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 973925a003..d64bb5211e 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -44,8 +44,10 @@
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
+#include "drivers/png/png_driver_common.h"
#include "main/main.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/atlas_texture.h"
+#include "scene/resources/image_texture.h"
#if defined(GLES3_ENABLED)
#include "drivers/gles3/rasterizer_gles3.h"
@@ -1847,6 +1849,176 @@ Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vect
return OK;
}
+Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+ _THREAD_SAFE_METHOD_
+
+ NSString *url = [NSString stringWithUTF8String:p_current_directory.utf8().get_data()];
+ NSMutableArray *allowed_types = [[NSMutableArray alloc] init];
+ bool allow_other = false;
+ for (int i = 0; i < p_filters.size(); i++) {
+ Vector<String> tokens = p_filters[i].split(";");
+ if (tokens.size() > 0) {
+ if (tokens[0].strip_edges() == "*.*") {
+ allow_other = true;
+ } else {
+ [allowed_types addObject:[NSString stringWithUTF8String:tokens[0].replace("*.", "").strip_edges().utf8().get_data()]];
+ }
+ }
+ }
+
+ Callable callback = p_callback; // Make a copy for async completion handler.
+ switch (p_mode) {
+ case FILE_DIALOG_MODE_SAVE_FILE: {
+ NSSavePanel *panel = [NSSavePanel savePanel];
+
+ [panel setDirectoryURL:[NSURL fileURLWithPath:url]];
+ if ([allowed_types count]) {
+ [panel setAllowedFileTypes:allowed_types];
+ }
+ [panel setAllowsOtherFileTypes:allow_other];
+ [panel setExtensionHidden:YES];
+ [panel setCanSelectHiddenExtension:YES];
+ [panel setCanCreateDirectories:YES];
+ [panel setShowsHiddenFiles:p_show_hidden];
+ if (p_filename != "") {
+ NSString *fileurl = [NSString stringWithUTF8String:p_filename.utf8().get_data()];
+ [panel setNameFieldStringValue:fileurl];
+ }
+
+ [panel beginSheetModalForWindow:[[NSApplication sharedApplication] mainWindow]
+ completionHandler:^(NSInteger ret) {
+ if (ret == NSModalResponseOK) {
+ // Save bookmark for folder.
+ if (OS::get_singleton()->is_sandboxed()) {
+ NSArray *bookmarks = [[NSUserDefaults standardUserDefaults] arrayForKey:@"sec_bookmarks"];
+ bool skip = false;
+ for (id bookmark in bookmarks) {
+ NSError *error = nil;
+ BOOL isStale = NO;
+ NSURL *exurl = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
+ if (!error && !isStale && ([[exurl path] compare:[[panel directoryURL] path]] == NSOrderedSame)) {
+ skip = true;
+ break;
+ }
+ }
+ if (!skip) {
+ NSError *error = nil;
+ NSData *bookmark = [[panel directoryURL] bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
+ if (!error) {
+ NSArray *new_bookmarks = [bookmarks arrayByAddingObject:bookmark];
+ [[NSUserDefaults standardUserDefaults] setObject:new_bookmarks forKey:@"sec_bookmarks"];
+ }
+ }
+ }
+ // Callback.
+ Vector<String> files;
+ String url;
+ url.parse_utf8([[[panel URL] path] UTF8String]);
+ files.push_back(url);
+ if (!callback.is_null()) {
+ Variant v_status = true;
+ Variant v_files = files;
+ Variant *v_args[2] = { &v_status, &v_files };
+ Variant ret;
+ Callable::CallError ce;
+ callback.callp((const Variant **)&v_args, 2, ret, ce);
+ }
+ } else {
+ if (!callback.is_null()) {
+ Variant v_status = false;
+ Variant v_files = Vector<String>();
+ Variant *v_args[2] = { &v_status, &v_files };
+ Variant ret;
+ Callable::CallError ce;
+ callback.callp((const Variant **)&v_args, 2, ret, ce);
+ }
+ }
+ }];
+ } break;
+ case FILE_DIALOG_MODE_OPEN_ANY:
+ case FILE_DIALOG_MODE_OPEN_FILE:
+ case FILE_DIALOG_MODE_OPEN_FILES:
+ case FILE_DIALOG_MODE_OPEN_DIR: {
+ NSOpenPanel *panel = [NSOpenPanel openPanel];
+
+ [panel setDirectoryURL:[NSURL fileURLWithPath:url]];
+ if ([allowed_types count]) {
+ [panel setAllowedFileTypes:allowed_types];
+ }
+ [panel setAllowsOtherFileTypes:allow_other];
+ [panel setExtensionHidden:YES];
+ [panel setCanSelectHiddenExtension:YES];
+ [panel setCanCreateDirectories:YES];
+ [panel setCanChooseFiles:(p_mode != FILE_DIALOG_MODE_OPEN_DIR)];
+ [panel setCanChooseDirectories:(p_mode == FILE_DIALOG_MODE_OPEN_DIR || p_mode == FILE_DIALOG_MODE_OPEN_ANY)];
+ [panel setShowsHiddenFiles:p_show_hidden];
+ if (p_filename != "") {
+ NSString *fileurl = [NSString stringWithUTF8String:p_filename.utf8().get_data()];
+ [panel setNameFieldStringValue:fileurl];
+ }
+ [panel setAllowsMultipleSelection:(p_mode == FILE_DIALOG_MODE_OPEN_FILES)];
+
+ [panel beginSheetModalForWindow:[[NSApplication sharedApplication] mainWindow]
+ completionHandler:^(NSInteger ret) {
+ if (ret == NSModalResponseOK) {
+ // Save bookmark for folder.
+ NSArray *urls = [(NSOpenPanel *)panel URLs];
+ if (OS::get_singleton()->is_sandboxed()) {
+ NSArray *bookmarks = [[NSUserDefaults standardUserDefaults] arrayForKey:@"sec_bookmarks"];
+ NSMutableArray *new_bookmarks = [bookmarks mutableCopy];
+ for (NSUInteger i = 0; i != [urls count]; ++i) {
+ bool skip = false;
+ for (id bookmark in bookmarks) {
+ NSError *error = nil;
+ BOOL isStale = NO;
+ NSURL *exurl = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
+ if (!error && !isStale && ([[exurl path] compare:[[urls objectAtIndex:i] path]] == NSOrderedSame)) {
+ skip = true;
+ break;
+ }
+ }
+ if (!skip) {
+ NSError *error = nil;
+ NSData *bookmark = [[urls objectAtIndex:i] bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
+ if (!error) {
+ [new_bookmarks addObject:bookmark];
+ }
+ }
+ }
+ [[NSUserDefaults standardUserDefaults] setObject:new_bookmarks forKey:@"sec_bookmarks"];
+ }
+ // Callback.
+ Vector<String> files;
+ for (NSUInteger i = 0; i != [urls count]; ++i) {
+ String url;
+ url.parse_utf8([[[urls objectAtIndex:i] path] UTF8String]);
+ files.push_back(url);
+ }
+ if (!callback.is_null()) {
+ Variant v_status = true;
+ Variant v_files = files;
+ Variant *v_args[2] = { &v_status, &v_files };
+ Variant ret;
+ Callable::CallError ce;
+ callback.callp((const Variant **)&v_args, 2, ret, ce);
+ }
+ } else {
+ if (!callback.is_null()) {
+ Variant v_status = false;
+ Variant v_files = Vector<String>();
+ Variant *v_args[2] = { &v_status, &v_files };
+ Variant ret;
+ Callable::CallError ce;
+ callback.callp((const Variant **)&v_args, 2, ret, ce);
+ }
+ }
+ }];
+ } break;
+ }
+
+ return OK;
+}
+
Error DisplayServerMacOS::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) {
_THREAD_SAFE_METHOD_
@@ -2100,6 +2272,37 @@ String DisplayServerMacOS::clipboard_get() const {
return ret;
}
+Ref<Image> DisplayServerMacOS::clipboard_get_image() const {
+ Ref<Image> image;
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
+ NSString *result = [pasteboard availableTypeFromArray:[NSArray arrayWithObjects:NSPasteboardTypeTIFF, NSPasteboardTypePNG, nil]];
+ if (!result) {
+ return image;
+ }
+ NSData *data = [pasteboard dataForType:result];
+ if (!data) {
+ return image;
+ }
+ NSBitmapImageRep *bitmap = [NSBitmapImageRep imageRepWithData:data];
+ NSData *pngData = [bitmap representationUsingType:NSPNGFileType properties:@{}];
+ image.instantiate();
+ PNGDriverCommon::png_to_image((const uint8_t *)pngData.bytes, pngData.length, false, image);
+ return image;
+}
+
+bool DisplayServerMacOS::clipboard_has() const {
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
+ NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
+ NSDictionary *options = [NSDictionary dictionary];
+ return [pasteboard canReadObjectForClasses:classArray options:options];
+}
+
+bool DisplayServerMacOS::clipboard_has_image() const {
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
+ NSString *result = [pasteboard availableTypeFromArray:[NSArray arrayWithObjects:NSPasteboardTypeTIFF, NSPasteboardTypePNG, nil]];
+ return result;
+}
+
int DisplayServerMacOS::get_screen_count() const {
_THREAD_SAFE_METHOD_
@@ -3085,14 +3288,14 @@ bool DisplayServerMacOS::window_is_focused(WindowID p_window) const {
}
bool DisplayServerMacOS::window_can_draw(WindowID p_window) const {
- return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED;
+ return (window_get_mode(p_window) != WINDOW_MODE_MINIMIZED) && [windows[p_window].window_object isOnActiveSpace];
}
bool DisplayServerMacOS::can_any_window_draw() const {
_THREAD_SAFE_METHOD_
for (const KeyValue<WindowID, WindowData> &E : windows) {
- if (window_get_mode(E.key) != WINDOW_MODE_MINIMIZED) {
+ if ((window_get_mode(E.key) != WINDOW_MODE_MINIMIZED) && [E.value.window_object isOnActiveSpace]) {
return true;
}
}
@@ -3499,6 +3702,17 @@ Key DisplayServerMacOS::keyboard_get_keycode_from_physical(Key p_keycode) const
return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0, false) | modifiers);
}
+Key DisplayServerMacOS::keyboard_get_label_from_physical(Key p_keycode) const {
+ if (p_keycode == Key::PAUSE || p_keycode == Key::NONE) {
+ return p_keycode;
+ }
+
+ Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
+ Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK;
+ unsigned int macos_keycode = KeyMappingMacOS::unmap_key(keycode_no_mod);
+ return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0, true) | modifiers);
+}
+
void DisplayServerMacOS::process_events() {
_THREAD_SAFE_METHOD_
@@ -3588,55 +3802,67 @@ void DisplayServerMacOS::set_native_icon(const String &p_filename) {
Vector<uint8_t> data;
uint64_t len = f->get_length();
+ ERR_FAIL_COND_MSG(len < 8, "Error reading icon data."); // "icns" + 32-bit length
+
data.resize(len);
f->get_buffer((uint8_t *)&data.write[0], len);
- NSData *icon_data = [[NSData alloc] initWithBytes:&data.write[0] length:len];
- ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data.");
+ @try {
+ NSData *icon_data = [[NSData alloc] initWithBytes:&data.write[0] length:len];
+ ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data.");
- NSImage *icon = [[NSImage alloc] initWithData:icon_data];
- ERR_FAIL_COND_MSG(!icon, "Error loading icon.");
+ NSImage *icon = [[NSImage alloc] initWithData:icon_data];
+ ERR_FAIL_COND_MSG(!icon, "Error loading icon.");
- [NSApp setApplicationIconImage:icon];
+ [NSApp setApplicationIconImage:icon];
+ } @catch (NSException *exception) {
+ ERR_FAIL_MSG("NSException: " + String::utf8([exception reason].UTF8String));
+ }
}
void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) {
_THREAD_SAFE_METHOD_
- Ref<Image> img = p_icon;
- img = img->duplicate();
- img->convert(Image::FORMAT_RGBA8);
- NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:nullptr
- pixelsWide:img->get_width()
- pixelsHigh:img->get_height()
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:img->get_width() * 4
- bitsPerPixel:32];
- ERR_FAIL_COND(imgrep == nil);
- uint8_t *pixels = [imgrep bitmapData];
+ if (p_icon.is_valid()) {
+ ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0);
- int len = img->get_width() * img->get_height();
- const uint8_t *r = img->get_data().ptr();
+ Ref<Image> img = p_icon->duplicate();
+ img->convert(Image::FORMAT_RGBA8);
- /* Premultiply the alpha channel */
- for (int i = 0; i < len; i++) {
- uint8_t alpha = r[i * 4 + 3];
- pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
- pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
- pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
- pixels[i * 4 + 3] = alpha;
- }
+ NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:nullptr
+ pixelsWide:img->get_width()
+ pixelsHigh:img->get_height()
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:img->get_width() * 4
+ bitsPerPixel:32];
+ ERR_FAIL_COND(imgrep == nil);
+ uint8_t *pixels = [imgrep bitmapData];
- NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
- ERR_FAIL_COND(nsimg == nil);
+ int len = img->get_width() * img->get_height();
+ const uint8_t *r = img->get_data().ptr();
- [nsimg addRepresentation:imgrep];
- [NSApp setApplicationIconImage:nsimg];
+ /* Premultiply the alpha channel */
+ for (int i = 0; i < len; i++) {
+ uint8_t alpha = r[i * 4 + 3];
+ pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
+ pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
+ pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
+ pixels[i * 4 + 3] = alpha;
+ }
+
+ NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
+ ERR_FAIL_COND(nsimg == nil);
+
+ [nsimg addRepresentation:imgrep];
+ [NSApp setApplicationIconImage:nsimg];
+ } else {
+ [NSApp setApplicationIconImage:nil];
+ }
}
DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
index cef837de07..6af816989d 100644
--- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
+++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlatformMacOS" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorExportPlatformMacOS" inherits="EditorExportPlatform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for macOS.
</brief_description>
@@ -96,6 +96,9 @@
<member name="codesign/entitlements/app_sandbox/files_pictures" type="int" setter="" getter="">
Allows read or write access to the user's "Pictures" folder. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_assets_pictures_read-write]com.apple.security.files.pictures.read-write[/url].
</member>
+ <member name="codesign/entitlements/app_sandbox/files_user_selected" type="int" setter="" getter="">
+ Allows read or write access to the locations the user has selected using a native file dialog. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_files_user-selected_read-write]com.apple.security.files.user-selected.read-write[/url].
+ </member>
<member name="codesign/entitlements/app_sandbox/helper_executables" type="Array" setter="" getter="">
List of helper executables to embedded to the app bundle. Sandboxed app are limited to execute only these executable. See [url=https://developer.apple.com/documentation/xcode/embedding-a-helper-tool-in-a-sandboxed-app]Embedding a command-line tool in a sandboxed app[/url].
</member>
diff --git a/platform/macos/export/codesign.cpp b/platform/macos/export/codesign.cpp
index a1ec06b5f6..2b8898e6a1 100644
--- a/platform/macos/export/codesign.cpp
+++ b/platform/macos/export/codesign.cpp
@@ -1211,7 +1211,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
// Read Info.plist.
if (!p_info.is_empty()) {
- print_verbose(vformat("CodeSign: Reading bundle info..."));
+ print_verbose("CodeSign: Reading bundle info...");
PList info_plist;
if (info_plist.load_file(p_info)) {
info_hash1 = file_hash_sha1(p_info);
@@ -1262,7 +1262,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
}
}
} else if (MachO::is_macho(main_exe)) {
- print_verbose(vformat("CodeSign: Executable is thin..."));
+ print_verbose("CodeSign: Executable is thin...");
files_to_sign.push_back(main_exe);
} else {
r_error_msg = TTR("Invalid binary format.");
@@ -1284,7 +1284,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
// Generate core resources.
if (!p_bundle_path.is_empty()) {
- print_verbose(vformat("CodeSign: Generating bundle CodeResources..."));
+ print_verbose("CodeSign: Generating bundle CodeResources...");
CodeSignCodeResources cr;
if (p_ios_bundle) {
@@ -1366,7 +1366,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
CharString uuid_str = id.utf8();
print_verbose(vformat("CodeSign: Used bundle ID: %s", id));
- print_verbose(vformat("CodeSign: Processing entitlements..."));
+ print_verbose("CodeSign: Processing entitlements...");
Ref<CodeSignEntitlementsText> cet;
Ref<CodeSignEntitlementsBinary> ceb;
@@ -1381,7 +1381,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
ceb = Ref<CodeSignEntitlementsBinary>(memnew(CodeSignEntitlementsBinary(entitlements)));
}
- print_verbose(vformat("CodeSign: Generating requirements..."));
+ print_verbose("CodeSign: Generating requirements...");
Ref<CodeSignRequirements> rq;
String team_id = "";
rq = Ref<CodeSignRequirements>(memnew(CodeSignRequirements()));
@@ -1396,10 +1396,10 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
}
print_verbose(vformat("CodeSign: Signing executable for cputype: %d ...", mh.get_cputype()));
- print_verbose(vformat("CodeSign: Generating CodeDirectory..."));
+ print_verbose("CodeSign: Generating CodeDirectory...");
Ref<CodeSignCodeDirectory> cd1 = memnew(CodeSignCodeDirectory(0x14, 0x01, true, uuid_str, team_id.utf8(), 12, mh.get_exe_limit(), mh.get_code_limit()));
Ref<CodeSignCodeDirectory> cd2 = memnew(CodeSignCodeDirectory(0x20, 0x02, true, uuid_str, team_id.utf8(), 12, mh.get_exe_limit(), mh.get_code_limit()));
- print_verbose(vformat("CodeSign: Calculating special slot hashes..."));
+ print_verbose("CodeSign: Calculating special slot hashes...");
if (info_hash2.size() == 0x20) {
cd2->set_hash_in_slot(info_hash2, CodeSignCodeDirectory::SLOT_INFO_PLIST);
}
@@ -1444,7 +1444,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
ERR_FAIL_V_MSG(FAILED, "CodeSign: Can't resize signature load command.");
}
- print_verbose(vformat("CodeSign: Calculating executable code hashes..."));
+ print_verbose("CodeSign: Calculating executable code hashes...");
// Calculate executable code hashes.
PackedByteArray buffer;
PackedByteArray hash1, hash2;
@@ -1481,11 +1481,11 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
cd1->set_hash_in_slot(hash1, cd1->get_page_count());
}
- print_verbose(vformat("CodeSign: Generating signature..."));
+ print_verbose("CodeSign: Generating signature...");
Ref<CodeSignSignature> cs;
cs = Ref<CodeSignSignature>(memnew(CodeSignSignature()));
- print_verbose(vformat("CodeSign: Writing signature superblob..."));
+ print_verbose("CodeSign: Writing signature superblob...");
// Write signature data to the executable.
CodeSignSuperBlob sb = CodeSignSuperBlob();
sb.add_blob(cd2);
@@ -1502,7 +1502,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
sb.write_to_file(mh.get_file());
}
if (files_to_sign.size() > 1) {
- print_verbose(vformat("CodeSign: Rebuilding fat executable..."));
+ print_verbose("CodeSign: Rebuilding fat executable...");
LipO lip;
if (!lip.create_file(main_exe, files_to_sign)) {
CLEANUP();
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 2d185db812..81f9707f6b 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -41,6 +41,7 @@
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
+#include "scene/resources/image_texture.h"
#include "modules/modules_enabled.gen.h" // For svg and regex.
#ifdef MODULE_SVG_ENABLED
@@ -425,6 +426,7 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_pictures", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_user_selected", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array()));
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
@@ -1359,7 +1361,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String src_pkg_name;
- EditorProgress ep("export", "Exporting for macOS", 3, true);
+ EditorProgress ep("export", TTR("Exporting for macOS"), 3, true);
if (p_debug) {
src_pkg_name = p_preset->get("custom_template/debug");
@@ -1922,6 +1924,14 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
ent_f->store_line("<key>com.apple.security.files.movies.read-write</key>");
ent_f->store_line("<true/>");
}
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_user_selected") == 1) {
+ ent_f->store_line("<key>com.apple.security.files.user-selected.read-only</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_user_selected") == 2) {
+ ent_f->store_line("<key>com.apple.security.files.user-selected.read-write</key>");
+ ent_f->store_line("<true/>");
+ }
}
ent_f->store_line("</dict>");
@@ -2442,11 +2452,10 @@ EditorExportPlatformMacOS::EditorExportPlatformMacOS() {
Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
- ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false);
logo = ImageTexture::create_from_image(img);
- img_loader.create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img);
#endif
diff --git a/platform/macos/export/run_icon.svg b/platform/macos/export/run_icon.svg
index c7067bb4b6..647270ce22 100644
--- a/platform/macos/export/run_icon.svg
+++ b/platform/macos/export/run_icon.svg
@@ -1 +1 @@
-<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke-width:.93168;-inkscape-stroke:none" d="M4.418 1.055c-1.82 0-3.365 1.537-3.365 3.363v7.164c0 1.829 1.548 3.363 3.365 3.363h7.164c1.828 0 3.363-1.544 3.363-3.363V4.418c0-1.822-1.537-3.363-3.363-3.363H7.729Zm3.875 1.164h3.291c1.149 0 2.2 1.053 2.2 2.199v7.164c0 1.14-1.052 2.2-2.2 2.2h-2.15a8.884 8.884 0 0 1-.358-1.598c-.135.02-.487.082-.693.117a3.947 3.947 0 0 1-.049.004l-.008-.002a7.345 7.345 0 0 1-1.205-.004 7.114 7.114 0 0 1-.926-.139 6.057 6.057 0 0 1-.867-.271 3.843 3.843 0 0 1-.988-.566 3.214 3.214 0 0 1-.397-.378 2.8 2.8 0 0 1-.318-.441.558.558 0 0 1-.059-.424.564.564 0 0 1 .881-.299.56.56 0 0 1 .145.164c.083.138.188.26.312.362.096.082.2.158.307.224.12.075.243.142.371.201.285.139.583.247.89.319a5.35 5.35 0 0 0 1.282.158c.065 0 .129-.005.184-.006.056 0 .102-.005.148-.008l.096-.006c.114-.009.228-.02.31-.032.083-.013.11-.021.143-.028.099-.022.204-.058.327-.089a28.438 28.438 0 0 1-.06-1.929V8.53H6.887c.048-1.963.746-4.357 1.181-5.677.1-.293.184-.527.225-.633ZM4.973 5.03h.002a.562.562 0 0 1 .558.559v.805a.556.556 0 0 1-.558.558.56.56 0 0 1-.397-.162.565.565 0 0 1-.164-.396V5.59a.561.561 0 0 1 .559-.559Z"/><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke-linecap:round;-inkscape-stroke:none" d="M26.117 11.467c.008.11.014.225.022.328.022.283.052.565.088.846l.012.053c1.238-.252 2.448-.829 3.011-1.803a.6.6 0 1 0-1.039-.6c-.28.486-1.161.936-2.094 1.176z" transform="translate(-15.37 .357) scale(.93168)"/><g style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-opacity:1"><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-opacity:1;-inkscape-stroke:none" d="M27.836 5.585v.862" transform="translate(-15.37 .357) scale(.93168)"/><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-linecap:round;stroke-opacity:1;-inkscape-stroke:none" d="M27.836 4.984a.6.6 0 0 0-.6.6v.863a.6.6 0 0 0 .6.6.6.6 0 0 0 .6-.6v-.863a.6.6 0 0 0-.6-.6Z" transform="translate(-15.37 .357) scale(.93168)"/></g></svg>
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path fill="#e0e0e0" d="M4.418 1.055a3.364 3.364 0 0 0-3.364 3.364v7.164a3.364 3.364 0 0 0 3.364 3.364h7.164a3.364 3.364 0 0 0 3.364-3.364V4.418a3.364 3.364 0 0 0-3.364-3.364H7.729Zm3.875 1.164h3.291a2.2 2.2 0 0 1 2.2 2.2v7.164a2.2 2.2 0 0 1-2.2 2.2h-2.15a8.884 8.884 0 0 1-.358-1.598c-.135.02-.487.082-.693.117a7.345 7.345 0 0 1-1.254 0 7.114 7.114 0 0 1-.926-.139 6.057 6.057 0 0 1-.867-.271 3.843 3.843 0 0 1-.988-.566 3.214 3.214 0 0 1-.397-.378 2.8 2.8 0 0 1-.318-.441.56.56 0 0 1 .968-.56c.083.138.188.26.312.362.096.082.2.158.307.224.12.075.243.142.371.201.285.139.583.247.89.319a5.35 5.35 0 0 0 1.282.158c.065 0 .129-.005.184-.006.056 0 .102-.005.148-.008l.096-.006c.114-.009.228-.02.31-.032.083-.013.11-.021.143-.028.099-.022.204-.058.327-.089a28.438 28.438 0 0 1-.06-1.929V8.53H6.887c.048-1.963.746-4.357 1.181-5.677.1-.293.184-.527.225-.633ZM5.531 6.394a.56.56 0 0 1-1.118 0v-.9a.56.56 0 0 1 1.118 0Zm3.432 4.646.02.306c.02.264.049.527.082.788l.011.05c1.154-.235 2.281-.773 2.806-1.68a.56.56 0 1 0-.968-.56c-.261.454-1.082.873-1.951 1.097zM10 6.364a.56.56 0 0 0 1.118 0v-.9a.56.56 0 0 0-1.118 0z"/></svg>
diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h
index ab61649d19..ae94b6296d 100644
--- a/platform/macos/os_macos.h
+++ b/platform/macos/os_macos.h
@@ -113,6 +113,10 @@ public:
virtual String get_unique_id() const override;
virtual String get_processor_name() const override;
+ virtual bool is_sandboxed() const override;
+ virtual Vector<String> get_granted_permissions() const override;
+ virtual void revoke_granted_permissions() override;
+
virtual bool _check_internal_feature_support(const String &p_feature) override;
virtual void disable_crash_handler() override;
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index fe6d8d9fb0..c17ea95f4f 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -76,6 +76,36 @@ String OS_MacOS::get_processor_name() const {
ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string."));
}
+bool OS_MacOS::is_sandboxed() const {
+ return has_environment("APP_SANDBOX_CONTAINER_ID");
+}
+
+Vector<String> OS_MacOS::get_granted_permissions() const {
+ Vector<String> ret;
+
+ if (is_sandboxed()) {
+ NSArray *bookmarks = [[NSUserDefaults standardUserDefaults] arrayForKey:@"sec_bookmarks"];
+ for (id bookmark in bookmarks) {
+ NSError *error = nil;
+ BOOL isStale = NO;
+ NSURL *url = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
+ if (!error && !isStale) {
+ String url_string;
+ url_string.parse_utf8([[url path] UTF8String]);
+ ret.push_back(url_string);
+ }
+ }
+ }
+
+ return ret;
+}
+
+void OS_MacOS::revoke_granted_permissions() {
+ if (is_sandboxed()) {
+ [[NSUserDefaults standardUserDefaults] setObject:nil forKey:@"sec_bookmarks"];
+ }
+}
+
void OS_MacOS::initialize_core() {
OS_Unix::initialize_core();
@@ -85,6 +115,18 @@ void OS_MacOS::initialize_core() {
}
void OS_MacOS::finalize() {
+ if (is_sandboxed()) {
+ NSArray *bookmarks = [[NSUserDefaults standardUserDefaults] arrayForKey:@"sec_bookmarks"];
+ for (id bookmark in bookmarks) {
+ NSError *error = nil;
+ BOOL isStale = NO;
+ NSURL *url = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
+ if (!error && !isStale) {
+ [url stopAccessingSecurityScopedResource];
+ }
+ }
+ }
+
#ifdef COREMIDI_ENABLED
midi_driver.close();
#endif
@@ -189,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, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
+ ERR_FAIL_COND_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;
@@ -733,6 +775,23 @@ void OS_MacOS::run() {
}
OS_MacOS::OS_MacOS() {
+ if (is_sandboxed()) {
+ // Load security-scoped bookmarks, request access, remove stale or invalid bookmarks.
+ NSArray *bookmarks = [[NSUserDefaults standardUserDefaults] arrayForKey:@"sec_bookmarks"];
+ NSMutableArray *new_bookmarks = [[NSMutableArray alloc] init];
+ for (id bookmark in bookmarks) {
+ NSError *error = nil;
+ BOOL isStale = NO;
+ NSURL *url = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
+ if (!error && !isStale) {
+ if ([url startAccessingSecurityScopedResource]) {
+ [new_bookmarks addObject:bookmark];
+ }
+ }
+ }
+ [[NSUserDefaults standardUserDefaults] setObject:new_bookmarks forKey:@"sec_bookmarks"];
+ }
+
main_loop = nullptr;
Vector<Logger *> loggers;
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 0332fbf718..c92520b755 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -34,6 +34,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "scene/resources/image_texture.h"
#include "modules/modules_enabled.gen.h" // For svg and regex.
#ifdef MODULE_SVG_ENABLED
@@ -131,11 +132,11 @@ void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options)
bool EditorExportPlatformUWP::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
#ifndef DEV_ENABLED
// We don't provide export templates for the UWP platform currently as it
- // has not been ported for Godot 4.0. This is skipped in DEV_ENABLED so that
+ // has not been ported for Godot 4. This is skipped in DEV_ENABLED so that
// contributors can still test the pipeline if/when we can build it again.
- r_error = "The UWP platform is currently not supported in Godot 4.0.\n";
+ r_error = "The UWP platform is currently not supported in Godot 4.\n";
return false;
-#endif
+#else
String err;
bool valid = false;
@@ -175,16 +176,17 @@ bool EditorExportPlatformUWP::has_valid_export_configuration(const Ref<EditorExp
}
return valid;
+#endif // DEV_ENABLED
}
bool EditorExportPlatformUWP::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
#ifndef DEV_ENABLED
// We don't provide export templates for the UWP platform currently as it
- // has not been ported for Godot 4.0. This is skipped in DEV_ENABLED so that
+ // has not been ported for Godot 4. This is skipped in DEV_ENABLED so that
// contributors can still test the pipeline if/when we can build it again.
- r_error = "The UWP platform is currently not supported in Godot 4.0.\n";
+ r_error = "The UWP platform is currently not supported in Godot 4.\n";
return false;
-#endif
+#else
String err;
bool valid = true;
@@ -258,6 +260,7 @@ bool EditorExportPlatformUWP::has_valid_project_configuration(const Ref<EditorEx
r_error = err;
return valid;
+#endif // DEV_ENABLED
}
Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
@@ -265,7 +268,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
String src_appx;
- EditorProgress ep("export", "Exporting for UWP", 7, true);
+ EditorProgress ep("export", TTR("Exporting for UWP"), 7, true);
if (p_debug) {
src_appx = p_preset->get("custom_template/debug");
@@ -515,8 +518,7 @@ EditorExportPlatformUWP::EditorExportPlatformUWP() {
Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
- ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, _uwp_logo_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _uwp_logo_svg, EDSCALE, upsample, false);
logo = ImageTexture::create_from_image(img);
#endif
diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h
index cc86bdb280..147279e5c5 100644
--- a/platform/uwp/export/export_plugin.h
+++ b/platform/uwp/export/export_plugin.h
@@ -44,6 +44,7 @@
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/export/editor_export_platform.h"
+#include "scene/resources/compressed_texture.h"
#include "thirdparty/minizip/unzip.h"
#include "thirdparty/minizip/zip.h"
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index df7923660c..b9cd9d0baa 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -745,7 +745,7 @@ static String format_error_message(DWORD id) {
Error OS_UWP::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
String full_path = "game/" + p_path;
p_library_handle = (void *)LoadPackagedLibrary((LPCWSTR)(full_path.utf16().get_data()), 0);
- ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + full_path + ", error: " + format_error_message(GetLastError()) + ".");
+ ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", full_path, format_error_message(GetLastError())));
if (r_resolved_path != nullptr) {
*r_resolved_path = full_path;
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index 951ce110e0..93b0496d74 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -35,6 +35,7 @@
#include "os_web.h"
#include "core/config/project_settings.h"
+#include "scene/resources/atlas_texture.h"
#include "servers/rendering/dummy/rasterizer_dummy.h"
#ifdef GLES3_ENABLED
@@ -731,35 +732,40 @@ void DisplayServerWeb::send_window_event_callback(int p_notification) {
}
void DisplayServerWeb::set_icon(const Ref<Image> &p_icon) {
- ERR_FAIL_COND(p_icon.is_null());
- Ref<Image> icon = p_icon;
- if (icon->is_compressed()) {
- icon = icon->duplicate();
- ERR_FAIL_COND(icon->decompress() != OK);
- }
- if (icon->get_format() != Image::FORMAT_RGBA8) {
- if (icon == p_icon) {
+ if (p_icon.is_valid()) {
+ ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0);
+
+ Ref<Image> icon = p_icon;
+ if (icon->is_compressed()) {
icon = icon->duplicate();
+ ERR_FAIL_COND(icon->decompress() != OK);
+ }
+ if (icon->get_format() != Image::FORMAT_RGBA8) {
+ if (icon == p_icon) {
+ icon = icon->duplicate();
+ }
+ icon->convert(Image::FORMAT_RGBA8);
}
- icon->convert(Image::FORMAT_RGBA8);
- }
- png_image png_meta;
- memset(&png_meta, 0, sizeof png_meta);
- png_meta.version = PNG_IMAGE_VERSION;
- png_meta.width = icon->get_width();
- png_meta.height = icon->get_height();
- png_meta.format = PNG_FORMAT_RGBA;
+ png_image png_meta;
+ memset(&png_meta, 0, sizeof png_meta);
+ png_meta.version = PNG_IMAGE_VERSION;
+ png_meta.width = icon->get_width();
+ png_meta.height = icon->get_height();
+ png_meta.format = PNG_FORMAT_RGBA;
- PackedByteArray png;
- size_t len;
- PackedByteArray data = icon->get_data();
- ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, data.ptr(), 0, nullptr));
+ PackedByteArray png;
+ size_t len;
+ PackedByteArray data = icon->get_data();
+ ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, data.ptr(), 0, nullptr));
- png.resize(len);
- ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, png.ptrw(), &len, 0, data.ptr(), 0, nullptr));
+ png.resize(len);
+ ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, png.ptrw(), &len, 0, data.ptr(), 0, nullptr));
- godot_js_display_window_icon_set(png.ptr(), len);
+ godot_js_display_window_icon_set(png.ptr(), len);
+ } else {
+ godot_js_display_window_icon_set(nullptr, 0);
+ }
}
void DisplayServerWeb::_dispatch_input_event(const Ref<InputEvent> &p_event) {
diff --git a/platform/web/doc_classes/EditorExportPlatformWeb.xml b/platform/web/doc_classes/EditorExportPlatformWeb.xml
index 6e5a2ac078..607fdd0533 100644
--- a/platform/web/doc_classes/EditorExportPlatformWeb.xml
+++ b/platform/web/doc_classes/EditorExportPlatformWeb.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlatformWeb" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorExportPlatformWeb" inherits="EditorExportPlatform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for the Web.
</brief_description>
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index 38d7ed7fb6..38e2714d9f 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -37,6 +37,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/export/editor_export.h"
+#include "scene/resources/image_texture.h"
#include "modules/modules_enabled.gen.h" // For mono and svg.
#ifdef MODULE_SVG_ENABLED
@@ -359,17 +360,16 @@ Ref<Texture2D> EditorExportPlatformWeb::get_logo() const {
}
bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
- String err;
- bool valid = false;
- bool extensions = (bool)p_preset->get("variant/extensions_support");
-
#ifdef MODULE_MONO_ENABLED
- err += TTR("Exporting to Web is currently not supported in Godot 4 when using C#/.NET. Use Godot 3 to target Web with C#/Mono instead.") + "\n";
- err += TTR("If this project does not use C#, use a non-C# editor build to export the project.") + "\n";
// Don't check for additional errors, as this particular error cannot be resolved.
- r_error = err;
+ r_error += TTR("Exporting to Web is currently not supported in Godot 4 when using C#/.NET. Use Godot 3 to target Web with C#/Mono instead.") + "\n";
+ r_error += TTR("If this project does not use C#, use a non-C# editor build to export the project.") + "\n";
return false;
-#endif
+#else
+
+ String err;
+ bool valid = false;
+ bool extensions = (bool)p_preset->get("variant/extensions_support");
// Look for export templates (first official, and if defined custom templates).
bool dvalid = exists_export_template(_get_template_name(extensions, true), &err);
@@ -396,6 +396,7 @@ bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExp
}
return valid;
+#endif // !MODULE_MONO_ENABLED
}
bool EditorExportPlatformWeb::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
@@ -674,11 +675,10 @@ EditorExportPlatformWeb::EditorExportPlatformWeb() {
Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
- ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false);
logo = ImageTexture::create_from_image(img);
- img_loader.create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img);
#endif
diff --git a/platform/web/export/run_icon.svg b/platform/web/export/run_icon.svg
index 494f53cb90..fa95e64e79 100644
--- a/platform/web/export/run_icon.svg
+++ b/platform/web/export/run_icon.svg
@@ -1 +1 @@
-<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M3.143 1 5.48 27.504 15.967 31l10.553-3.496L28.857 1ZM23.78 9.565H11.473l.275 3.308h11.759l-.911 9.937-6.556 1.808v.02h-.073l-6.61-1.828-.402-5.076h3.195l.234 2.552 3.583.97 3.595-.97.402-4.165H8.788L7.93 6.37h16.145Z" fill="#eb6428" style="fill:#e0e0e0;fill-opacity:1" transform="translate(.586 .586) scale(.46337)"/></svg>
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m2 1 1.09 12.357 4.9 1.63 4.9-1.63L13.98 1zm9.622 3.994h-5.74l.129 1.541h5.482l-.424 4.634-3.057.843v.01h-.033l-3.082-.853-.187-2.367h1.489l.11 1.19 1.67.452 1.676-.453.187-1.942h-5.21l-.4-4.546h7.527z" fill="#eb6428" style="fill:#e0e0e0;fill-opacity:1"/></svg>
diff --git a/platform/web/http_client_web.cpp b/platform/web/http_client_web.cpp
index 3e4ba5a2ae..ea9226a5a4 100644
--- a/platform/web/http_client_web.cpp
+++ b/platform/web/http_client_web.cpp
@@ -149,7 +149,15 @@ Error HTTPClientWeb::get_response_headers(List<String> *r_response) {
}
int64_t HTTPClientWeb::get_response_body_length() const {
- return godot_js_fetch_body_length_get(js_id);
+ // Body length cannot be consistently retrieved from the web.
+ // Reading the "content-length" value will return a meaningless value when the response is compressed,
+ // as reading will return uncompressed chunks in any case, resulting in a mismatch between the detected
+ // body size and the actual size returned by repeatedly calling read_response_body_chunk.
+ // Additionally, while "content-length" is considered a safe CORS header, "content-encoding" is not,
+ // so using the "content-encoding" to decide if "content-length" is meaningful is not an option either.
+ // We simply must accept the fact that browsers are awful when it comes to networking APIs.
+ // See GH-47597, and GH-79327.
+ return -1;
}
PackedByteArray HTTPClientWeb::read_response_body_chunk() {
diff --git a/platform/web/http_client_web.h b/platform/web/http_client_web.h
index bb9672ab82..4d3c457a7d 100644
--- a/platform/web/http_client_web.h
+++ b/platform/web/http_client_web.h
@@ -51,7 +51,6 @@ extern int godot_js_fetch_read_headers(int p_id, void (*parse_callback)(int p_si
extern int godot_js_fetch_read_chunk(int p_id, uint8_t *p_buf, int p_buf_size);
extern void godot_js_fetch_free(int p_id);
extern godot_js_fetch_state_t godot_js_fetch_state_get(int p_id);
-extern int godot_js_fetch_body_length_get(int p_id);
extern int godot_js_fetch_http_status_get(int p_id);
extern int godot_js_fetch_is_chunked(int p_id);
diff --git a/platform/web/js/libs/library_godot_display.js b/platform/web/js/libs/library_godot_display.js
index 23cbc67c16..746f858923 100644
--- a/platform/web/js/libs/library_godot_display.js
+++ b/platform/web/js/libs/library_godot_display.js
@@ -536,7 +536,7 @@ const GodotDisplay = {
}
navigator.clipboard.writeText(text).catch(function (e) {
// Setting OS clipboard is only possible from an input callback.
- GodotRuntime.error('Setting OS clipboard is only possible from an input callback for the Web plafrom. Exception:', e);
+ GodotRuntime.error('Setting OS clipboard is only possible from an input callback for the Web platform. Exception:', e);
});
return 0;
},
@@ -568,16 +568,23 @@ const GodotDisplay = {
godot_js_display_window_icon_set__sig: 'vii',
godot_js_display_window_icon_set: function (p_ptr, p_len) {
let link = document.getElementById('-gd-engine-icon');
- if (link === null) {
- link = document.createElement('link');
- link.rel = 'icon';
- link.id = '-gd-engine-icon';
- document.head.appendChild(link);
- }
const old_icon = GodotDisplay.window_icon;
- const png = new Blob([GodotRuntime.heapSlice(HEAPU8, p_ptr, p_len)], { type: 'image/png' });
- GodotDisplay.window_icon = URL.createObjectURL(png);
- link.href = GodotDisplay.window_icon;
+ if (p_ptr) {
+ if (link === null) {
+ link = document.createElement('link');
+ link.rel = 'icon';
+ link.id = '-gd-engine-icon';
+ document.head.appendChild(link);
+ }
+ const png = new Blob([GodotRuntime.heapSlice(HEAPU8, p_ptr, p_len)], { type: 'image/png' });
+ GodotDisplay.window_icon = URL.createObjectURL(png);
+ link.href = GodotDisplay.window_icon;
+ } else {
+ if (link) {
+ link.remove();
+ }
+ GodotDisplay.window_icon = null;
+ }
if (old_icon) {
URL.revokeObjectURL(old_icon);
}
diff --git a/platform/web/js/libs/library_godot_fetch.js b/platform/web/js/libs/library_godot_fetch.js
index 1bb48bfd6a..4ef24903e3 100644
--- a/platform/web/js/libs/library_godot_fetch.js
+++ b/platform/web/js/libs/library_godot_fetch.js
@@ -50,22 +50,17 @@ const GodotFetch = {
return;
}
let chunked = false;
- let bodySize = -1;
response.headers.forEach(function (value, header) {
const v = value.toLowerCase().trim();
const h = header.toLowerCase().trim();
if (h === 'transfer-encoding' && v === 'chunked') {
chunked = true;
}
- if (h === 'content-length') {
- bodySize = parseInt(v, 10);
- }
});
obj.status = response.status;
obj.response = response;
obj.reader = response.body.getReader();
obj.chunked = chunked;
- obj.bodySize = bodySize;
},
onerror: function (id, err) {
@@ -87,7 +82,6 @@ const GodotFetch = {
reading: false,
status: 0,
chunks: [],
- bodySize: -1,
};
const id = IDHandler.add(obj);
const init = {
@@ -224,15 +218,6 @@ const GodotFetch = {
return p_buf_size - to_read;
},
- godot_js_fetch_body_length_get__sig: 'ii',
- godot_js_fetch_body_length_get: function (p_id) {
- const obj = IDHandler.get(p_id);
- if (!obj || !obj.response) {
- return -1;
- }
- return obj.bodySize;
- },
-
godot_js_fetch_is_chunked__sig: 'ii',
godot_js_fetch_is_chunked: function (p_id) {
const obj = IDHandler.get(p_id);
diff --git a/platform/web/os_web.cpp b/platform/web/os_web.cpp
index 5115ff50da..9ee8f90e89 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, "Can't open dynamic library: " + p_path + ". Error: " + dlerror());
+ ERR_FAIL_COND_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/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 91f7de7f26..c073d6f028 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -32,9 +32,11 @@
#include "os_windows.h"
+#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
+#include "drivers/png/png_driver_common.h"
#include "main/main.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/atlas_texture.h"
#if defined(GLES3_ENABLED)
#include "drivers/gles3/rasterizer_gles3.h"
@@ -42,6 +44,8 @@
#include <avrt.h>
#include <dwmapi.h>
+#include <shlwapi.h>
+#include <shobjidl.h>
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
@@ -87,6 +91,7 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const {
case FEATURE_HIDPI:
case FEATURE_ICON:
case FEATURE_NATIVE_ICON:
+ case FEATURE_NATIVE_DIALOG:
case FEATURE_SWAP_BUFFERS:
case FEATURE_KEEP_SCREEN_ON:
case FEATURE_TEXT_TO_SPEECH:
@@ -213,6 +218,129 @@ void DisplayServerWindows::tts_stop() {
tts->stop();
}
+Error DisplayServerWindows::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+ _THREAD_SAFE_METHOD_
+
+ Vector<Char16String> filter_names;
+ Vector<Char16String> filter_exts;
+ for (const String &E : p_filters) {
+ Vector<String> tokens = E.split(";");
+ if (tokens.size() == 2) {
+ filter_exts.push_back(tokens[0].strip_edges().utf16());
+ filter_names.push_back(tokens[1].strip_edges().utf16());
+ } else if (tokens.size() == 1) {
+ filter_exts.push_back(tokens[0].strip_edges().utf16());
+ filter_names.push_back(tokens[0].strip_edges().utf16());
+ }
+ }
+
+ Vector<COMDLG_FILTERSPEC> filters;
+ for (int i = 0; i < filter_names.size(); i++) {
+ filters.push_back({ (LPCWSTR)filter_names[i].ptr(), (LPCWSTR)filter_exts[i].ptr() });
+ }
+
+ HRESULT hr = S_OK;
+ IFileDialog *pfd = nullptr;
+ if (p_mode == FILE_DIALOG_MODE_SAVE_FILE) {
+ hr = CoCreateInstance(CLSID_FileSaveDialog, nullptr, CLSCTX_INPROC_SERVER, IID_IFileSaveDialog, (void **)&pfd);
+ } else {
+ hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, (void **)&pfd);
+ }
+ if (SUCCEEDED(hr)) {
+ DWORD flags;
+ pfd->GetOptions(&flags);
+ if (p_mode == FILE_DIALOG_MODE_OPEN_FILES) {
+ flags |= FOS_ALLOWMULTISELECT;
+ }
+ if (p_mode == FILE_DIALOG_MODE_OPEN_DIR) {
+ flags |= FOS_PICKFOLDERS;
+ }
+ if (p_show_hidden) {
+ flags |= FOS_FORCESHOWHIDDEN;
+ }
+ pfd->SetOptions(flags | FOS_FORCEFILESYSTEM);
+ pfd->SetTitle((LPCWSTR)p_title.utf16().ptr());
+
+ String dir = ProjectSettings::get_singleton()->globalize_path(p_current_directory);
+ if (dir == ".") {
+ dir = OS::get_singleton()->get_executable_path().get_base_dir();
+ }
+ dir = dir.replace("/", "\\");
+
+ IShellItem *shellitem = nullptr;
+ hr = SHCreateItemFromParsingName((LPCWSTR)dir.utf16().ptr(), nullptr, IID_IShellItem, (void **)&shellitem);
+ if (SUCCEEDED(hr)) {
+ pfd->SetDefaultFolder(shellitem);
+ pfd->SetFolder(shellitem);
+ }
+
+ pfd->SetFileName((LPCWSTR)p_filename.utf16().ptr());
+ pfd->SetFileTypes(filters.size(), filters.ptr());
+ pfd->SetFileTypeIndex(0);
+
+ hr = pfd->Show(nullptr);
+ if (SUCCEEDED(hr)) {
+ Vector<String> file_names;
+
+ if (p_mode == FILE_DIALOG_MODE_OPEN_FILES) {
+ IShellItemArray *results;
+ hr = static_cast<IFileOpenDialog *>(pfd)->GetResults(&results);
+ if (SUCCEEDED(hr)) {
+ DWORD count = 0;
+ results->GetCount(&count);
+ for (DWORD i = 0; i < count; i++) {
+ IShellItem *result;
+ results->GetItemAt(i, &result);
+
+ PWSTR file_path = nullptr;
+ hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
+ if (SUCCEEDED(hr)) {
+ file_names.push_back(String::utf16((const char16_t *)file_path));
+ CoTaskMemFree(file_path);
+ }
+ result->Release();
+ }
+ results->Release();
+ }
+ } else {
+ IShellItem *result;
+ hr = pfd->GetResult(&result);
+ if (SUCCEEDED(hr)) {
+ PWSTR file_path = nullptr;
+ hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
+ if (SUCCEEDED(hr)) {
+ file_names.push_back(String::utf16((const char16_t *)file_path));
+ CoTaskMemFree(file_path);
+ }
+ result->Release();
+ }
+ }
+ if (!p_callback.is_null()) {
+ Variant v_status = true;
+ Variant v_files = file_names;
+ Variant *v_args[2] = { &v_status, &v_files };
+ Variant ret;
+ Callable::CallError ce;
+ p_callback.callp((const Variant **)&v_args, 2, ret, ce);
+ }
+ } else {
+ if (!p_callback.is_null()) {
+ Variant v_status = false;
+ Variant v_files = Vector<String>();
+ Variant *v_args[2] = { &v_status, &v_files };
+ Variant ret;
+ Callable::CallError ce;
+ p_callback.callp((const Variant **)&v_args, 2, ret, ce);
+ }
+ }
+ pfd->Release();
+
+ return OK;
+ } else {
+ return ERR_CANT_OPEN;
+ }
+}
+
void DisplayServerWindows::mouse_set_mode(MouseMode p_mode) {
_THREAD_SAFE_METHOD_
@@ -341,6 +469,68 @@ String DisplayServerWindows::clipboard_get() const {
return ret;
}
+Ref<Image> DisplayServerWindows::clipboard_get_image() const {
+ Ref<Image> image;
+ if (!windows.has(last_focused_window)) {
+ return image; // No focused window?
+ }
+ if (!OpenClipboard(windows[last_focused_window].hWnd)) {
+ ERR_FAIL_V_MSG(image, "Unable to open clipboard.");
+ }
+ UINT png_format = RegisterClipboardFormatA("PNG");
+ if (png_format && IsClipboardFormatAvailable(png_format)) {
+ HANDLE png_handle = GetClipboardData(png_format);
+ if (png_handle) {
+ size_t png_size = GlobalSize(png_handle);
+ uint8_t *png_data = (uint8_t *)GlobalLock(png_handle);
+ image.instantiate();
+
+ PNGDriverCommon::png_to_image(png_data, png_size, false, image);
+
+ GlobalUnlock(png_handle);
+ }
+ } else if (IsClipboardFormatAvailable(CF_DIB)) {
+ HGLOBAL mem = GetClipboardData(CF_DIB);
+ if (mem != NULL) {
+ BITMAPINFO *ptr = static_cast<BITMAPINFO *>(GlobalLock(mem));
+
+ if (ptr != NULL) {
+ BITMAPINFOHEADER *info = &ptr->bmiHeader;
+ PackedByteArray pba;
+
+ for (LONG y = info->biHeight - 1; y > -1; y--) {
+ for (LONG x = 0; x < info->biWidth; x++) {
+ tagRGBQUAD *rgbquad = ptr->bmiColors + (info->biWidth * y) + x;
+ pba.append(rgbquad->rgbRed);
+ pba.append(rgbquad->rgbGreen);
+ pba.append(rgbquad->rgbBlue);
+ pba.append(rgbquad->rgbReserved);
+ }
+ }
+ image.instantiate();
+ image->create_from_data(info->biWidth, info->biHeight, false, Image::Format::FORMAT_RGBA8, pba);
+
+ GlobalUnlock(mem);
+ }
+ }
+ }
+
+ CloseClipboard();
+
+ return image;
+}
+
+bool DisplayServerWindows::clipboard_has() const {
+ return (IsClipboardFormatAvailable(CF_TEXT) ||
+ IsClipboardFormatAvailable(CF_UNICODETEXT) ||
+ IsClipboardFormatAvailable(CF_OEMTEXT));
+}
+
+bool DisplayServerWindows::clipboard_has_image() const {
+ UINT png_format = RegisterClipboardFormatA("PNG");
+ return ((png_format && IsClipboardFormatAvailable(png_format)) || IsClipboardFormatAvailable(CF_DIB));
+}
+
typedef struct {
int count;
int screen;
@@ -618,7 +808,7 @@ Color DisplayServerWindows::screen_get_pixel(const Point2i &p_position) const {
COLORREF col = GetPixel(dc, p.x, p.y);
if (col != CLR_INVALID) {
ReleaseDC(NULL, dc);
- return Color(float(col & 0x000000FF) / 256.0, float((col & 0x0000FF00) >> 8) / 256.0, float((col & 0x00FF0000) >> 16) / 256.0, 1.0);
+ return Color(float(col & 0x000000FF) / 255.0f, float((col & 0x0000FF00) >> 8) / 255.0f, float((col & 0x00FF0000) >> 16) / 255.0f, 1.0f);
}
ReleaseDC(NULL, dc);
}
@@ -1598,7 +1788,7 @@ void DisplayServerWindows::window_request_attention(WindowID p_window) {
FLASHWINFO info;
info.cbSize = sizeof(FLASHWINFO);
info.hwnd = wd.hWnd;
- info.dwFlags = FLASHW_TRAY;
+ info.dwFlags = FLASHW_ALL;
info.dwTimeout = 0;
info.uCount = 2;
FlashWindowEx(&info);
@@ -2010,6 +2200,38 @@ Key DisplayServerWindows::keyboard_get_keycode_from_physical(Key p_keycode) cons
return (Key)(KeyMappingWindows::get_keysym(vk) | modifiers);
}
+Key DisplayServerWindows::keyboard_get_label_from_physical(Key p_keycode) const {
+ Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
+ Key keycode_no_mod = (Key)(p_keycode & KeyModifierMask::CODE_MASK);
+
+ if (keycode_no_mod == Key::PRINT ||
+ keycode_no_mod == Key::KP_ADD ||
+ keycode_no_mod == Key::KP_5 ||
+ (keycode_no_mod >= Key::KEY_0 && keycode_no_mod <= Key::KEY_9)) {
+ return p_keycode;
+ }
+
+ unsigned int scancode = KeyMappingWindows::get_scancode(keycode_no_mod);
+ if (scancode == 0) {
+ return p_keycode;
+ }
+
+ Key keycode = KeyMappingWindows::get_keysym(MapVirtualKey(scancode, MAPVK_VSC_TO_VK));
+
+ HKL current_layout = GetKeyboardLayout(0);
+ static BYTE keyboard_state[256];
+ memset(keyboard_state, 0, 256);
+ wchar_t chars[256] = {};
+ UINT extended_code = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX);
+ if (ToUnicodeEx(extended_code, scancode, keyboard_state, chars, 255, 4, current_layout) > 0) {
+ String keysym = String::utf16((char16_t *)chars, 255);
+ if (!keysym.is_empty()) {
+ return fix_key_label(keysym[0], keycode) | modifiers;
+ }
+ }
+ return p_keycode;
+}
+
String _get_full_layout_name_from_registry(HKL p_layout) {
String id = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\" + String::num_int64((int64_t)p_layout, 16, false).lpad(8, "0");
String ret;
@@ -2194,55 +2416,65 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND(!p_icon.is_valid());
- if (icon != p_icon) {
- icon = p_icon->duplicate();
- if (icon->get_format() != Image::FORMAT_RGBA8) {
- icon->convert(Image::FORMAT_RGBA8);
+ if (p_icon.is_valid()) {
+ ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0);
+
+ Ref<Image> img = p_icon;
+ if (img != icon) {
+ img = img->duplicate();
+ img->convert(Image::FORMAT_RGBA8);
}
- }
- int w = icon->get_width();
- int h = icon->get_height();
-
- // Create temporary bitmap buffer.
- int icon_len = 40 + h * w * 4;
- Vector<BYTE> v;
- v.resize(icon_len);
- BYTE *icon_bmp = v.ptrw();
-
- encode_uint32(40, &icon_bmp[0]);
- encode_uint32(w, &icon_bmp[4]);
- encode_uint32(h * 2, &icon_bmp[8]);
- encode_uint16(1, &icon_bmp[12]);
- encode_uint16(32, &icon_bmp[14]);
- encode_uint32(BI_RGB, &icon_bmp[16]);
- encode_uint32(w * h * 4, &icon_bmp[20]);
- encode_uint32(0, &icon_bmp[24]);
- encode_uint32(0, &icon_bmp[28]);
- encode_uint32(0, &icon_bmp[32]);
- encode_uint32(0, &icon_bmp[36]);
-
- uint8_t *wr = &icon_bmp[40];
- const uint8_t *r = icon->get_data().ptr();
-
- for (int i = 0; i < h; i++) {
- for (int j = 0; j < w; j++) {
- const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
- uint8_t *wpx = &wr[(i * w + j) * 4];
- wpx[0] = rpx[2];
- wpx[1] = rpx[1];
- wpx[2] = rpx[0];
- wpx[3] = rpx[3];
+
+ int w = img->get_width();
+ int h = img->get_height();
+
+ // Create temporary bitmap buffer.
+ int icon_len = 40 + h * w * 4;
+ Vector<BYTE> v;
+ v.resize(icon_len);
+ BYTE *icon_bmp = v.ptrw();
+
+ encode_uint32(40, &icon_bmp[0]);
+ encode_uint32(w, &icon_bmp[4]);
+ encode_uint32(h * 2, &icon_bmp[8]);
+ encode_uint16(1, &icon_bmp[12]);
+ encode_uint16(32, &icon_bmp[14]);
+ encode_uint32(BI_RGB, &icon_bmp[16]);
+ encode_uint32(w * h * 4, &icon_bmp[20]);
+ encode_uint32(0, &icon_bmp[24]);
+ encode_uint32(0, &icon_bmp[28]);
+ encode_uint32(0, &icon_bmp[32]);
+ encode_uint32(0, &icon_bmp[36]);
+
+ uint8_t *wr = &icon_bmp[40];
+ const uint8_t *r = img->get_data().ptr();
+
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
+ uint8_t *wpx = &wr[(i * w + j) * 4];
+ wpx[0] = rpx[2];
+ wpx[1] = rpx[1];
+ wpx[2] = rpx[0];
+ wpx[3] = rpx[3];
+ }
}
- }
- HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
+ HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
+ ERR_FAIL_COND(!hicon);
+
+ icon = img;
- // Set the icon for the window.
- SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
+ // Set the icon for the window.
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
- // Set the icon in the task manager (should we do this?).
- SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
+ // Set the icon in the task manager (should we do this?).
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
+ } else {
+ icon = Ref<Image>();
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, 0);
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, 0);
+ }
}
void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
@@ -3926,7 +4158,9 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
WindowRect.top += offset.y;
WindowRect.bottom += offset.y;
- AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
+ if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
+ AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
+ }
WindowID id = window_id_counter;
{
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 7228de7d31..59c4442604 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -511,6 +511,8 @@ public:
virtual bool is_dark_mode() const override;
virtual Color get_accent_color() const override;
+ virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
+
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
@@ -520,6 +522,9 @@ public:
virtual void clipboard_set(const String &p_text) override;
virtual String clipboard_get() const override;
+ virtual Ref<Image> clipboard_get_image() const override;
+ virtual bool clipboard_has() const override;
+ virtual bool clipboard_has_image() const override;
virtual int get_screen_count() const override;
virtual int get_primary_screen() const override;
@@ -623,6 +628,7 @@ public:
virtual String keyboard_get_layout_language(int p_index) const override;
virtual String keyboard_get_layout_name(int p_index) const override;
virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override;
+ virtual Key keyboard_get_label_from_physical(Key p_keycode) const override;
virtual int tablet_get_driver_count() const override;
virtual String tablet_get_driver_name(int p_driver) const override;
diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
index 7506ac09f0..80928d7418 100644
--- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml
+++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlatformWindows" inherits="EditorExportPlatformPC" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorExportPlatformWindows" inherits="EditorExportPlatformPC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for Windows.
</brief_description>
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index b521a649be..0ef07c3275 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -1011,11 +1011,10 @@ EditorExportPlatformWindows::EditorExportPlatformWindows() {
Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
- ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false);
set_logo(ImageTexture::create_from_image(img));
- img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false);
+ ImageLoaderSVG::create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img);
#endif
diff --git a/platform/windows/export/run_icon.svg b/platform/windows/export/run_icon.svg
index 0897276ef7..6a18433ed2 100644
--- a/platform/windows/export/run_icon.svg
+++ b/platform/windows/export/run_icon.svg
@@ -1 +1 @@
-<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m1.095 2.997 5.66-.78v5.469h-5.66zm0 10.006 5.66.78v-5.4h-5.66zm6.282.863 7.528 1.04V8.381H7.377Zm0-11.732v5.552h7.528V1.095Z" fill="#00abed" style="stroke-width:.460341;fill:#e0e0e0;fill-opacity:1"/></svg>
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m1.095 2.997 5.66-.78v5.469h-5.66zm0 10.006 5.66.78v-5.4h-5.66zm6.282.863 7.528 1.04V8.381H7.377Zm0-11.732v5.552h7.528V1.095Z" fill="#00abed" style="fill:#e0e0e0;fill-opacity:1"/></svg>
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp
index 0334bdd973..d3972c7bbc 100644
--- a/platform/windows/gl_manager_windows.cpp
+++ b/platform/windows/gl_manager_windows.cpp
@@ -53,6 +53,7 @@
#if defined(__GNUC__)
// Workaround GCC warning from -Wcast-function-type.
#define wglGetProcAddress (void *)wglGetProcAddress
+#define GetProcAddress (void *)GetProcAddress
#endif
typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index cb70f93a62..df93631ef0 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -389,13 +389,13 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
}
missing += E;
}
- ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s, missing dependencies: (%s), error: \"%s\".", p_path, missing, format_error_message(err_code)));
+ ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Missing dependencies: %s. Error: %s.", p_path, missing, format_error_message(err_code)));
} else {
- ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s, error: \"%s\"." + p_path, format_error_message(err_code)));
+ ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, format_error_message(err_code)));
}
}
#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_COND_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) {
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 48445496aa..e7003ab98b 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -41,7 +41,7 @@ void Camera2D::_update_scroll() {
if (Engine::get_singleton()->is_editor_hint()) {
queue_redraw();
// Only set viewport transform when not bound to the main viewport.
- if (get_viewport() == get_tree()->get_edited_scene_root()->get_viewport()) {
+ if (get_tree()->get_edited_scene_root() && get_viewport() == get_tree()->get_edited_scene_root()->get_viewport()) {
return;
}
}
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 10fc7ef5b2..70ec57aa7a 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -142,7 +142,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) {
return;
}
if (shape.is_valid()) {
- shape->disconnect("changed", callable_mp(this, &CollisionShape2D::_shape_changed));
+ shape->disconnect_changed(callable_mp(this, &CollisionShape2D::_shape_changed));
}
shape = p_shape;
queue_redraw();
@@ -155,7 +155,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) {
}
if (shape.is_valid()) {
- shape->connect("changed", callable_mp(this, &CollisionShape2D::_shape_changed));
+ shape->connect_changed(callable_mp(this, &CollisionShape2D::_shape_changed));
}
update_configuration_warnings();
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 115104adff..1c193f991e 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -30,9 +30,12 @@
#include "cpu_particles_2d.h"
-#include "core/core_string_names.h"
#include "scene/2d/gpu_particles_2d.h"
+#include "scene/resources/atlas_texture.h"
+#include "scene/resources/curve_texture.h"
+#include "scene/resources/gradient_texture.h"
#include "scene/resources/particle_process_material.h"
+#include "scene/scene_string_names.h"
void CPUParticles2D::set_emitting(bool p_emitting) {
if (emitting == p_emitting) {
@@ -41,6 +44,7 @@ void CPUParticles2D::set_emitting(bool p_emitting) {
emitting = p_emitting;
if (emitting) {
+ active = true;
set_process_internal(true);
}
}
@@ -202,13 +206,13 @@ void CPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
}
if (texture.is_valid()) {
- texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CPUParticles2D::_texture_changed));
+ texture->disconnect_changed(callable_mp(this, &CPUParticles2D::_texture_changed));
}
texture = p_texture;
if (texture.is_valid()) {
- texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CPUParticles2D::_texture_changed));
+ texture->connect_changed(callable_mp(this, &CPUParticles2D::_texture_changed));
}
queue_redraw();
@@ -259,7 +263,6 @@ PackedStringArray CPUParticles2D::get_configuration_warnings() const {
void CPUParticles2D::restart() {
time = 0;
- inactive_time = 0;
frame_remainder = 0;
cycle = 0;
emitting = false;
@@ -561,21 +564,15 @@ void CPUParticles2D::_update_internal() {
}
double delta = get_process_delta_time();
- if (emitting) {
- inactive_time = 0;
- } else {
- inactive_time += delta;
- if (inactive_time > lifetime * 1.2) {
- set_process_internal(false);
- _set_do_redraw(false);
+ if (!active && !emitting) {
+ set_process_internal(false);
+ _set_do_redraw(false);
- //reset variables
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- return;
- }
+ //reset variables
+ time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
}
_set_do_redraw(true);
@@ -650,6 +647,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
double system_phase = time / lifetime;
+ bool should_be_active = false;
for (int i = 0; i < pcount; i++) {
Particle &p = parray[i];
@@ -994,6 +992,12 @@ void CPUParticles2D::_particles_process(double p_delta) {
p.transform.columns[1] *= base_scale.y;
p.transform[2] += p.velocity * local_delta;
+
+ should_be_active = true;
+ }
+ if (!Math::is_equal_approx(time, 0.0) && active && !should_be_active) {
+ active = false;
+ emit_signal(SceneStringNames::get_singleton()->finished);
}
}
@@ -1364,6 +1368,8 @@ void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles);
+ ADD_SIGNAL(MethodInfo("finished"));
+
ADD_GROUP("Emission Shape", "emission_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Rectangle,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,suffix:px"), "set_emission_sphere_radius", "get_emission_sphere_radius");
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index d4ff999459..3f858c3277 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -78,6 +78,7 @@ public:
private:
bool emitting = false;
+ bool active = false;
struct Particle {
Transform2D transform;
@@ -99,7 +100,6 @@ private:
};
double time = 0.0;
- double inactive_time = 0.0;
double frame_remainder = 0.0;
int cycle = 0;
bool do_redraw = false;
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 078a73c583..8c5782dc41 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -30,21 +30,39 @@
#include "gpu_particles_2d.h"
-#include "core/core_string_names.h"
+#include "scene/resources/atlas_texture.h"
#include "scene/resources/particle_process_material.h"
+#include "scene/scene_string_names.h"
#ifdef TOOLS_ENABLED
#include "core/config/engine.h"
#endif
void GPUParticles2D::set_emitting(bool p_emitting) {
- RS::get_singleton()->particles_set_emitting(particles, p_emitting);
+ // Do not return even if `p_emitting == emitting` because `emitting` is just an approximation.
if (p_emitting && one_shot) {
+ if (!active && !emitting) {
+ // Last cycle ended.
+ active = true;
+ time = 0;
+ signal_cancled = false;
+ emission_time = lifetime;
+ active_time = lifetime * (2 - explosiveness_ratio);
+ } else {
+ signal_cancled = true;
+ }
set_process_internal(true);
} else if (!p_emitting) {
- set_process_internal(false);
+ if (one_shot) {
+ set_process_internal(true);
+ } else {
+ set_process_internal(false);
+ }
}
+
+ emitting = p_emitting;
+ RS::get_singleton()->particles_set_emitting(particles, p_emitting);
}
void GPUParticles2D::set_amount(int p_amount) {
@@ -149,7 +167,7 @@ void GPUParticles2D::set_trail_enabled(bool p_enabled) {
}
void GPUParticles2D::set_trail_lifetime(double p_seconds) {
- ERR_FAIL_COND(p_seconds < 0.001);
+ ERR_FAIL_COND(p_seconds < 0.01);
trail_lifetime = p_seconds;
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime);
queue_redraw();
@@ -211,7 +229,7 @@ void GPUParticles2D::set_speed_scale(double p_scale) {
}
bool GPUParticles2D::is_emitting() const {
- return RS::get_singleton()->particles_get_emitting(particles);
+ return emitting;
}
int GPUParticles2D::get_amount() const {
@@ -338,13 +356,13 @@ Rect2 GPUParticles2D::capture_rect() const {
void GPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
if (texture.is_valid()) {
- texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GPUParticles2D::_texture_changed));
+ texture->disconnect_changed(callable_mp(this, &GPUParticles2D::_texture_changed));
}
texture = p_texture;
if (texture.is_valid()) {
- texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GPUParticles2D::_texture_changed));
+ texture->connect_changed(callable_mp(this, &GPUParticles2D::_texture_changed));
}
_update_collision_size();
queue_redraw();
@@ -405,6 +423,16 @@ NodePath GPUParticles2D::get_sub_emitter() const {
void GPUParticles2D::restart() {
RS::get_singleton()->particles_restart(particles);
RS::get_singleton()->particles_set_emitting(particles, true);
+
+ emitting = true;
+ active = true;
+ signal_cancled = false;
+ time = 0;
+ emission_time = lifetime;
+ active_time = lifetime * (2 - explosiveness_ratio);
+ if (one_shot) {
+ set_process_internal(true);
+ }
}
void GPUParticles2D::_notification(int p_what) {
@@ -570,9 +598,23 @@ void GPUParticles2D::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
- if (one_shot && !is_emitting()) {
- notify_property_list_changed();
- set_process_internal(false);
+ if (one_shot) {
+ time += get_process_delta_time();
+ if (time > emission_time) {
+ emitting = false;
+ if (!active) {
+ set_process_internal(false);
+ }
+ }
+ if (time > active_time) {
+ if (active && !signal_cancled) {
+ emit_signal(SceneStringNames::get_singleton()->finished);
+ }
+ active = false;
+ if (!emitting) {
+ set_process_internal(false);
+ }
+ }
}
} break;
}
@@ -638,6 +680,8 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_trail_section_subdivisions", "subdivisions"), &GPUParticles2D::set_trail_section_subdivisions);
ClassDB::bind_method(D_METHOD("get_trail_section_subdivisions"), &GPUParticles2D::get_trail_section_subdivisions);
+ ADD_SIGNAL(MethodInfo("finished"));
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index e518ffec6f..3131698e5c 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -47,6 +47,9 @@ public:
private:
RID particles;
+ bool emitting = false;
+ bool active = false;
+ bool signal_cancled = false;
bool one_shot = false;
int amount = 0;
double lifetime = 0.0;
@@ -78,6 +81,10 @@ private:
int trail_sections = 8;
int trail_section_subdivisions = 4;
+ double time = 0.0;
+ double emission_time = 0.0;
+ double active_time = 0.0;
+
RID mesh;
void _attach_sub_emitter();
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 4c3161d049..61f5d5cd46 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -215,7 +215,7 @@ bool LightOccluder2D::_edit_is_selected_on_click(const Point2 &p_point, double p
void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon) {
#ifdef DEBUG_ENABLED
if (occluder_polygon.is_valid()) {
- occluder_polygon->disconnect("changed", callable_mp(this, &LightOccluder2D::_poly_changed));
+ occluder_polygon->disconnect_changed(callable_mp(this, &LightOccluder2D::_poly_changed));
}
#endif
occluder_polygon = p_polygon;
@@ -228,7 +228,7 @@ void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polyg
#ifdef DEBUG_ENABLED
if (occluder_polygon.is_valid()) {
- occluder_polygon->connect("changed", callable_mp(this, &LightOccluder2D::_poly_changed));
+ occluder_polygon->connect_changed(callable_mp(this, &LightOccluder2D::_poly_changed));
}
queue_redraw();
#endif
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 58dad40403..3a9473d76c 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -30,7 +30,6 @@
#include "line_2d.h"
-#include "core/core_string_names.h"
#include "core/math/geometry_2d.h"
#include "line_builder.h"
@@ -89,14 +88,14 @@ 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(CoreStringNames::get_singleton()->changed, callable_mp(this, &Line2D::_curve_changed));
+ _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(CoreStringNames::get_singleton()->changed, callable_mp(this, &Line2D::_curve_changed));
+ _curve->connect_changed(callable_mp(this, &Line2D::_curve_changed));
}
queue_redraw();
@@ -159,14 +158,14 @@ 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(CoreStringNames::get_singleton()->changed, callable_mp(this, &Line2D::_gradient_changed));
+ _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(CoreStringNames::get_singleton()->changed, callable_mp(this, &Line2D::_gradient_changed));
+ _gradient->connect_changed(callable_mp(this, &Line2D::_gradient_changed));
}
queue_redraw();
diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp
index f347eb6520..9631b2cc4e 100644
--- a/scene/2d/multimesh_instance_2d.cpp
+++ b/scene/2d/multimesh_instance_2d.cpp
@@ -30,7 +30,6 @@
#include "multimesh_instance_2d.h"
-#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
void MultiMeshInstance2D::_notification(int p_what) {
@@ -59,13 +58,13 @@ void MultiMeshInstance2D::_bind_methods() {
void MultiMeshInstance2D::set_multimesh(const Ref<MultiMesh> &p_multimesh) {
// Cleanup previous connection if any.
if (multimesh.is_valid()) {
- multimesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ multimesh->disconnect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
multimesh = p_multimesh;
// Connect to the multimesh so the AABB can update when instance transforms are changed.
if (multimesh.is_valid()) {
- multimesh->connect(CoreStringNames::get_singleton()->changed, callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ multimesh->connect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
queue_redraw();
}
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 73a801c822..6aeaf300d1 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -258,11 +258,13 @@ void NavigationAgent2D::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+ if (agent_parent && avoidance_enabled) {
+ NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
+ }
if (agent_parent && target_position_submitted) {
if (velocity_submitted) {
velocity_submitted = false;
if (avoidance_enabled) {
- NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
NavigationServer2D::get_singleton()->agent_set_velocity(agent, velocity);
}
}
@@ -755,6 +757,11 @@ void NavigationAgent2D::update_navigation() {
navigation_path_index -= 1;
navigation_finished = true;
target_position_submitted = false;
+ if (avoidance_enabled) {
+ NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
+ NavigationServer2D::get_singleton()->agent_set_velocity(agent, Vector2(0.0, 0.0));
+ NavigationServer2D::get_singleton()->agent_set_velocity_forced(agent, Vector2(0.0, 0.0));
+ }
emit_signal(SNAME("navigation_finished"));
break;
}
diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
index 3664040e7b..95798b6856 100644
--- a/scene/2d/navigation_link_2d.cpp
+++ b/scene/2d/navigation_link_2d.cpp
@@ -182,15 +182,7 @@ void NavigationLink2D::set_enabled(bool p_enabled) {
enabled = p_enabled;
- if (!is_inside_tree()) {
- return;
- }
-
- if (!enabled) {
- NavigationServer2D::get_singleton()->link_set_map(link, RID());
- } else {
- NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map());
- }
+ NavigationServer3D::get_singleton()->link_set_enabled(link, enabled);
#ifdef DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index 8e96f8265c..d993b8a400 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -79,7 +79,7 @@ void NavigationObstacle2D::_notification(int p_what) {
previous_transform = get_global_transform();
// need to trigger map controlled agent assignment somehow for the fake_agent since obstacles use no callback like regular agents
NavigationServer2D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
- _update_position(get_global_transform().get_origin());
+ _update_position(get_global_position());
set_physics_process_internal(true);
} break;
@@ -112,7 +112,7 @@ void NavigationObstacle2D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (is_inside_tree()) {
- _update_position(get_global_transform().get_origin());
+ _update_position(get_global_position());
if (velocity_submitted) {
velocity_submitted = false;
@@ -164,9 +164,9 @@ NavigationObstacle2D::~NavigationObstacle2D() {
void NavigationObstacle2D::set_vertices(const Vector<Vector2> &p_vertices) {
vertices = p_vertices;
NavigationServer2D::get_singleton()->obstacle_set_vertices(obstacle, vertices);
- if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) {
- queue_redraw();
- }
+#ifdef DEBUG_ENABLED
+ queue_redraw();
+#endif // DEBUG_ENABLED
}
void NavigationObstacle2D::set_navigation_map(RID p_navigation_map) {
@@ -195,9 +195,9 @@ void NavigationObstacle2D::set_radius(real_t p_radius) {
radius = p_radius;
NavigationServer2D::get_singleton()->obstacle_set_radius(obstacle, radius);
- if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) {
- queue_redraw();
- }
+#ifdef DEBUG_ENABLED
+ queue_redraw();
+#endif // DEBUG_ENABLED
}
void NavigationObstacle2D::set_avoidance_layers(uint32_t p_layers) {
@@ -237,6 +237,9 @@ void NavigationObstacle2D::set_avoidance_enabled(bool p_enabled) {
avoidance_enabled = p_enabled;
NavigationServer2D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
+#ifdef DEBUG_ENABLED
+ queue_redraw();
+#endif // DEBUG_ENABLED
}
bool NavigationObstacle2D::get_avoidance_enabled() const {
@@ -255,13 +258,16 @@ void NavigationObstacle2D::_update_map(RID p_map) {
void NavigationObstacle2D::_update_position(const Vector2 p_position) {
NavigationServer2D::get_singleton()->obstacle_set_position(obstacle, p_position);
+#ifdef DEBUG_ENABLED
+ queue_redraw();
+#endif // DEBUG_ENABLED
}
#ifdef DEBUG_ENABLED
void NavigationObstacle2D::_update_fake_agent_radius_debug() {
if (radius > 0.0 && NavigationServer2D::get_singleton()->get_debug_navigation_avoidance_enable_obstacles_radius()) {
Color debug_radius_color = NavigationServer2D::get_singleton()->get_debug_navigation_avoidance_obstacles_radius_color();
- draw_circle(get_global_transform().get_origin(), radius, debug_radius_color);
+ RS::get_singleton()->canvas_item_add_circle(get_canvas_item(), Vector2(), radius, debug_radius_color);
}
}
#endif // DEBUG_ENABLED
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 693e03e1d4..670a2c641c 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -30,7 +30,6 @@
#include "navigation_region_2d.h"
-#include "core/core_string_names.h"
#include "core/math/geometry_2d.h"
#include "scene/2d/navigation_obstacle_2d.h"
#include "scene/resources/world_2d.h"
@@ -43,15 +42,7 @@ void NavigationRegion2D::set_enabled(bool p_enabled) {
enabled = p_enabled;
- if (!is_inside_tree()) {
- return;
- }
-
- if (!enabled) {
- NavigationServer2D::get_singleton()->region_set_map(region, RID());
- } else {
- NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
- }
+ NavigationServer2D::get_singleton()->region_set_enabled(region, enabled);
#ifdef DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_navigation_enabled()) {
@@ -161,17 +152,7 @@ bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, doubl
void NavigationRegion2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- if (enabled) {
- NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
- for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
- if (constrain_avoidance_obstacles[i].is_valid()) {
- NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], get_world_2d()->get_navigation_map());
- NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position());
- }
- }
- }
- current_global_transform = get_global_transform();
- NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform);
+ _region_enter_navigation_map();
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -179,30 +160,11 @@ void NavigationRegion2D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
- NavigationServer2D::get_singleton()->region_set_map(region, RID());
- for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
- if (constrain_avoidance_obstacles[i].is_valid()) {
- NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], RID());
- }
- }
+ _region_exit_navigation_map();
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
set_physics_process_internal(false);
- if (is_inside_tree()) {
- Transform2D new_global_transform = get_global_transform();
- if (current_global_transform != new_global_transform) {
- current_global_transform = new_global_transform;
- NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform);
- queue_redraw();
-
- for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
- if (constrain_avoidance_obstacles[i].is_valid()) {
- NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position());
- }
- }
- }
- }
} break;
case NOTIFICATION_DRAW: {
@@ -222,14 +184,14 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_
}
if (navigation_polygon.is_valid()) {
- navigation_polygon->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed));
+ navigation_polygon->disconnect_changed(callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed));
}
navigation_polygon = p_navigation_polygon;
NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, p_navigation_polygon);
if (navigation_polygon.is_valid()) {
- navigation_polygon->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed));
+ navigation_polygon->connect_changed(callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed));
}
_navigation_polygon_changed();
@@ -240,6 +202,30 @@ Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
return navigation_polygon;
}
+void NavigationRegion2D::set_navigation_map(RID p_navigation_map) {
+ if (map_override == p_navigation_map) {
+ return;
+ }
+
+ map_override = p_navigation_map;
+
+ NavigationServer2D::get_singleton()->region_set_map(region, map_override);
+ for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
+ if (constrain_avoidance_obstacles[i].is_valid()) {
+ NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], map_override);
+ }
+ }
+}
+
+RID NavigationRegion2D::get_navigation_map() const {
+ if (map_override.is_valid()) {
+ return map_override;
+ } else if (is_inside_tree()) {
+ return get_world_2d()->get_navigation_map();
+ }
+ return RID();
+}
+
void NavigationRegion2D::_navigation_polygon_changed() {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) {
queue_redraw();
@@ -277,6 +263,9 @@ void NavigationRegion2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion2D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion2D::is_enabled);
+ ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationRegion2D::set_navigation_map);
+ ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationRegion2D::get_navigation_map);
+
ClassDB::bind_method(D_METHOD("set_use_edge_connections", "enabled"), &NavigationRegion2D::set_use_edge_connections);
ClassDB::bind_method(D_METHOD("get_use_edge_connections"), &NavigationRegion2D::get_use_edge_connections);
@@ -416,7 +405,11 @@ void NavigationRegion2D::_update_avoidance_constrain() {
NavigationServer2D::get_singleton()->obstacle_set_vertices(obstacle_rid, new_obstacle_outline);
NavigationServer2D::get_singleton()->obstacle_set_avoidance_layers(obstacle_rid, avoidance_layers);
if (is_inside_tree()) {
- NavigationServer2D::get_singleton()->obstacle_set_map(obstacle_rid, get_world_2d()->get_navigation_map());
+ if (map_override.is_valid()) {
+ NavigationServer2D::get_singleton()->obstacle_set_map(obstacle_rid, map_override);
+ } else {
+ NavigationServer2D::get_singleton()->obstacle_set_map(obstacle_rid, get_world_2d()->get_navigation_map());
+ }
NavigationServer2D::get_singleton()->obstacle_set_position(obstacle_rid, get_global_position());
}
}
@@ -472,6 +465,68 @@ bool NavigationRegion2D::get_avoidance_layer_value(int p_layer_number) const {
return get_avoidance_layers() & (1 << (p_layer_number - 1));
}
+void NavigationRegion2D::_region_enter_navigation_map() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (enabled) {
+ if (map_override.is_valid()) {
+ NavigationServer2D::get_singleton()->region_set_map(region, map_override);
+ for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
+ if (constrain_avoidance_obstacles[i].is_valid()) {
+ NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], map_override);
+ }
+ }
+ } else {
+ NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
+ for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
+ if (constrain_avoidance_obstacles[i].is_valid()) {
+ NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], get_world_2d()->get_navigation_map());
+ }
+ }
+ }
+ }
+
+ current_global_transform = get_global_transform();
+ NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform);
+ for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
+ if (constrain_avoidance_obstacles[i].is_valid()) {
+ NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position());
+ }
+ }
+
+ queue_redraw();
+}
+
+void NavigationRegion2D::_region_exit_navigation_map() {
+ NavigationServer2D::get_singleton()->region_set_map(region, RID());
+ for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
+ if (constrain_avoidance_obstacles[i].is_valid()) {
+ NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], RID());
+ }
+ }
+}
+
+void NavigationRegion2D::_region_update_transform() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ Transform2D new_global_transform = get_global_transform();
+ if (current_global_transform != new_global_transform) {
+ current_global_transform = new_global_transform;
+ NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform);
+ for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) {
+ if (constrain_avoidance_obstacles[i].is_valid()) {
+ NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position());
+ }
+ }
+ }
+
+ queue_redraw();
+}
+
#ifdef DEBUG_ENABLED
void NavigationRegion2D::_update_debug_mesh() {
Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices();
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 642f1663cd..0a48b10f47 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -40,6 +40,7 @@ class NavigationRegion2D : public Node2D {
bool use_edge_connections = true;
RID region;
+ RID map_override;
uint32_t navigation_layers = 1;
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
@@ -79,6 +80,9 @@ public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
+ void set_navigation_map(RID p_navigation_map);
+ RID get_navigation_map() const;
+
void set_use_edge_connections(bool p_enabled);
bool get_use_edge_connections() const;
@@ -115,6 +119,9 @@ public:
private:
void _update_avoidance_constrain();
+ void _region_enter_navigation_map();
+ void _region_exit_navigation_map();
+ void _region_update_transform();
};
#endif // NAVIGATION_REGION_2D_H
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 3e6a484e72..ee0ccc42ff 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -182,13 +182,13 @@ void Path2D::_curve_changed() {
void Path2D::set_curve(const Ref<Curve2D> &p_curve) {
if (curve.is_valid()) {
- curve->disconnect("changed", callable_mp(this, &Path2D::_curve_changed));
+ curve->disconnect_changed(callable_mp(this, &Path2D::_curve_changed));
}
curve = p_curve;
if (curve.is_valid()) {
- curve->connect("changed", callable_mp(this, &Path2D::_curve_changed));
+ curve->connect_changed(callable_mp(this, &Path2D::_curve_changed));
}
_curve_changed();
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index b3acc1849b..b9bde47507 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -30,7 +30,6 @@
#include "physics_body_2d.h"
-#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
void PhysicsBody2D::_bind_methods() {
@@ -195,15 +194,13 @@ real_t StaticBody2D::get_constant_angular_velocity() const {
void StaticBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody2D::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody2D::_reload_physics_characteristics));
- }
+ physics_material_override->disconnect_changed(callable_mp(this, &StaticBody2D::_reload_physics_characteristics));
}
physics_material_override = p_physics_material_override;
if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody2D::_reload_physics_characteristics));
+ physics_material_override->connect_changed(callable_mp(this, &StaticBody2D::_reload_physics_characteristics));
}
_reload_physics_characteristics();
}
@@ -651,15 +648,13 @@ const Vector2 &RigidBody2D::get_center_of_mass() const {
void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody2D::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody2D::_reload_physics_characteristics));
- }
+ physics_material_override->disconnect_changed(callable_mp(this, &RigidBody2D::_reload_physics_characteristics));
}
physics_material_override = p_physics_material_override;
if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody2D::_reload_physics_characteristics));
+ physics_material_override->connect_changed(callable_mp(this, &RigidBody2D::_reload_physics_characteristics));
}
_reload_physics_characteristics();
}
diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp
index f1a9119458..90d80d7549 100644
--- a/scene/2d/shape_cast_2d.cpp
+++ b/scene/2d/shape_cast_2d.cpp
@@ -31,7 +31,6 @@
#include "shape_cast_2d.h"
#include "core/config/engine.h"
-#include "core/core_string_names.h"
#include "scene/2d/collision_object_2d.h"
#include "scene/2d/physics_body_2d.h"
#include "scene/resources/circle_shape_2d.h"
@@ -155,11 +154,11 @@ void ShapeCast2D::set_shape(const Ref<Shape2D> &p_shape) {
return;
}
if (shape.is_valid()) {
- shape->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &ShapeCast2D::_shape_changed));
+ shape->disconnect_changed(callable_mp(this, &ShapeCast2D::_shape_changed));
}
shape = p_shape;
if (shape.is_valid()) {
- shape->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &ShapeCast2D::_shape_changed));
+ shape->connect_changed(callable_mp(this, &ShapeCast2D::_shape_changed));
shape_rid = shape->get_rid();
}
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index c31b42beba..350fdad7d7 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -309,8 +309,8 @@ void Bone2D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p_outline_shape, Bone2D *p_other_bone) {
- int bone_width = EDITOR_GET("editors/2d/bone_width");
- int bone_outline_width = EDITOR_GET("editors/2d/bone_outline_size");
+ float bone_width = EDITOR_GET("editors/2d/bone_width");
+ float bone_outline_width = EDITOR_GET("editors/2d/bone_outline_size");
if (!is_inside_tree()) {
return false; //may have been removed
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index 6e314160fd..7e6b43559c 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -30,7 +30,6 @@
#include "sprite_2d.h"
-#include "core/core_string_names.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
@@ -137,13 +136,13 @@ void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) {
}
if (texture.is_valid()) {
- texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite2D::_texture_changed));
+ texture->disconnect_changed(callable_mp(this, &Sprite2D::_texture_changed));
}
texture = p_texture;
if (texture.is_valid()) {
- texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite2D::_texture_changed));
+ texture->connect_changed(callable_mp(this, &Sprite2D::_texture_changed));
}
queue_redraw();
diff --git a/scene/2d/tile_map.compat.inc b/scene/2d/tile_map.compat.inc
new file mode 100644
index 0000000000..49e2bf6f0b
--- /dev/null
+++ b/scene/2d/tile_map.compat.inc
@@ -0,0 +1,45 @@
+/**************************************************************************/
+/* object.compat.inc */
+/**************************************************************************/
+/* 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 DISABLE_DEPRECATED
+
+#include "core/object/object.h"
+
+#include "core/object/class_db.h"
+
+Rect2i TileMap::_get_used_rect_bind_compat_78328() {
+ return get_used_rect();
+}
+
+void TileMap::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("get_used_rect"), &TileMap::_get_used_rect_bind_compat_78328);
+}
+
+#endif
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 5ea751f089..81d82b13bb 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -29,7 +29,9 @@
/**************************************************************************/
#include "tile_map.h"
+#include "tile_map.compat.inc"
+#include "core/core_string_names.h"
#include "core/io/marshalls.h"
#include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h"
@@ -38,793 +40,17 @@
#include "servers/navigation_server_3d.h"
#endif // DEBUG_ENABLED
-HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping_coords_and_peering_bits() const {
- HashMap<Vector2i, TileSet::CellNeighbor> output;
-
- ERR_FAIL_COND_V(is_center_bit(), output);
-
- Ref<TileSet> ts = tile_map->get_tileset();
- ERR_FAIL_COND_V(!ts.is_valid(), output);
-
- TileSet::TileShape shape = ts->get_tile_shape();
- if (shape == TileSet::TILE_SHAPE_SQUARE) {
- switch (bit) {
- case 1:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
- break;
- case 2:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
- break;
- case 3:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
- break;
- default:
- ERR_FAIL_V(output);
- }
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- switch (bit) {
- case 1:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
- break;
- case 2:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
- break;
- case 3:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
- break;
- default:
- ERR_FAIL_V(output);
- }
- } else {
- // Half offset shapes.
- TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis();
- if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- switch (bit) {
- case 1:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
- break;
- case 2:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
- break;
- case 3:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
- break;
- case 4:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
- break;
- case 5:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
- break;
- default:
- ERR_FAIL_V(output);
- }
- } else {
- switch (bit) {
- case 1:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
- break;
- case 2:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
- break;
- case 3:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
- break;
- case 4:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
- break;
- case 5:
- output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
- output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
- break;
- default:
- ERR_FAIL_V(output);
- }
- }
- }
- return output;
-}
-
-TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain) {
- tile_map = p_tile_map;
-
- Ref<TileSet> ts = tile_map->get_tileset();
- ERR_FAIL_COND(!ts.is_valid());
-
- bit = 0;
- base_cell_coords = p_position;
- terrain = p_terrain;
-}
-
-TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) {
- // The way we build the constraint make it easy to detect conflicting constraints.
- tile_map = p_tile_map;
-
- Ref<TileSet> ts = tile_map->get_tileset();
- ERR_FAIL_COND(!ts.is_valid());
-
- TileSet::TileShape shape = ts->get_tile_shape();
- if (shape == TileSet::TILE_SHAPE_SQUARE) {
- switch (p_bit) {
- case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
- bit = 1;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
- bit = 2;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
- bit = 3;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
- bit = 2;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
- bit = 1;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
- bit = 2;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_SIDE:
- bit = 3;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
- bit = 2;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
- break;
- default:
- ERR_FAIL();
- break;
- }
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- switch (p_bit) {
- case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
- bit = 2;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
- bit = 1;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
- bit = 2;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
- bit = 3;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
- bit = 2;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
- bit = 1;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_CORNER:
- bit = 2;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_CORNER);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
- bit = 3;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
- break;
- default:
- ERR_FAIL();
- break;
- }
- } else {
- // Half-offset shapes
- TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis();
- if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- switch (p_bit) {
- case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
- bit = 1;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
- bit = 2;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
- bit = 3;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
- bit = 4;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
- bit = 5;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
- bit = 2;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
- bit = 1;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
- bit = 4;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
- bit = 3;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_CORNER:
- bit = 2;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
- bit = 5;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
- bit = 4;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
- break;
- default:
- ERR_FAIL();
- break;
- }
- } else {
- switch (p_bit) {
- case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
- bit = 1;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
- bit = 2;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
- bit = 3;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
- bit = 4;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
- bit = 1;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
- bit = 5;
- base_cell_coords = p_position;
- break;
- case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
- bit = 3;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
- bit = 2;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
- bit = 1;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_SIDE:
- bit = 4;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
- bit = 3;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
- break;
- case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
- bit = 5;
- base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
- break;
- default:
- ERR_FAIL();
- break;
- }
- }
- }
- terrain = p_terrain;
-}
-
-Vector2i TileMap::transform_coords_layout(const Vector2i &p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) {
- // Transform to stacked layout.
- Vector2i output = p_coords;
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- SWAP(output.x, output.y);
- }
- switch (p_from_layout) {
- case TileSet::TILE_LAYOUT_STACKED:
- break;
- case TileSet::TILE_LAYOUT_STACKED_OFFSET:
- if (output.y % 2) {
- output.x -= 1;
- }
- break;
- case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
- case TileSet::TILE_LAYOUT_STAIRS_DOWN:
- if ((p_from_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if (output.y < 0 && bool(output.y % 2)) {
- output = Vector2i(output.x + output.y / 2 - 1, output.y);
- } else {
- output = Vector2i(output.x + output.y / 2, output.y);
- }
- } else {
- if (output.x < 0 && bool(output.x % 2)) {
- output = Vector2i(output.x / 2 - 1, output.x + output.y * 2);
- } else {
- output = Vector2i(output.x / 2, output.x + output.y * 2);
- }
- }
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
- case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
- if ((p_from_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if ((output.x + output.y) < 0 && (output.x - output.y) % 2) {
- output = Vector2i((output.x + output.y) / 2 - 1, output.y - output.x);
- } else {
- output = Vector2i((output.x + output.y) / 2, -output.x + output.y);
- }
- } else {
- if ((output.x - output.y) < 0 && (output.x + output.y) % 2) {
- output = Vector2i((output.x - output.y) / 2 - 1, output.x + output.y);
- } else {
- output = Vector2i((output.x - output.y) / 2, output.x + output.y);
- }
- }
- break;
- }
-
- switch (p_to_layout) {
- case TileSet::TILE_LAYOUT_STACKED:
- break;
- case TileSet::TILE_LAYOUT_STACKED_OFFSET:
- if (output.y % 2) {
- output.x += 1;
- }
- break;
- case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
- case TileSet::TILE_LAYOUT_STAIRS_DOWN:
- if ((p_to_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if (output.y < 0 && (output.y % 2)) {
- output = Vector2i(output.x - output.y / 2 + 1, output.y);
- } else {
- output = Vector2i(output.x - output.y / 2, output.y);
- }
- } else {
- if (output.y % 2) {
- if (output.y < 0) {
- output = Vector2i(2 * output.x + 1, -output.x + output.y / 2 - 1);
- } else {
- output = Vector2i(2 * output.x + 1, -output.x + output.y / 2);
- }
- } else {
- output = Vector2i(2 * output.x, -output.x + output.y / 2);
- }
- }
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
- case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
- if ((p_to_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if (output.y % 2) {
- if (output.y > 0) {
- output = Vector2i(output.x - output.y / 2, output.x + output.y / 2 + 1);
- } else {
- output = Vector2i(output.x - output.y / 2 + 1, output.x + output.y / 2);
- }
- } else {
- output = Vector2i(output.x - output.y / 2, output.x + output.y / 2);
- }
- } else {
- if (output.y % 2) {
- if (output.y < 0) {
- output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2 - 1);
- } else {
- output = Vector2i(output.x + output.y / 2 + 1, -output.x + output.y / 2);
- }
- } else {
- output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2);
- }
- }
- break;
- }
-
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- SWAP(output.x, output.y);
- }
-
- return output;
-}
-
-int TileMap::get_effective_quadrant_size(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), 1);
-
- // When using YSort, the quadrant size is reduced to 1 to have one CanvasItem per quadrant
- if (is_y_sort_enabled() && layers[p_layer].y_sort_enabled) {
- return 1;
- } else {
- return quadrant_size;
- }
-}
-
-void TileMap::set_selected_layer(int p_layer_id) {
- ERR_FAIL_COND(p_layer_id < -1 || p_layer_id >= (int)layers.size());
- selected_layer = p_layer_id;
- emit_signal(SNAME("changed"));
-
- // Update the layers modulation.
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- _rendering_update_layer(layer);
- }
-}
-
-int TileMap::get_selected_layer() const {
- return selected_layer;
-}
-
-void TileMap::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- _clear_internals();
- _recreate_internals();
- } break;
-
- case NOTIFICATION_EXIT_TREE: {
- _clear_internals();
- } break;
- }
-
- // Transfers the notification to tileset plugins.
- if (tile_set.is_valid()) {
- _rendering_notification(p_what);
- _physics_notification(p_what);
- _navigation_notification(p_what);
- }
-}
-
-Ref<TileSet> TileMap::get_tileset() const {
- return tile_set;
-}
-
-void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
- if (p_tileset == tile_set) {
- return;
- }
-
- // Set the tileset, registering to its changes.
- if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
- }
-
- if (!p_tileset.is_valid()) {
- _clear_internals();
- }
-
- tile_set = p_tileset;
-
- if (tile_set.is_valid()) {
- tile_set->connect("changed", callable_mp(this, &TileMap::_tile_set_changed));
- _clear_internals();
- _recreate_internals();
- }
-
- emit_signal(SNAME("changed"));
-}
-
-void TileMap::set_quadrant_size(int p_size) {
- ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1.");
-
- quadrant_size = p_size;
- _clear_internals();
- _recreate_internals();
- emit_signal(SNAME("changed"));
-}
-
-int TileMap::get_quadrant_size() const {
- return quadrant_size;
-}
-
-int TileMap::get_layers_count() const {
- return layers.size();
-}
-
-void TileMap::add_layer(int p_to_pos) {
- if (p_to_pos < 0) {
- p_to_pos = layers.size() + p_to_pos + 1;
- }
-
- ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
-
- // Must clear before adding the layer.
- _clear_internals();
-
- layers.insert(p_to_pos, TileMapLayer());
- _recreate_internals();
- notify_property_list_changed();
-
- emit_signal(SNAME("changed"));
-
- update_configuration_warnings();
-}
-
-void TileMap::move_layer(int p_layer, int p_to_pos) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
- ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
+Vector2i TileMapLayer::_coords_to_quadrant_coords(const Vector2i &p_coords) const {
+ int quad_size = get_effective_quadrant_size();
- // Clear before shuffling layers.
- _clear_internals();
-
- TileMapLayer tl = layers[p_layer];
- layers.insert(p_to_pos, tl);
- layers.remove_at(p_to_pos < p_layer ? p_layer + 1 : p_layer);
- _recreate_internals();
- notify_property_list_changed();
-
- if (selected_layer == p_layer) {
- selected_layer = p_to_pos < p_layer ? p_to_pos - 1 : p_to_pos;
- }
-
- emit_signal(SNAME("changed"));
-
- update_configuration_warnings();
-}
-
-void TileMap::remove_layer(int p_layer) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- // Clear before removing the layer.
- _clear_internals();
-
- layers.remove_at(p_layer);
- _recreate_internals();
- notify_property_list_changed();
-
- if (selected_layer >= p_layer) {
- selected_layer -= 1;
- }
-
- emit_signal(SNAME("changed"));
-
- update_configuration_warnings();
-}
-
-void TileMap::set_layer_name(int p_layer, String p_name) {
- if (p_layer < 0) {
- p_layer = layers.size() + p_layer;
- }
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- if (layers[p_layer].name == p_name) {
- return;
- }
- layers[p_layer].name = p_name;
- emit_signal(SNAME("changed"));
-}
-
-String TileMap::get_layer_name(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), String());
- return layers[p_layer].name;
-}
-
-void TileMap::set_layer_enabled(int p_layer, bool p_enabled) {
- if (p_layer < 0) {
- p_layer = layers.size() + p_layer;
- }
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- if (layers[p_layer].enabled == p_enabled) {
- return;
- }
- layers[p_layer].enabled = p_enabled;
- _clear_layer_internals(p_layer);
- _recreate_layer_internals(p_layer);
- emit_signal(SNAME("changed"));
-
- update_configuration_warnings();
-}
-
-bool TileMap::is_layer_enabled(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), false);
- return layers[p_layer].enabled;
-}
-
-void TileMap::set_layer_modulate(int p_layer, Color p_modulate) {
- if (p_layer < 0) {
- p_layer = layers.size() + p_layer;
- }
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- if (layers[p_layer].modulate == p_modulate) {
- return;
- }
- layers[p_layer].modulate = p_modulate;
- _rendering_update_layer(p_layer);
- emit_signal(SNAME("changed"));
-}
-
-Color TileMap::get_layer_modulate(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), Color());
- return layers[p_layer].modulate;
-}
-
-void TileMap::set_layer_y_sort_enabled(int p_layer, bool p_y_sort_enabled) {
- if (p_layer < 0) {
- p_layer = layers.size() + p_layer;
- }
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- if (layers[p_layer].y_sort_enabled == p_y_sort_enabled) {
- return;
- }
- layers[p_layer].y_sort_enabled = p_y_sort_enabled;
- _clear_layer_internals(p_layer);
- _recreate_layer_internals(p_layer);
- emit_signal(SNAME("changed"));
-
- update_configuration_warnings();
-}
-
-bool TileMap::is_layer_y_sort_enabled(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), false);
- return layers[p_layer].y_sort_enabled;
-}
-
-void TileMap::set_layer_y_sort_origin(int p_layer, int p_y_sort_origin) {
- if (p_layer < 0) {
- p_layer = layers.size() + p_layer;
- }
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- if (layers[p_layer].y_sort_origin == p_y_sort_origin) {
- return;
- }
- layers[p_layer].y_sort_origin = p_y_sort_origin;
- _clear_layer_internals(p_layer);
- _recreate_layer_internals(p_layer);
- emit_signal(SNAME("changed"));
-}
-
-int TileMap::get_layer_y_sort_origin(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), false);
- return layers[p_layer].y_sort_origin;
-}
-
-void TileMap::set_layer_z_index(int p_layer, int p_z_index) {
- if (p_layer < 0) {
- p_layer = layers.size() + p_layer;
- }
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- if (layers[p_layer].z_index == p_z_index) {
- return;
- }
- layers[p_layer].z_index = p_z_index;
- _rendering_update_layer(p_layer);
- emit_signal(SNAME("changed"));
-
- update_configuration_warnings();
-}
-
-int TileMap::get_layer_z_index(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), false);
- return layers[p_layer].z_index;
-}
-
-void TileMap::set_collision_animatable(bool p_enabled) {
- if (collision_animatable == p_enabled) {
- return;
- }
- collision_animatable = p_enabled;
- _clear_internals();
- set_notify_local_transform(p_enabled);
- set_physics_process_internal(p_enabled);
- _recreate_internals();
- emit_signal(SNAME("changed"));
-}
-
-bool TileMap::is_collision_animatable() const {
- return collision_animatable;
-}
-
-void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_collision) {
- if (collision_visibility_mode == p_show_collision) {
- return;
- }
- collision_visibility_mode = p_show_collision;
- _clear_internals();
- _recreate_internals();
- emit_signal(SNAME("changed"));
-}
-
-TileMap::VisibilityMode TileMap::get_collision_visibility_mode() {
- return collision_visibility_mode;
-}
-
-void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navigation) {
- if (navigation_visibility_mode == p_show_navigation) {
- return;
- }
- navigation_visibility_mode = p_show_navigation;
- _clear_internals();
- _recreate_internals();
- emit_signal(SNAME("changed"));
-}
-
-TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() {
- return navigation_visibility_mode;
-}
-
-void TileMap::set_navigation_map(int p_layer, RID p_map) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
- ERR_FAIL_COND_MSG(!is_inside_tree(), "A TileMap navigation map can only be changed while inside the SceneTree.");
- layers[p_layer].navigation_map = p_map;
- layers[p_layer].uses_world_navigation_map = p_map == get_world_2d()->get_navigation_map();
-}
-
-RID TileMap::get_navigation_map(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), RID());
- if (layers[p_layer].navigation_map.is_valid()) {
- return layers[p_layer].navigation_map;
- }
- return RID();
-}
-
-void TileMap::set_y_sort_enabled(bool p_enable) {
- if (is_y_sort_enabled() == p_enable) {
- return;
- }
- Node2D::set_y_sort_enabled(p_enable);
- _clear_internals();
- _recreate_internals();
- emit_signal(SNAME("changed"));
- update_configuration_warnings();
-}
-
-Vector2i TileMap::_coords_to_quadrant_coords(int p_layer, const Vector2i &p_coords) const {
- int quad_size = get_effective_quadrant_size(p_layer);
-
- // Rounding down, instead of simply rounding towards zero (truncating)
+ // Rounding down, instead of simply rounding towards zero (truncating).
return Vector2i(
p_coords.x > 0 ? p_coords.x / quad_size : (p_coords.x - (quad_size - 1)) / quad_size,
p_coords.y > 0 ? p_coords.y / quad_size : (p_coords.y - (quad_size - 1)) / quad_size);
}
-HashMap<Vector2i, TileMapQuadrant>::Iterator TileMap::_create_quadrant(int p_layer, const Vector2i &p_qk) {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
-
+HashMap<Vector2i, TileMapQuadrant>::Iterator TileMapLayer::_create_quadrant(const Vector2i &p_qk) {
TileMapQuadrant q;
- q.layer = p_layer;
q.coords = p_qk;
rect_cache_dirty = true;
@@ -833,156 +59,32 @@ HashMap<Vector2i, TileMapQuadrant>::Iterator TileMap::_create_quadrant(int p_lay
RenderingServer *rs = RenderingServer::get_singleton();
q.debug_canvas_item = rs->canvas_item_create();
rs->canvas_item_set_z_index(q.debug_canvas_item, RS::CANVAS_ITEM_Z_MAX - 1);
- rs->canvas_item_set_parent(q.debug_canvas_item, get_canvas_item());
+ rs->canvas_item_set_parent(q.debug_canvas_item, tile_map_node->get_canvas_item());
- // Call the create_quadrant method on plugins
+ // Call the create_quadrant method on plugins.
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
if (tile_set.is_valid()) {
_rendering_create_quadrant(&q);
}
- return layers[p_layer].quadrant_map.insert(p_qk, q);
+ return quadrant_map.insert(p_qk, q);
}
-void TileMap::_make_quadrant_dirty(HashMap<Vector2i, TileMapQuadrant>::Iterator Q) {
+void TileMapLayer::_make_quadrant_dirty(HashMap<Vector2i, TileMapQuadrant>::Iterator Q) {
// Make the given quadrant dirty, then trigger an update later.
TileMapQuadrant &q = Q->value;
if (!q.dirty_list_element.in_list()) {
- layers[q.layer].dirty_quadrant_list.add(&q.dirty_list_element);
- }
- _queue_update_dirty_quadrants();
-}
-
-void TileMap::_make_all_quadrants_dirty() {
- // Make all quandrants dirty, then trigger an update later.
- for (TileMapLayer &layer : layers) {
- for (KeyValue<Vector2i, TileMapQuadrant> &E : layer.quadrant_map) {
- if (!E.value.dirty_list_element.in_list()) {
- layer.dirty_quadrant_list.add(&E.value.dirty_list_element);
- }
- }
- }
- _queue_update_dirty_quadrants();
-}
-
-void TileMap::_queue_update_dirty_quadrants() {
- if (pending_update || !is_inside_tree()) {
- return;
- }
- pending_update = true;
- call_deferred(SNAME("_update_dirty_quadrants"));
-}
-
-void TileMap::_update_dirty_quadrants() {
- if (!pending_update) {
- return;
- }
- if (!is_inside_tree() || !tile_set.is_valid()) {
- pending_update = false;
- return;
- }
-
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- SelfList<TileMapQuadrant>::List &dirty_quadrant_list = layers[layer].dirty_quadrant_list;
-
- // Update the coords cache.
- for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
- q->self()->map_to_local.clear();
- q->self()->local_to_map.clear();
- for (const Vector2i &E : q->self()->cells) {
- Vector2i pk = E;
- Vector2 pk_local_coords = map_to_local(pk);
- q->self()->map_to_local[pk] = pk_local_coords;
- q->self()->local_to_map[pk_local_coords] = pk;
- }
- }
-
- // Find TileData that need a runtime modification.
- _build_runtime_update_tile_data(dirty_quadrant_list);
-
- // Call the update_dirty_quadrant method on plugins.
- _rendering_update_dirty_quadrants(dirty_quadrant_list);
- _physics_update_dirty_quadrants(dirty_quadrant_list);
- _navigation_update_dirty_quadrants(dirty_quadrant_list);
- _scenes_update_dirty_quadrants(dirty_quadrant_list);
-
- // Redraw the debug canvas_items.
- RenderingServer *rs = RenderingServer::get_singleton();
- for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
- rs->canvas_item_clear(q->self()->debug_canvas_item);
- Transform2D xform;
- xform.set_origin(map_to_local(q->self()->coords * get_effective_quadrant_size(layer)));
- rs->canvas_item_set_transform(q->self()->debug_canvas_item, xform);
-
- _rendering_draw_quadrant_debug(q->self());
- _physics_draw_quadrant_debug(q->self());
- _navigation_draw_quadrant_debug(q->self());
- _scenes_draw_quadrant_debug(q->self());
- }
-
- // Clear the list
- while (dirty_quadrant_list.first()) {
- // Clear the runtime tile data.
- for (const KeyValue<Vector2i, TileData *> &kv : dirty_quadrant_list.first()->self()->runtime_tile_data_cache) {
- memdelete(kv.value);
- }
-
- dirty_quadrant_list.remove(dirty_quadrant_list.first());
- }
+ dirty_quadrant_list.add(&q.dirty_list_element);
}
-
- pending_update = false;
-
- _recompute_rect_cache();
+ tile_map_node->queue_update_dirty_quadrants();
}
-void TileMap::_recreate_layer_internals(int p_layer) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- // Make sure that _clear_internals() was called prior.
- ERR_FAIL_COND_MSG(layers[p_layer].quadrant_map.size() > 0, "TileMap layer " + itos(p_layer) + " had a non-empty quadrant map.");
-
- if (!layers[p_layer].enabled) {
- return;
- }
-
- // Update the layer internals.
- _rendering_update_layer(p_layer);
-
- // Update the layer internal navigation maps.
- _navigation_update_layer(p_layer);
-
- // Recreate the quadrants.
- const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
- Vector2i qk = _coords_to_quadrant_coords(p_layer, Vector2i(E.key.x, E.key.y));
-
- HashMap<Vector2i, TileMapQuadrant>::Iterator Q = layers[p_layer].quadrant_map.find(qk);
- if (!Q) {
- Q = _create_quadrant(p_layer, qk);
- layers[p_layer].dirty_quadrant_list.add(&Q->value.dirty_list_element);
- }
-
- Vector2i pk = E.key;
- Q->value.cells.insert(pk);
-
- _make_quadrant_dirty(Q);
- }
-
- _queue_update_dirty_quadrants();
-}
-
-void TileMap::_recreate_internals() {
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- _recreate_layer_internals(layer);
- }
-}
-
-void TileMap::_erase_quadrant(HashMap<Vector2i, TileMapQuadrant>::Iterator Q) {
+void TileMapLayer::_erase_quadrant(HashMap<Vector2i, TileMapQuadrant>::Iterator Q) {
// Remove a quadrant.
TileMapQuadrant *q = &(Q->value);
// Call the cleanup_quadrant method on plugins.
- if (tile_set.is_valid()) {
+ if (tile_map_node->get_tileset().is_valid()) {
_rendering_cleanup_quadrant(q);
_physics_cleanup_quadrant(q);
_navigation_cleanup_quadrant(q);
@@ -991,217 +93,42 @@ void TileMap::_erase_quadrant(HashMap<Vector2i, TileMapQuadrant>::Iterator Q) {
// Remove the quadrant from the dirty_list if it is there.
if (q->dirty_list_element.in_list()) {
- layers[q->layer].dirty_quadrant_list.remove(&(q->dirty_list_element));
+ dirty_quadrant_list.remove(&(q->dirty_list_element));
}
// Free the debug canvas item.
RenderingServer *rs = RenderingServer::get_singleton();
rs->free(q->debug_canvas_item);
- layers[q->layer].quadrant_map.remove(Q);
+ quadrant_map.remove(Q);
rect_cache_dirty = true;
}
-void TileMap::_clear_layer_internals(int p_layer) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- // Clear quadrants.
- while (layers[p_layer].quadrant_map.size()) {
- _erase_quadrant(layers[p_layer].quadrant_map.begin());
- }
-
- // Clear the layers internals.
- _rendering_cleanup_layer(p_layer);
-
- // Clear the layers internal navigation maps.
- _navigation_cleanup_layer(p_layer);
-
- // Clear the dirty quadrants list.
- while (layers[p_layer].dirty_quadrant_list.first()) {
- layers[p_layer].dirty_quadrant_list.remove(layers[p_layer].dirty_quadrant_list.first());
- }
-}
-
-void TileMap::_clear_internals() {
- // Clear quadrants.
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- _clear_layer_internals(layer);
- }
-}
-
-void TileMap::_recompute_rect_cache() {
- // Compute the displayed area of the tilemap.
-#ifdef DEBUG_ENABLED
-
- if (!rect_cache_dirty) {
- return;
- }
-
- Rect2 r_total;
- bool first = true;
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
- Rect2 r;
- r.position = map_to_local(E.key * get_effective_quadrant_size(layer));
- r.expand_to(map_to_local((E.key + Vector2i(1, 0)) * get_effective_quadrant_size(layer)));
- r.expand_to(map_to_local((E.key + Vector2i(1, 1)) * get_effective_quadrant_size(layer)));
- r.expand_to(map_to_local((E.key + Vector2i(0, 1)) * get_effective_quadrant_size(layer)));
- if (first) {
- r_total = r;
- first = false;
- } else {
- r_total = r_total.merge(r);
- }
- }
- }
-
- bool changed = rect_cache != r_total;
-
- rect_cache = r_total;
-
- item_rect_changed(changed);
-
- rect_cache_dirty = false;
-#endif
-}
-
/////////////////////////////// Rendering //////////////////////////////////////
-void TileMap::_rendering_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_CANVAS: {
- bool node_visible = is_visible_in_tree();
- for (TileMapLayer &layer : layers) {
- for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) {
- TileMapQuadrant &q = E_quadrant.value;
- for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
- Transform2D xform;
- xform.set_origin(map_to_local(kv.key));
- RS::get_singleton()->canvas_light_occluder_attach_to_canvas(kv.value, get_canvas());
- RS::get_singleton()->canvas_light_occluder_set_transform(kv.value, get_global_transform() * xform);
- RS::get_singleton()->canvas_light_occluder_set_enabled(kv.value, node_visible);
- }
- }
- }
- } break;
-
- case NOTIFICATION_VISIBILITY_CHANGED: {
- bool node_visible = is_visible_in_tree();
- for (TileMapLayer &layer : layers) {
- for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) {
- TileMapQuadrant &q = E_quadrant.value;
-
- // Update occluders transform.
- for (const KeyValue<Vector2, Vector2i> &E_cell : q.local_to_map) {
- Transform2D xform;
- xform.set_origin(E_cell.key);
- for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
- RS::get_singleton()->canvas_light_occluder_set_enabled(kv.value, node_visible);
- }
- }
- }
- }
- } break;
-
- case NOTIFICATION_TRANSFORM_CHANGED: {
- if (!is_inside_tree()) {
- return;
- }
- for (TileMapLayer &layer : layers) {
- for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) {
- TileMapQuadrant &q = E_quadrant.value;
-
- // Update occluders transform.
- for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
- Transform2D xform;
- xform.set_origin(map_to_local(kv.key));
- RenderingServer::get_singleton()->canvas_light_occluder_set_transform(kv.value, get_global_transform() * xform);
- }
- }
- }
- } break;
-
- case NOTIFICATION_DRAW: {
- if (tile_set.is_valid()) {
- RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), is_y_sort_enabled());
- }
- } break;
-
- case NOTIFICATION_EXIT_CANVAS: {
- for (TileMapLayer &layer : layers) {
- for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) {
- TileMapQuadrant &q = E_quadrant.value;
- for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
- RS::get_singleton()->canvas_light_occluder_attach_to_canvas(kv.value, RID());
- }
- }
- }
- } break;
- }
-}
-
-void TileMap::_navigation_update_layer(int p_layer) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
- ERR_FAIL_NULL(NavigationServer2D::get_singleton());
-
- if (!layers[p_layer].navigation_map.is_valid()) {
- if (p_layer == 0 && is_inside_tree()) {
- // Use the default World2D navigation map for the first layer when empty.
- layers[p_layer].navigation_map = get_world_2d()->get_navigation_map();
- layers[p_layer].uses_world_navigation_map = true;
- } else {
- RID new_layer_map = NavigationServer2D::get_singleton()->map_create();
- NavigationServer2D::get_singleton()->map_set_active(new_layer_map, true);
- layers[p_layer].navigation_map = new_layer_map;
- layers[p_layer].uses_world_navigation_map = false;
- }
- }
-}
-
-void TileMap::_navigation_cleanup_layer(int p_layer) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
- ERR_FAIL_NULL(NavigationServer2D::get_singleton());
-
- if (layers[p_layer].navigation_map.is_valid()) {
- if (layers[p_layer].uses_world_navigation_map) {
- // Do not delete the World2D default navigation map.
- return;
- }
- NavigationServer2D::get_singleton()->free(layers[p_layer].navigation_map);
- layers[p_layer].navigation_map = RID();
- }
-}
-
-void TileMap::_rendering_update_layer(int p_layer) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
+void TileMapLayer::_rendering_update() {
RenderingServer *rs = RenderingServer::get_singleton();
- if (!layers[p_layer].canvas_item.is_valid()) {
+ if (!canvas_item.is_valid()) {
RID ci = rs->canvas_item_create();
- rs->canvas_item_set_parent(ci, get_canvas_item());
-
- /*Transform2D xform;
- xform.set_origin(Vector2(0, p_layer));
- rs->canvas_item_set_transform(ci, xform);*/
- rs->canvas_item_set_draw_index(ci, p_layer - (int64_t)0x80000000);
-
- layers[p_layer].canvas_item = ci;
- }
- RID &ci = layers[p_layer].canvas_item;
- rs->canvas_item_set_sort_children_by_y(ci, layers[p_layer].y_sort_enabled);
- rs->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid());
- rs->canvas_item_set_z_index(ci, layers[p_layer].z_index);
- rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
- rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
- rs->canvas_item_set_light_mask(ci, get_light_mask());
-
- Color layer_modulate = get_layer_modulate(p_layer);
- if (selected_layer >= 0 && p_layer != selected_layer) {
- int z1 = get_layer_z_index(p_layer);
- int z2 = get_layer_z_index(selected_layer);
- if (z1 < z2 || (z1 == z2 && p_layer < selected_layer)) {
+ rs->canvas_item_set_parent(ci, tile_map_node->get_canvas_item());
+ rs->canvas_item_set_draw_index(ci, layer_index_in_tile_map_node - (int64_t)0x80000000);
+ canvas_item = ci;
+ }
+ RID &ci = canvas_item;
+ rs->canvas_item_set_sort_children_by_y(ci, y_sort_enabled);
+ rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid());
+ rs->canvas_item_set_z_index(ci, z_index);
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree()));
+ rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
+
+ Color layer_modulate = modulate;
+ int selected_layer = tile_map_node->get_selected_layer();
+ if (selected_layer >= 0 && layer_index_in_tile_map_node != selected_layer) {
+ int z_selected = tile_map_node->get_layer_z_index(selected_layer);
+ if (z_index < z_selected || (z_index == z_selected && layer_index_in_tile_map_node < selected_layer)) {
layer_modulate = layer_modulate.darkened(0.5);
- } else if (z1 > z2 || (z1 == z2 && p_layer > selected_layer)) {
+ } else if (z_index > z_selected || (z_index == z_selected && layer_index_in_tile_map_node > selected_layer)) {
layer_modulate = layer_modulate.darkened(0.5);
layer_modulate.a *= 0.3;
}
@@ -1209,22 +136,21 @@ void TileMap::_rendering_update_layer(int p_layer) {
rs->canvas_item_set_modulate(ci, layer_modulate);
}
-void TileMap::_rendering_cleanup_layer(int p_layer) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
+void TileMapLayer::_rendering_cleanup() {
ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer *rs = RenderingServer::get_singleton();
- if (layers[p_layer].canvas_item.is_valid()) {
- rs->free(layers[p_layer].canvas_item);
- layers[p_layer].canvas_item = RID();
+ if (canvas_item.is_valid()) {
+ rs->free(canvas_item);
+ canvas_item = RID();
}
}
-void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
- ERR_FAIL_COND(!is_inside_tree());
+void TileMapLayer::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ ERR_FAIL_COND(!tile_map_node->is_inside_tree());
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
- bool node_visible = is_visible_in_tree();
+ bool node_visible = tile_map_node->is_visible_in_tree();
SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
while (q_list_element) {
@@ -1251,7 +177,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
// Iterate over the cells of the quadrant.
for (const KeyValue<Vector2, Vector2i> &E_cell : q.local_to_map) {
- TileMapCell c = get_cell(q.layer, E_cell.value, true);
+ TileMapCell c = get_cell(E_cell.value, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1275,10 +201,10 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
int tile_z_index = tile_data->get_z_index();
// Quandrant pos.
- Vector2 tile_position = map_to_local(q.coords * get_effective_quadrant_size(q.layer));
- if (is_y_sort_enabled() && layers[q.layer].y_sort_enabled) {
+ Vector2 tile_position = tile_map_node->map_to_local(q.coords * get_effective_quadrant_size());
+ if (tile_map_node->is_y_sort_enabled() && y_sort_enabled) {
// When Y-sorting, the quandrant size is sure to be 1, we can thus offset the CanvasItem.
- tile_position.y += layers[q.layer].y_sort_origin + tile_data->get_y_sort_origin();
+ tile_position.y += y_sort_origin + tile_data->get_y_sort_origin();
}
// --- CanvasItems ---
@@ -1292,19 +218,19 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
if (mat.is_valid()) {
rs->canvas_item_set_material(ci, mat->get_rid());
}
- rs->canvas_item_set_parent(ci, layers[q.layer].canvas_item);
- rs->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid());
+ rs->canvas_item_set_parent(ci, canvas_item);
+ rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid());
Transform2D xform;
xform.set_origin(tile_position);
rs->canvas_item_set_transform(ci, xform);
- rs->canvas_item_set_light_mask(ci, get_light_mask());
+ rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
rs->canvas_item_set_z_as_relative_to_parent(ci, true);
rs->canvas_item_set_z_index(ci, tile_z_index);
- rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
- rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree()));
q.canvas_items.push_back(ci);
@@ -1317,8 +243,17 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
ci = prev_ci;
}
+ // Random animation offset.
+ real_t random_animation_offset = 0.0;
+ if (atlas_source->get_tile_animation_mode(c.get_atlas_coords()) != TileSetAtlasSource::TILE_ANIMATION_MODE_DEFAULT) {
+ Array to_hash;
+ to_hash.push_back(E_cell.key);
+ to_hash.push_back(get_instance_id()); // Use instance id as a random hash
+ random_animation_offset = RandomPCG(to_hash.hash()).randf();
+ }
+
// Drawing the tile in the canvas item.
- draw_tile(ci, E_cell.key - tile_position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, get_self_modulate(), tile_data);
+ tile_map_node->draw_tile(ci, E_cell.key - tile_position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, tile_map_node->get_self_modulate(), tile_data, random_animation_offset);
// --- Occluders ---
for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
@@ -1327,9 +262,9 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
if (tile_data->get_occluder(i).is_valid()) {
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, get_global_transform() * xform);
+ 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_attach_to_canvas(occluder_id, get_canvas());
+ 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));
q.occluders[E_cell.value] = occluder_id;
}
@@ -1342,36 +277,35 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
q_list_element = q_list_element->next();
}
- // Reset the drawing indices
+ // Reset the drawing indices.
if (_rendering_quadrant_order_dirty) {
int index = -(int64_t)0x80000000; //always must be drawn below children.
- for (TileMapLayer &layer : layers) {
- // Sort the quadrants coords per local coordinates.
- RBMap<Vector2, Vector2i, TileMapQuadrant::CoordsWorldComparator> local_to_map;
- for (const KeyValue<Vector2i, TileMapQuadrant> &E : layer.quadrant_map) {
- local_to_map[map_to_local(E.key)] = E.key;
- }
+ // Sort the quadrants coords per local coordinates.
+ RBMap<Vector2, Vector2i, TileMapQuadrant::CoordsWorldComparator> local_to_map;
+ for (const KeyValue<Vector2i, TileMapQuadrant> &E : quadrant_map) {
+ local_to_map[tile_map_node->map_to_local(E.key)] = E.key;
+ }
- // Sort the quadrants.
- for (const KeyValue<Vector2, Vector2i> &E : local_to_map) {
- TileMapQuadrant &q = layer.quadrant_map[E.value];
- for (const RID &ci : q.canvas_items) {
- RS::get_singleton()->canvas_item_set_draw_index(ci, index++);
- }
+ // Sort the quadrants.
+ for (const KeyValue<Vector2, Vector2i> &E : local_to_map) {
+ TileMapQuadrant &q = quadrant_map[E.value];
+ for (const RID &ci : q.canvas_items) {
+ RS::get_singleton()->canvas_item_set_draw_index(ci, index++);
}
}
_rendering_quadrant_order_dirty = false;
}
}
-void TileMap::_rendering_create_quadrant(TileMapQuadrant *p_quadrant) {
+void TileMapLayer::_rendering_create_quadrant(TileMapQuadrant *p_quadrant) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
_rendering_quadrant_order_dirty = true;
}
-void TileMap::_rendering_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
+void TileMapLayer::_rendering_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
ERR_FAIL_NULL(RenderingServer::get_singleton());
// Free the canvas items.
for (const RID &ci : p_quadrant->canvas_items) {
@@ -1386,7 +320,8 @@ void TileMap::_rendering_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
p_quadrant->occluders.clear();
}
-void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
+void TileMapLayer::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
if (!Engine::get_singleton()->is_editor_hint()) {
@@ -1395,9 +330,9 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder for tiles needing one.
RenderingServer *rs = RenderingServer::get_singleton();
- Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = tile_map_node->map_to_local(p_quadrant->coords * get_effective_quadrant_size());
for (const Vector2i &E_cell : p_quadrant->cells) {
- const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true);
+ const TileMapCell &c = get_cell(E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1427,7 +362,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder tile.
Transform2D cell_to_quadrant;
- cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ cell_to_quadrant.set_origin(tile_map_node->map_to_local(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
@@ -1436,167 +371,17 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
}
}
-void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation, const TileData *p_tile_data_override) {
- ERR_FAIL_COND(!p_tile_set.is_valid());
- ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
- ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
- ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile));
- TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
- if (atlas_source) {
- // Check for the frame.
- if (p_frame >= 0) {
- ERR_FAIL_INDEX(p_frame, atlas_source->get_tile_animation_frames_count(p_atlas_coords));
- }
-
- // Get the texture.
- Ref<Texture2D> tex = atlas_source->get_runtime_texture();
- if (!tex.is_valid()) {
- return;
- }
-
- // Check if we are in the texture, return otherwise.
- Vector2i grid_size = atlas_source->get_atlas_grid_size();
- if (p_atlas_coords.x >= grid_size.x || p_atlas_coords.y >= grid_size.y) {
- return;
- }
-
- // Get tile data.
- const TileData *tile_data = p_tile_data_override ? p_tile_data_override : atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile);
-
- // Get the tile modulation.
- Color modulate = tile_data->get_modulate() * p_modulation;
-
- // Compute the offset.
- Vector2 tile_offset = tile_data->get_texture_origin();
-
- // Get destination rect.
- Rect2 dest_rect;
- dest_rect.size = atlas_source->get_runtime_tile_texture_region(p_atlas_coords).size;
- dest_rect.size.x += FP_ADJUST;
- dest_rect.size.y += FP_ADJUST;
-
- bool transpose = tile_data->get_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()) {
- dest_rect.size.x = -dest_rect.size.x;
- }
-
- if (tile_data->get_flip_v()) {
- dest_rect.size.y = -dest_rect.size.y;
- }
-
- // Draw the tile.
- if (p_frame >= 0) {
- Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, p_frame);
- tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
- } else if (atlas_source->get_tile_animation_frames_count(p_atlas_coords) == 1) {
- Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, 0);
- tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
- } else {
- real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords);
- real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed;
- real_t time = 0.0;
- for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) {
- real_t frame_duration = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame) / speed;
- RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, time, time + frame_duration, 0.0);
-
- Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, frame);
- tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
-
- time += frame_duration;
- }
- RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0);
- }
- }
-}
-
/////////////////////////////// Physics //////////////////////////////////////
-void TileMap::_physics_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- bool in_editor = false;
-#ifdef TOOLS_ENABLED
- in_editor = Engine::get_singleton()->is_editor_hint();
-#endif
- if (is_inside_tree() && collision_animatable && !in_editor) {
- // Update transform on the physics tick when in animatable mode.
- last_valid_transform = new_transform;
- set_notify_local_transform(false);
- set_global_transform(new_transform);
- set_notify_local_transform(true);
- }
- } break;
-
- case NOTIFICATION_TRANSFORM_CHANGED: {
- bool in_editor = false;
-#ifdef TOOLS_ENABLED
- in_editor = Engine::get_singleton()->is_editor_hint();
-#endif
- if (is_inside_tree() && (!collision_animatable || in_editor)) {
- // Update the new transform directly if we are not in animatable mode.
- Transform2D gl_transform = get_global_transform();
- for (TileMapLayer &layer : layers) {
- for (KeyValue<Vector2i, TileMapQuadrant> &E : layer.quadrant_map) {
- TileMapQuadrant &q = E.value;
-
- for (RID body : q.bodies) {
- Transform2D xform;
- xform.set_origin(map_to_local(bodies_coords[body]));
- xform = gl_transform * xform;
- PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
- }
- }
- }
- }
- } break;
-
- case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- bool in_editor = false;
-#ifdef TOOLS_ENABLED
- in_editor = Engine::get_singleton()->is_editor_hint();
-#endif
- if (is_inside_tree() && !in_editor && collision_animatable) {
- // Only active when animatable. Send the new transform to the physics...
- new_transform = get_global_transform();
- for (TileMapLayer &layer : layers) {
- for (KeyValue<Vector2i, TileMapQuadrant> &E : layer.quadrant_map) {
- TileMapQuadrant &q = E.value;
-
- for (RID body : q.bodies) {
- Transform2D xform;
- xform.set_origin(map_to_local(bodies_coords[body]));
- xform = new_transform * xform;
-
- PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
- }
- }
- }
-
- // ... but then revert changes.
- set_notify_local_transform(false);
- set_global_transform(last_valid_transform);
- set_notify_local_transform(true);
- }
- } break;
- }
-}
-
-void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
- ERR_FAIL_COND(!is_inside_tree());
+void TileMapLayer::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ ERR_FAIL_COND(!tile_map_node->is_inside_tree());
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
- Transform2D gl_transform = get_global_transform();
- last_valid_transform = gl_transform;
- new_transform = gl_transform;
+ Transform2D gl_transform = tile_map_node->get_global_transform();
+
PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
- RID space = get_world_2d()->get_space();
+ RID space = tile_map_node->get_world_2d()->get_space();
SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
while (q_list_element) {
@@ -1611,7 +396,7 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
// Recreate bodies and shapes.
for (const Vector2i &E_cell : q.cells) {
- TileMapCell c = get_cell(q.layer, E_cell, true);
+ TileMapCell c = get_cell(E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1637,16 +422,15 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
// Create the body.
RID body = ps->body_create();
bodies_coords[body] = E_cell;
- bodies_layers[body] = q.layer;
- ps->body_set_mode(body, collision_animatable ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC);
+ ps->body_set_mode(body, tile_map_node->is_collision_animatable() ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC);
ps->body_set_space(body, space);
Transform2D xform;
- xform.set_origin(map_to_local(E_cell));
+ xform.set_origin(tile_map_node->map_to_local(E_cell));
xform = gl_transform * xform;
ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
- ps->body_attach_object_instance_id(body, get_instance_id());
+ ps->body_attach_object_instance_id(body, tile_map_node->get_instance_id());
ps->body_set_collision_layer(body, physics_layer);
ps->body_set_collision_mask(body, physics_mask);
ps->body_set_pickable(body, false);
@@ -1688,29 +472,29 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
}
}
-void TileMap::_physics_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
+void TileMapLayer::_physics_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
// Remove a quadrant.
ERR_FAIL_NULL(PhysicsServer2D::get_singleton());
for (RID body : p_quadrant->bodies) {
bodies_coords.erase(body);
- bodies_layers.erase(body);
PhysicsServer2D::get_singleton()->free(body);
}
p_quadrant->bodies.clear();
}
-void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
+void TileMapLayer::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw the debug collision shapes.
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
- if (!get_tree()) {
+ if (!tile_map_node->get_tree()) {
return;
}
bool show_collision = false;
- switch (collision_visibility_mode) {
+ switch (tile_map_node->get_collision_visibility_mode()) {
case TileMap::VISIBILITY_MODE_DEFAULT:
- show_collision = !Engine::get_singleton()->is_editor_hint() && (get_tree() && get_tree()->is_debugging_collisions_hint());
+ show_collision = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_collisions_hint();
break;
case TileMap::VISIBILITY_MODE_FORCE_HIDE:
show_collision = false;
@@ -1726,14 +510,14 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
RenderingServer *rs = RenderingServer::get_singleton();
PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
- Color debug_collision_color = get_tree()->get_debug_collisions_color();
+ Color debug_collision_color = tile_map_node->get_tree()->get_debug_collisions_color();
Vector<Color> color;
color.push_back(debug_collision_color);
- Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = tile_map_node->map_to_local(p_quadrant->coords * get_effective_quadrant_size());
Transform2D quadrant_to_local;
quadrant_to_local.set_origin(quadrant_pos);
- Transform2D global_to_quadrant = (get_global_transform() * quadrant_to_local).affine_inverse();
+ Transform2D global_to_quadrant = (tile_map_node->get_global_transform() * quadrant_to_local).affine_inverse();
for (RID body : p_quadrant->bodies) {
Transform2D body_to_quadrant = global_to_quadrant * Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM));
@@ -1754,36 +538,12 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
/////////////////////////////// Navigation //////////////////////////////////////
-void TileMap::_navigation_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_TRANSFORM_CHANGED: {
- if (is_inside_tree()) {
- for (TileMapLayer &layer : layers) {
- Transform2D tilemap_xform = get_global_transform();
- for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) {
- TileMapQuadrant &q = E_quadrant.value;
- for (const KeyValue<Vector2i, Vector<RID>> &E_region : q.navigation_regions) {
- for (const RID &region : E_region.value) {
- if (!region.is_valid()) {
- continue;
- }
- Transform2D tile_transform;
- tile_transform.set_origin(map_to_local(E_region.key));
- NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
- }
- }
- }
- }
- }
- } break;
- }
-}
-
-void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
- ERR_FAIL_COND(!is_inside_tree());
+void TileMapLayer::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ ERR_FAIL_COND(!tile_map_node->is_inside_tree());
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
- Transform2D tilemap_xform = get_global_transform();
+ Transform2D tilemap_xform = tile_map_node->get_global_transform();
SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
while (q_list_element) {
TileMapQuadrant &q = *q_list_element->self();
@@ -1802,7 +562,7 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
// Get the navigation polygons and create regions.
for (const Vector2i &E_cell : q.cells) {
- TileMapCell c = get_cell(q.layer, E_cell, true);
+ TileMapCell c = get_cell(E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1822,24 +582,21 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
}
q.navigation_regions[E_cell].resize(tile_set->get_navigation_layers_count());
- for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
- if (layer_index >= (int)layers.size() || !layers[layer_index].navigation_map.is_valid()) {
- continue;
- }
+ for (int navigation_layer_index = 0; navigation_layer_index < tile_set->get_navigation_layers_count(); navigation_layer_index++) {
Ref<NavigationPolygon> navigation_polygon;
- navigation_polygon = tile_data->get_navigation_polygon(layer_index);
+ navigation_polygon = tile_data->get_navigation_polygon(navigation_layer_index);
if (navigation_polygon.is_valid()) {
Transform2D tile_transform;
- tile_transform.set_origin(map_to_local(E_cell));
+ tile_transform.set_origin(tile_map_node->map_to_local(E_cell));
RID region = NavigationServer2D::get_singleton()->region_create();
- NavigationServer2D::get_singleton()->region_set_owner_id(region, get_instance_id());
- NavigationServer2D::get_singleton()->region_set_map(region, layers[layer_index].navigation_map);
+ NavigationServer2D::get_singleton()->region_set_owner_id(region, tile_map_node->get_instance_id());
+ NavigationServer2D::get_singleton()->region_set_map(region, navigation_map);
NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
- NavigationServer2D::get_singleton()->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(layer_index));
+ NavigationServer2D::get_singleton()->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(navigation_layer_index));
NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, navigation_polygon);
- q.navigation_regions[E_cell].write[layer_index] = region;
+ q.navigation_regions[E_cell].write[navigation_layer_index] = region;
}
}
}
@@ -1850,7 +607,39 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
}
}
-void TileMap::_navigation_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
+void TileMapLayer::_navigation_update() {
+ ERR_FAIL_NULL(NavigationServer2D::get_singleton());
+
+ if (!navigation_map.is_valid()) {
+ if (layer_index_in_tile_map_node == 0 && tile_map_node->is_inside_tree()) {
+ // Use the default World2D navigation map for the first layer when empty.
+ navigation_map = tile_map_node->get_world_2d()->get_navigation_map();
+ uses_world_navigation_map = true;
+ } else {
+ RID new_layer_map = NavigationServer2D::get_singleton()->map_create();
+ // Set the default NavigationPolygon cell_size on the new map as a mismatch causes an error.
+ NavigationServer2D::get_singleton()->map_set_cell_size(new_layer_map, 1.0);
+ NavigationServer2D::get_singleton()->map_set_active(new_layer_map, true);
+ navigation_map = new_layer_map;
+ uses_world_navigation_map = false;
+ }
+ }
+}
+
+void TileMapLayer::_navigation_cleanup() {
+ ERR_FAIL_NULL(NavigationServer2D::get_singleton());
+
+ if (navigation_map.is_valid()) {
+ if (uses_world_navigation_map) {
+ // Do not delete the World2D default navigation map.
+ return;
+ }
+ NavigationServer2D::get_singleton()->free(navigation_map);
+ navigation_map = RID();
+ }
+}
+
+void TileMapLayer::_navigation_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
// Clear navigation shapes in the quadrant.
ERR_FAIL_NULL(NavigationServer2D::get_singleton());
for (const KeyValue<Vector2i, Vector<RID>> &E : p_quadrant->navigation_regions) {
@@ -1865,18 +654,19 @@ void TileMap::_navigation_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
p_quadrant->navigation_regions.clear();
}
-void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
+void TileMapLayer::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw the debug collision shapes.
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
- if (!get_tree()) {
+ if (!tile_map_node->get_tree()) {
return;
}
bool show_navigation = false;
- switch (navigation_visibility_mode) {
+ switch (tile_map_node->get_navigation_visibility_mode()) {
case TileMap::VISIBILITY_MODE_DEFAULT:
- show_navigation = !Engine::get_singleton()->is_editor_hint() && (get_tree() && get_tree()->is_debugging_navigation_hint());
+ show_navigation = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_navigation_hint();
break;
case TileMap::VISIBILITY_MODE_FORCE_HIDE:
show_navigation = false;
@@ -1901,10 +691,10 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
RandomPCG rand;
- Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = tile_map_node->map_to_local(p_quadrant->coords * get_effective_quadrant_size());
for (const Vector2i &E_cell : p_quadrant->cells) {
- TileMapCell c = get_cell(p_quadrant->layer, E_cell, true);
+ TileMapCell c = get_cell(E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1924,7 +714,7 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
}
Transform2D cell_to_quadrant;
- cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ cell_to_quadrant.set_origin(tile_map_node->map_to_local(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
@@ -1976,37 +766,26 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
/////////////////////////////// Scenes //////////////////////////////////////
-void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+void TileMapLayer::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
while (q_list_element) {
TileMapQuadrant &q = *q_list_element->self();
-
- // Clear the scenes if instance cache was cleared.
- if (instantiated_scenes.is_empty()) {
- for (const KeyValue<Vector2i, String> &E : q.scenes) {
- Node *node = get_node_or_null(E.value);
- if (node) {
- node->queue_free();
- }
- }
- }
-
- q.scenes.clear();
+ _scenes_cleanup_quadrant(&q);
// Recreate the scenes.
for (const Vector2i &E_cell : q.cells) {
- Vector3i cell_coords = Vector3i(q.layer, E_cell.x, E_cell.y);
- if (instantiated_scenes.has(cell_coords)) {
+ if (instantiated_scenes.has(E_cell)) {
// Skip scene if the instance was cached (to avoid recreating scenes unnecessarily).
continue;
}
if (!Engine::get_singleton()->is_editor_hint()) {
- instantiated_scenes.insert(cell_coords);
+ instantiated_scenes.insert(E_cell);
}
- const TileMapCell &c = get_cell(q.layer, E_cell, true);
+ const TileMapCell &c = get_cell(E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -2024,13 +803,13 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
Control *scene_as_control = Object::cast_to<Control>(scene);
Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene);
if (scene_as_control) {
- scene_as_control->set_position(map_to_local(E_cell) + scene_as_control->get_position());
+ scene_as_control->set_position(tile_map_node->map_to_local(E_cell) + scene_as_control->get_position());
} else if (scene_as_node2d) {
Transform2D xform;
- xform.set_origin(map_to_local(E_cell));
+ xform.set_origin(tile_map_node->map_to_local(E_cell));
scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
}
- add_child(scene);
+ tile_map_node->add_child(scene);
q.scenes[E_cell] = scene->get_name();
}
}
@@ -2041,11 +820,11 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
}
}
-void TileMap::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
+void TileMapLayer::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
// Clear the scenes if instance cache was cleared.
if (instantiated_scenes.is_empty()) {
for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) {
- Node *node = get_node_or_null(E.value);
+ Node *node = tile_map_node->get_node_or_null(E.value);
if (node) {
node->queue_free();
}
@@ -2054,7 +833,8 @@ void TileMap::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
}
}
-void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
+void TileMapLayer::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
if (!Engine::get_singleton()->is_editor_hint()) {
@@ -2063,9 +843,9 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder for scenes needing one.
RenderingServer *rs = RenderingServer::get_singleton();
- Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = tile_map_node->map_to_local(p_quadrant->coords * get_effective_quadrant_size());
for (const Vector2i &E_cell : p_quadrant->cells) {
- const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true);
+ const TileMapCell &c = get_cell(E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -2093,7 +873,7 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder tile.
Transform2D cell_to_quadrant;
- cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ cell_to_quadrant.set_origin(tile_map_node->map_to_local(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
@@ -2102,249 +882,51 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
}
}
-void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
-
- // Set the current cell tile (using integer position).
- HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- Vector2i pk(p_coords);
- HashMap<Vector2i, TileMapCell>::Iterator E = tile_map.find(pk);
-
- int source_id = p_source_id;
- Vector2i atlas_coords = p_atlas_coords;
- int alternative_tile = p_alternative_tile;
-
- if ((source_id == TileSet::INVALID_SOURCE || atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE) &&
- (source_id != TileSet::INVALID_SOURCE || atlas_coords != TileSetSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE)) {
- source_id = TileSet::INVALID_SOURCE;
- atlas_coords = TileSetSource::INVALID_ATLAS_COORDS;
- alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
- }
-
- if (!E && source_id == TileSet::INVALID_SOURCE) {
- return; // Nothing to do, the tile is already empty.
- }
-
- // Get the quadrant
- Vector2i qk = _coords_to_quadrant_coords(p_layer, pk);
-
- HashMap<Vector2i, TileMapQuadrant>::Iterator Q = layers[p_layer].quadrant_map.find(qk);
-
- if (source_id == TileSet::INVALID_SOURCE) {
- // Erase existing cell in the tile map.
- tile_map.erase(pk);
-
- // Erase existing cell in the quadrant.
- ERR_FAIL_COND(!Q);
- TileMapQuadrant &q = Q->value;
-
- q.cells.erase(pk);
-
- // Remove or make the quadrant dirty.
- if (q.cells.size() == 0) {
- _erase_quadrant(Q);
- } else {
- _make_quadrant_dirty(Q);
- }
-
- used_rect_cache_dirty = true;
- } else {
- if (!E) {
- // Insert a new cell in the tile map.
- E = tile_map.insert(pk, TileMapCell());
-
- // Create a new quadrant if needed, then insert the cell if needed.
- if (!Q) {
- Q = _create_quadrant(p_layer, qk);
- }
- TileMapQuadrant &q = Q->value;
- q.cells.insert(pk);
-
- } else {
- ERR_FAIL_COND(!Q); // TileMapQuadrant should exist...
-
- if (E->value.source_id == source_id && E->value.get_atlas_coords() == atlas_coords && E->value.alternative_tile == alternative_tile) {
- return; // Nothing changed.
- }
- }
-
- TileMapCell &c = E->value;
-
- c.source_id = source_id;
- c.set_atlas_coords(atlas_coords);
- c.alternative_tile = alternative_tile;
-
- _make_quadrant_dirty(Q);
- used_rect_cache_dirty = true;
- }
-}
-
-void TileMap::erase_cell(int p_layer, const Vector2i &p_coords) {
- set_cell(p_layer, p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
-}
-
-int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSet::INVALID_SOURCE);
-
- // Get a cell source id from position.
- const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
-
- if (!E) {
- return TileSet::INVALID_SOURCE;
- }
-
- if (p_use_proxies && tile_set.is_valid()) {
- Array proxyed = tile_set->map_tile_proxy(E->value.source_id, E->value.get_atlas_coords(), E->value.alternative_tile);
- return proxyed[0];
- }
-
- return E->value.source_id;
-}
-
-Vector2i TileMap::get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSetSource::INVALID_ATLAS_COORDS);
-
- // Get a cell source id from position
- const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
-
- if (!E) {
- return TileSetSource::INVALID_ATLAS_COORDS;
- }
-
- if (p_use_proxies && tile_set.is_valid()) {
- Array proxyed = tile_set->map_tile_proxy(E->value.source_id, E->value.get_atlas_coords(), E->value.alternative_tile);
- return proxyed[1];
- }
-
- return E->value.get_atlas_coords();
-}
-
-int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSetSource::INVALID_TILE_ALTERNATIVE);
-
- // Get a cell source id from position
- const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
-
- if (!E) {
- return TileSetSource::INVALID_TILE_ALTERNATIVE;
- }
-
- if (p_use_proxies && tile_set.is_valid()) {
- Array proxyed = tile_set->map_tile_proxy(E->value.source_id, E->value.get_atlas_coords(), E->value.alternative_tile);
- return proxyed[2];
- }
-
- return E->value.alternative_tile;
-}
+/////////////////////////////////////////////////////////////////////
-TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
- int source_id = get_cell_source_id(p_layer, p_coords, p_use_proxies);
- if (source_id == TileSet::INVALID_SOURCE) {
- return nullptr;
+void TileMapLayer::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ if (!tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) || !tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) {
+ return;
}
- Ref<TileSetAtlasSource> source = tile_set->get_source(source_id);
- if (source.is_valid()) {
- return source->get_tile_data(get_cell_atlas_coords(p_layer, p_coords, p_use_proxies), get_cell_alternative_tile(p_layer, p_coords, p_use_proxies));
- }
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
+ SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
+ while (q_list_element) {
+ TileMapQuadrant &q = *q_list_element->self();
+ // Iterate over the cells of the quadrant.
+ for (const KeyValue<Vector2, Vector2i> &E_cell : q.local_to_map) {
+ TileMapCell c = get_cell(E_cell.value, true);
- return nullptr;
-}
+ TileSetSource *source;
+ if (tile_set->has_source(c.source_id)) {
+ source = *tile_set->get_source(c.source_id);
-Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
- ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
- Ref<TileMapPattern> output;
- output.instantiate();
- if (p_coords_array.is_empty()) {
- return output;
- }
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ bool ret = false;
+ if (tile_map_node->GDVIRTUAL_CALL(_use_tile_data_runtime_update, layer_index_in_tile_map_node, E_cell.value, ret) && ret) {
+ TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
- Vector2i min = Vector2i(p_coords_array[0]);
- for (int i = 1; i < p_coords_array.size(); i++) {
- min = min.min(p_coords_array[i]);
- }
+ // Create the runtime TileData.
+ TileData *tile_data_runtime_use = tile_data->duplicate();
+ tile_data_runtime_use->set_allow_transform(true);
+ q.runtime_tile_data_cache[E_cell.value] = tile_data_runtime_use;
- Vector<Vector2i> coords_in_pattern_array;
- coords_in_pattern_array.resize(p_coords_array.size());
- Vector2i ensure_positive_offset;
- for (int i = 0; i < p_coords_array.size(); i++) {
- Vector2i coords = p_coords_array[i];
- Vector2i coords_in_pattern = coords - min;
- if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
- if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
- coords_in_pattern.x -= 1;
- if (coords_in_pattern.x < 0) {
- ensure_positive_offset.x = 1;
+ tile_map_node->GDVIRTUAL_CALL(_tile_data_runtime_update, layer_index_in_tile_map_node, E_cell.value, tile_data_runtime_use);
}
- } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
- coords_in_pattern.y -= 1;
- if (coords_in_pattern.y < 0) {
- ensure_positive_offset.y = 1;
- }
- }
- } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
- coords_in_pattern.x += 1;
- } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
- coords_in_pattern.y += 1;
}
}
}
- coords_in_pattern_array.write[i] = coords_in_pattern;
- }
-
- for (int i = 0; i < coords_in_pattern_array.size(); i++) {
- Vector2i coords = p_coords_array[i];
- Vector2i coords_in_pattern = coords_in_pattern_array[i];
- output->set_cell(coords_in_pattern + ensure_positive_offset, get_cell_source_id(p_layer, coords), get_cell_atlas_coords(p_layer, coords), get_cell_alternative_tile(p_layer, coords));
- }
-
- return output;
-}
-
-Vector2i TileMap::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) {
- ERR_FAIL_COND_V(p_pattern.is_null(), Vector2i());
- ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i());
-
- Vector2i output = p_position_in_tilemap + p_coords_in_pattern;
- if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
- if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
- output.x += 1;
- } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
- output.y += 1;
- }
- } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
- output.x -= 1;
- } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
- output.y -= 1;
- }
- }
- }
-
- return output;
-}
-
-void TileMap::set_pattern(int p_layer, const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
- ERR_FAIL_COND(tile_set.is_null());
- ERR_FAIL_COND(p_pattern.is_null());
-
- TypedArray<Vector2i> used_cells = p_pattern->get_used_cells();
- for (int i = 0; i < used_cells.size(); i++) {
- Vector2i coords = map_pattern(p_position, used_cells[i], p_pattern);
- set_cell(p_layer, coords, p_pattern->get_cell_source_id(used_cells[i]), p_pattern->get_cell_atlas_coords(used_cells[i]), p_pattern->get_cell_alternative_tile(used_cells[i]));
+ q_list_element = q_list_element->next();
}
}
-TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern) {
+TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
if (!tile_set.is_valid()) {
return TileSet::TerrainsPattern();
}
@@ -2355,8 +937,8 @@ TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int
for (TileSet::TerrainsPattern &terrain_pattern : pattern_set) {
int score = 0;
- // Check the center bit constraint
- TerrainConstraint terrain_constraint = TerrainConstraint(this, p_position, terrain_pattern.get_terrain());
+ // Check the center bit constraint.
+ TerrainConstraint terrain_constraint = TerrainConstraint(tile_map_node, p_position, terrain_pattern.get_terrain());
const RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint);
if (in_set_constraint_element) {
if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
@@ -2372,7 +954,7 @@ TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
// Check if the bit is compatible with the constraints.
- TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit));
+ TerrainConstraint terrain_bit_constraint = TerrainConstraint(tile_map_node, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit));
in_set_constraint_element = p_constraints.find(terrain_bit_constraint);
if (in_set_constraint_element) {
if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
@@ -2391,7 +973,7 @@ TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int
terrain_pattern_score[terrain_pattern] = score;
}
- // Compute the minimum score
+ // Compute the minimum score.
TileSet::TerrainsPattern min_score_pattern = p_current_pattern;
int min_score = INT32_MAX;
for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) {
@@ -2404,19 +986,20 @@ TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int
return min_score_pattern;
}
-RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const {
+RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
if (!tile_set.is_valid()) {
return RBSet<TerrainConstraint>();
}
// Compute the constraints needed from the surrounding tiles.
RBSet<TerrainConstraint> output;
- output.insert(TerrainConstraint(this, p_position, p_terrains_pattern.get_terrain()));
+ output.insert(TerrainConstraint(tile_map_node, p_position, p_terrains_pattern.get_terrain()));
for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, side)) {
- TerrainConstraint c = TerrainConstraint(this, p_position, side, p_terrains_pattern.get_terrain_peering_bit(side));
+ TerrainConstraint c = TerrainConstraint(tile_map_node, p_position, side, p_terrains_pattern.get_terrain_peering_bit(side));
output.insert(c);
}
}
@@ -2424,13 +1007,13 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_added_p
return output;
}
-RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const {
+RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
if (!tile_set.is_valid()) {
return RBSet<TerrainConstraint>();
}
ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), RBSet<TerrainConstraint>());
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), RBSet<TerrainConstraint>());
// Build a set of dummy constraints to get the constrained points.
RBSet<TerrainConstraint> dummy_constraints;
@@ -2438,7 +1021,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits.
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
- dummy_constraints.insert(TerrainConstraint(this, E, bit, -1));
+ dummy_constraints.insert(TerrainConstraint(tile_map_node, E, bit, -1));
}
}
}
@@ -2452,7 +1035,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted
HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = E_constraint.get_overlapping_coords_and_peering_bits();
for (const KeyValue<Vector2i, TileSet::CellNeighbor> &E_overlapping : overlapping_terrain_bits) {
TileData *neighbor_tile_data = nullptr;
- TileMapCell neighbor_cell = get_cell(p_layer, E_overlapping.key);
+ TileMapCell neighbor_cell = get_cell(E_overlapping.key);
if (neighbor_cell.source_id != TileSet::INVALID_SOURCE) {
Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id);
Ref<TileSetAtlasSource> atlas_source = source;
@@ -2491,10 +1074,10 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted
}
}
- // Add the centers as constraints
+ // Add the centers as constraints.
for (Vector2i E_coords : p_painted) {
TileData *tile_data = nullptr;
- TileMapCell cell = get_cell(p_layer, E_coords);
+ TileMapCell cell = get_cell(E_coords);
if (cell.source_id != TileSet::INVALID_SOURCE) {
Ref<TileSetSource> source = tile_set->get_source(cell.source_id);
Ref<TileSetAtlasSource> atlas_source = source;
@@ -2505,14 +1088,54 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted
int terrain = (tile_data && tile_data->get_terrain_set() == p_terrain_set) ? tile_data->get_terrain() : -1;
if (!p_ignore_empty_terrains || terrain >= 0) {
- constraints.insert(TerrainConstraint(this, E_coords, terrain));
+ constraints.insert(TerrainConstraint(tile_map_node, E_coords, terrain));
}
}
return constraints;
}
-HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) {
+void TileMapLayer::set_tile_map(TileMap *p_tile_map) {
+ tile_map_node = p_tile_map;
+}
+
+void TileMapLayer::set_layer_index_in_tile_map_node(int p_index) {
+ layer_index_in_tile_map_node = p_index;
+}
+
+Rect2 TileMapLayer::get_rect(bool &r_changed) const {
+ // Compute the displayed area of the tilemap.
+ r_changed = false;
+#ifdef DEBUG_ENABLED
+
+ if (rect_cache_dirty) {
+ Rect2 r_total;
+ bool first = true;
+ for (const KeyValue<Vector2i, TileMapQuadrant> &E : quadrant_map) {
+ Rect2 r;
+ r.position = tile_map_node->map_to_local(E.key * get_effective_quadrant_size());
+ r.expand_to(tile_map_node->map_to_local((E.key + Vector2i(1, 0)) * get_effective_quadrant_size()));
+ r.expand_to(tile_map_node->map_to_local((E.key + Vector2i(1, 1)) * get_effective_quadrant_size()));
+ r.expand_to(tile_map_node->map_to_local((E.key + Vector2i(0, 1)) * get_effective_quadrant_size()));
+ if (first) {
+ r_total = r;
+ first = false;
+ } else {
+ r_total = r_total.merge(r);
+ }
+ }
+
+ r_changed = rect_cache != r_total;
+
+ rect_cache = r_total;
+ rect_cache_dirty = false;
+ }
+#endif
+ return rect_cache;
+}
+
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
if (!tile_set.is_valid()) {
return HashMap<Vector2i, TileSet::TerrainsPattern>();
}
@@ -2527,9 +1150,9 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(in
for (int i = 0; i < p_to_replace.size(); i++) {
const Vector2i &coords = p_to_replace[i];
- // Select the best pattern for the given constraints
+ // Select the best pattern for the given constraints.
TileSet::TerrainsPattern current_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
- TileMapCell cell = get_cell(p_layer, coords);
+ TileMapCell cell = get_cell(coords);
if (cell.source_id != TileSet::INVALID_SOURCE) {
TileSetSource *source = *tile_set->get_source(cell.source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
@@ -2543,7 +1166,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(in
}
TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints, current_pattern);
- // Update the constraint set with the new ones
+ // Update the constraint set with the new ones.
RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern);
for (const TerrainConstraint &E_constraint : new_constraints) {
if (constraints.has(E_constraint)) {
@@ -2559,12 +1182,13 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(in
return output;
}
-HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
HashMap<Vector2i, TileSet::TerrainsPattern> output;
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND_V(!tile_set.is_valid(), output);
ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output);
- // Build list and set of tiles that can be modified (painted and their surroundings)
+ // Build list and set of tiles that can be modified (painted and their surroundings).
Vector<Vector2i> can_modify_list;
RBSet<Vector2i> can_modify_set;
RBSet<Vector2i> painted_set;
@@ -2575,11 +1199,11 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
painted_set.insert(coords);
}
for (Vector2i coords : p_coords_array) {
- // Find the adequate neighbor
+ // Find the adequate neighbor.
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
- if (is_existing_neighbor(bit)) {
- Vector2i neighbor = get_neighbor_cell(coords, bit);
+ if (tile_map_node->is_existing_neighbor(bit)) {
+ Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit);
if (!can_modify_set.has(neighbor)) {
can_modify_list.push_back(neighbor);
can_modify_set.insert(neighbor);
@@ -2588,16 +1212,16 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
}
}
- // Build a set, out of the possibly modified tiles, of the one with a center bit that is set (or will be) to the painted terrain
+ // Build a set, out of the possibly modified tiles, of the one with a center bit that is set (or will be) to the painted terrain.
RBSet<Vector2i> cells_with_terrain_center_bit;
for (Vector2i coords : can_modify_set) {
bool connect = false;
if (painted_set.has(coords)) {
connect = true;
} else {
- // Get the center bit of the cell
+ // Get the center bit of the cell.
TileData *tile_data = nullptr;
- TileMapCell cell = get_cell(p_layer, coords);
+ TileMapCell cell = get_cell(coords);
if (cell.source_id != TileSet::INVALID_SOURCE) {
Ref<TileSetSource> source = tile_set->get_source(cell.source_id);
Ref<TileSetAtlasSource> atlas_source = source;
@@ -2620,7 +1244,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
// Add new constraints from the path drawn.
for (Vector2i coords : p_coords_array) {
// Constraints on the center bit.
- TerrainConstraint c = TerrainConstraint(this, coords, p_terrain);
+ TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain);
c.set_priority(10);
constraints.insert(c);
@@ -2628,16 +1252,16 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
- c = TerrainConstraint(this, coords, bit, p_terrain);
+ c = TerrainConstraint(tile_map_node, coords, bit, p_terrain);
c.set_priority(10);
if ((int(bit) % 2) == 0) {
- // Side peering bits: add the constraint if the center is of the same terrain
- Vector2i neighbor = get_neighbor_cell(coords, bit);
+ // Side peering bits: add the constraint if the center is of the same terrain.
+ Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit);
if (cells_with_terrain_center_bit.has(neighbor)) {
constraints.insert(c);
}
} else {
- // Corner peering bits: add the constraint if all tiles on the constraint has the same center bit
+ // Corner peering bits: add the constraint if all tiles on the constraint has the same center bit.
HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits();
bool valid = true;
for (KeyValue<Vector2i, TileSet::CellNeighbor> kv : overlapping_terrain_bits) {
@@ -2655,54 +1279,55 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
}
// Fills in the constraint list from existing tiles.
- for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
return output;
}
-HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_layer, const Vector<Vector2i> &p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
HashMap<Vector2i, TileSet::TerrainsPattern> output;
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND_V(!tile_set.is_valid(), output);
ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output);
// Make sure the path is correct and build the peering bit list while doing it.
Vector<TileSet::CellNeighbor> neighbor_list;
- for (int i = 0; i < p_path.size() - 1; i++) {
- // Find the adequate neighbor
+ for (int i = 0; i < p_coords_array.size() - 1; i++) {
+ // Find the adequate neighbor.
TileSet::CellNeighbor found_bit = TileSet::CELL_NEIGHBOR_MAX;
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
- if (is_existing_neighbor(bit)) {
- if (get_neighbor_cell(p_path[i], bit) == p_path[i + 1]) {
+ if (tile_map_node->is_existing_neighbor(bit)) {
+ if (tile_map_node->get_neighbor_cell(p_coords_array[i], bit) == p_coords_array[i + 1]) {
found_bit = bit;
break;
}
}
}
- ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighboring tile of %s", p_path[i + 1], p_path[i]));
+ ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighboring tile of %s", p_coords_array[i + 1], p_coords_array[i]));
neighbor_list.push_back(found_bit);
}
- // Build list and set of tiles that can be modified (painted and their surroundings)
+ // Build list and set of tiles that can be modified (painted and their surroundings).
Vector<Vector2i> can_modify_list;
RBSet<Vector2i> can_modify_set;
RBSet<Vector2i> painted_set;
- for (int i = p_path.size() - 1; i >= 0; i--) {
- const Vector2i &coords = p_path[i];
+ for (int i = p_coords_array.size() - 1; i >= 0; i--) {
+ const Vector2i &coords = p_coords_array[i];
can_modify_list.push_back(coords);
can_modify_set.insert(coords);
painted_set.insert(coords);
}
- for (Vector2i coords : p_path) {
- // Find the adequate neighbor
+ for (Vector2i coords : p_coords_array) {
+ // Find the adequate neighbor.
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
- Vector2i neighbor = get_neighbor_cell(coords, bit);
+ Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit);
if (!can_modify_set.has(neighbor)) {
can_modify_list.push_back(neighbor);
can_modify_set.insert(neighbor);
@@ -2714,31 +1339,32 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
RBSet<TerrainConstraint> constraints;
// Add new constraints from the path drawn.
- for (Vector2i coords : p_path) {
- // Constraints on the center bit
- TerrainConstraint c = TerrainConstraint(this, coords, p_terrain);
+ for (Vector2i coords : p_coords_array) {
+ // Constraints on the center bit.
+ TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain);
c.set_priority(10);
constraints.insert(c);
}
- for (int i = 0; i < p_path.size() - 1; i++) {
+ for (int i = 0; i < p_coords_array.size() - 1; i++) {
// Constraints on the peering bits.
- TerrainConstraint c = TerrainConstraint(this, p_path[i], neighbor_list[i], p_terrain);
+ TerrainConstraint c = TerrainConstraint(tile_map_node, p_coords_array[i], neighbor_list[i], p_terrain);
c.set_priority(10);
constraints.insert(c);
}
// Fills in the constraint list from existing tiles.
- for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
return output;
}
-HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) {
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) {
HashMap<Vector2i, TileSet::TerrainsPattern> output;
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND_V(!tile_set.is_valid(), output);
ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output);
@@ -2753,11 +1379,11 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
painted_set.insert(coords);
}
for (Vector2i coords : p_coords_array) {
- // Find the adequate neighbor
+ // Find the adequate neighbor.
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
- Vector2i neighbor = get_neighbor_cell(coords, bit);
+ Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit);
if (!can_modify_set.has(neighbor)) {
can_modify_list.push_back(neighbor);
can_modify_set.insert(neighbor);
@@ -2771,7 +1397,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
// Add new constraints from the path drawn.
for (Vector2i coords : p_coords_array) {
- // Constraints on the center bit
+ // Constraints on the center bit.
RBSet<TerrainConstraint> added_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, p_terrains_pattern);
for (TerrainConstraint c : added_constraints) {
c.set_priority(10);
@@ -2780,18 +1406,628 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
}
// Fills in the constraint list from modified tiles border.
- for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
return output;
}
-void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords, bool p_use_proxies) const {
+ if (!tile_map.has(p_coords)) {
+ return TileMapCell();
+ } else {
+ TileMapCell c = tile_map.find(p_coords)->value;
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
+ if (p_use_proxies && tile_set.is_valid()) {
+ Array proxyed = tile_set->map_tile_proxy(c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ c.source_id = proxyed[0];
+ c.set_atlas_coords(proxyed[1]);
+ c.alternative_tile = proxyed[2];
+ }
+ return c;
+ }
+}
+
+int TileMapLayer::get_effective_quadrant_size() const {
+ // When using YSort, the quadrant size is reduced to 1 to have one CanvasItem per quadrant.
+ if (tile_map_node->is_y_sort_enabled() && is_y_sort_enabled()) {
+ return 1;
+ } else {
+ return tile_map_node->get_quadrant_size();
+ }
+}
+
+void TileMapLayer::set_tile_data(TileMapLayer::DataFormat p_format, const Vector<int> &p_data) {
+ ERR_FAIL_COND(p_format > TileMapLayer::FORMAT_3);
+
+ // Set data for a given tile from raw data.
+
+ int c = p_data.size();
+ const int *r = p_data.ptr();
+
+ int offset = (p_format >= TileMapLayer::FORMAT_2) ? 3 : 2;
+ ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %s. Expected modulo: %s", offset));
+
+ clear();
+
+#ifdef DISABLE_DEPRECATED
+ ERR_FAIL_COND_MSG(p_format != TileMapLayer::FORMAT_3, vformat("Cannot handle deprecated TileMap data format version %d. This Godot version was compiled with no support for deprecated data.", p_format));
+#endif
+
+ for (int i = 0; i < c; i += offset) {
+ const uint8_t *ptr = (const uint8_t *)&r[i];
+ uint8_t local[12];
+ for (int j = 0; j < ((p_format >= TileMapLayer::FORMAT_2) ? 12 : 8); j++) {
+ local[j] = ptr[j];
+ }
+
+#ifdef BIG_ENDIAN_ENABLED
+
+ SWAP(local[0], local[3]);
+ SWAP(local[1], local[2]);
+ SWAP(local[4], local[7]);
+ SWAP(local[5], local[6]);
+ //TODO: ask someone to check this...
+ if (FORMAT >= FORMAT_2) {
+ SWAP(local[8], local[11]);
+ SWAP(local[9], local[10]);
+ }
+#endif
+ // Extracts position in TileMap.
+ int16_t x = decode_uint16(&local[0]);
+ int16_t y = decode_uint16(&local[2]);
+
+ if (p_format == TileMapLayer::FORMAT_3) {
+ uint16_t source_id = decode_uint16(&local[4]);
+ uint16_t atlas_coords_x = decode_uint16(&local[6]);
+ uint16_t atlas_coords_y = decode_uint16(&local[8]);
+ uint16_t alternative_tile = decode_uint16(&local[10]);
+ set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile);
+ } else {
+#ifndef DISABLE_DEPRECATED
+ // Previous decated format.
+
+ uint32_t v = decode_uint32(&local[4]);
+ // Extract the transform flags that used to be in the tilemap.
+ bool flip_h = v & (1UL << 29);
+ bool flip_v = v & (1UL << 30);
+ bool transpose = v & (1UL << 31);
+ v &= (1UL << 29) - 1;
+
+ // Extract autotile/atlas coords.
+ int16_t coord_x = 0;
+ int16_t coord_y = 0;
+ if (p_format == TileMapLayer::FORMAT_2) {
+ coord_x = decode_uint16(&local[8]);
+ coord_y = decode_uint16(&local[10]);
+ }
+
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
+ if (tile_set.is_valid()) {
+ Array a = tile_set->compatibility_tilemap_map(v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose);
+ if (a.size() == 3) {
+ set_cell(Vector2i(x, y), a[0], a[1], a[2]);
+ } else {
+ ERR_PRINT(vformat("No valid tile in Tileset for: tile:%s coords:%s flip_h:%s flip_v:%s transpose:%s", v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose));
+ }
+ } else {
+ int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2);
+ set_cell(Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile);
+ }
+#endif
+ }
+ }
+}
+
+Vector<int> TileMapLayer::get_tile_data() const {
+ // Export tile data to raw format.
+ Vector<int> tile_data;
+ tile_data.resize(tile_map.size() * 3);
+ int *w = tile_data.ptrw();
+
+ // Save in highest format.
+
+ int idx = 0;
+ for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
+ uint8_t *ptr = (uint8_t *)&w[idx];
+ encode_uint16((int16_t)(E.key.x), &ptr[0]);
+ encode_uint16((int16_t)(E.key.y), &ptr[2]);
+ encode_uint16(E.value.source_id, &ptr[4]);
+ encode_uint16(E.value.coord_x, &ptr[6]);
+ encode_uint16(E.value.coord_y, &ptr[8]);
+ encode_uint16(E.value.alternative_tile, &ptr[10]);
+ idx += 3;
+ }
+
+ return tile_data;
+}
+
+void TileMapLayer::clear_instantiated_scenes() {
+ instantiated_scenes.clear();
+}
+
+void TileMapLayer::clear_internals() {
+ // Clear quadrants.
+ clear_instantiated_scenes();
+ while (quadrant_map.size()) {
+ _erase_quadrant(quadrant_map.begin());
+ }
+
+ // Clear the layers internals.
+ _rendering_cleanup();
+
+ // Clear the layers internal navigation maps.
+ _navigation_cleanup();
+
+ // Clear the dirty quadrants list.
+ while (dirty_quadrant_list.first()) {
+ dirty_quadrant_list.remove(dirty_quadrant_list.first());
+ }
+}
+
+void TileMapLayer::recreate_internals() {
+ // Make sure that _clear_internals() was called prior.
+ ERR_FAIL_COND_MSG(quadrant_map.size() > 0, "TileMap layer had a non-empty quadrant map.");
+
+ if (!enabled) {
+ return;
+ }
+
+ // Update the layer internals.
+ _rendering_update();
+
+ // Update the layer internal navigation maps.
+ _navigation_update();
+
+ // Recreate the quadrants.
+ for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
+ Vector2i qk = _coords_to_quadrant_coords(Vector2i(E.key.x, E.key.y));
+
+ HashMap<Vector2i, TileMapQuadrant>::Iterator Q = quadrant_map.find(qk);
+ if (!Q) {
+ Q = _create_quadrant(qk);
+ dirty_quadrant_list.add(&Q->value.dirty_list_element);
+ }
+
+ Vector2i pk = E.key;
+ Q->value.cells.insert(pk);
+
+ _make_quadrant_dirty(Q);
+ }
+
+ tile_map_node->queue_update_dirty_quadrants();
+}
+
+void TileMapLayer::notify_canvas_entered() {
+ // Rendering.
+ bool node_visible = tile_map_node->is_visible_in_tree();
+ for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : quadrant_map) {
+ TileMapQuadrant &q = E_quadrant.value;
+ for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
+ Transform2D xform;
+ xform.set_origin(tile_map_node->map_to_local(kv.key));
+ RS::get_singleton()->canvas_light_occluder_attach_to_canvas(kv.value, tile_map_node->get_canvas());
+ RS::get_singleton()->canvas_light_occluder_set_transform(kv.value, tile_map_node->get_global_transform() * xform);
+ RS::get_singleton()->canvas_light_occluder_set_enabled(kv.value, node_visible);
+ }
+ }
+}
+
+void TileMapLayer::notify_visibility_changed() {
+ bool node_visible = tile_map_node->is_visible_in_tree();
+ for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : quadrant_map) {
+ TileMapQuadrant &q = E_quadrant.value;
+
+ // Update occluders transform.
+ for (const KeyValue<Vector2, Vector2i> &E_cell : q.local_to_map) {
+ Transform2D xform;
+ xform.set_origin(E_cell.key);
+ for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
+ RS::get_singleton()->canvas_light_occluder_set_enabled(kv.value, node_visible);
+ }
+ }
+ }
+}
+
+void TileMapLayer::notify_xform_changed() {
+ if (!tile_map_node->is_inside_tree()) {
+ return;
+ }
+
+ bool in_editor = false;
+#ifdef TOOLS_ENABLED
+ in_editor = Engine::get_singleton()->is_editor_hint();
+#endif
+
+ Transform2D tilemap_xform = tile_map_node->get_global_transform();
+ for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : quadrant_map) {
+ TileMapQuadrant &q = E_quadrant.value;
+
+ // Update occluders transform.
+ for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
+ Transform2D xform;
+ xform.set_origin(tile_map_node->map_to_local(kv.key));
+ RenderingServer::get_singleton()->canvas_light_occluder_set_transform(kv.value, tilemap_xform * xform);
+ }
+
+ // Update navigation regions transform.
+ for (const KeyValue<Vector2i, Vector<RID>> &E_region : q.navigation_regions) {
+ for (const RID &region : E_region.value) {
+ if (!region.is_valid()) {
+ continue;
+ }
+ Transform2D tile_transform;
+ tile_transform.set_origin(tile_map_node->map_to_local(E_region.key));
+ NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
+ }
+ }
+
+ // Physics.
+ if (!tile_map_node->is_collision_animatable() || in_editor) {
+ for (RID body : q.bodies) {
+ Transform2D xform;
+ xform.set_origin(tile_map_node->map_to_local(bodies_coords[body]));
+ xform = tilemap_xform * xform;
+ PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
+ }
+ }
+ }
+}
+
+void TileMapLayer::notify_local_xform_changed() {
+ if (!tile_map_node->is_inside_tree()) {
+ return;
+ }
+
+ bool in_editor = false;
+#ifdef TOOLS_ENABLED
+ in_editor = Engine::get_singleton()->is_editor_hint();
+#endif
+ if (!tile_map_node->is_collision_animatable() || in_editor) {
+ Transform2D gl_transform = tile_map_node->get_global_transform();
+ for (KeyValue<Vector2i, TileMapQuadrant> &E : quadrant_map) {
+ TileMapQuadrant &q = E.value;
+
+ for (RID body : q.bodies) {
+ Transform2D xform;
+ xform.set_origin(tile_map_node->map_to_local(bodies_coords[body]));
+ xform = gl_transform * xform;
+ PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
+ }
+ }
+ }
+}
+
+void TileMapLayer::notify_canvas_exited() {
+ for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : quadrant_map) {
+ TileMapQuadrant &q = E_quadrant.value;
+ for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
+ RS::get_singleton()->canvas_light_occluder_attach_to_canvas(kv.value, RID());
+ }
+ }
+}
+
+void TileMapLayer::notify_selected_layer_changed() {
+ _rendering_update();
+}
+
+void TileMapLayer::notify_light_mask_changed() {
+ for (const KeyValue<Vector2i, TileMapQuadrant> &E : quadrant_map) {
+ for (const RID &ci : E.value.canvas_items) {
+ RenderingServer::get_singleton()->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
+ }
+ }
+ _rendering_update();
+}
+
+void TileMapLayer::notify_material_changed() {
+ for (KeyValue<Vector2i, TileMapQuadrant> &E : quadrant_map) {
+ TileMapQuadrant &q = E.value;
+ for (const RID &ci : q.canvas_items) {
+ RS::get_singleton()->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid());
+ }
+ }
+ _rendering_update();
+}
+
+void TileMapLayer::notify_use_parent_material_changed() {
+ notify_material_changed();
+}
+
+void TileMapLayer::notify_texture_filter_changed() {
+ for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = quadrant_map.begin(); F; ++F) {
+ TileMapQuadrant &q = F->value;
+ for (const RID &ci : q.canvas_items) {
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree()));
+ _make_quadrant_dirty(F);
+ }
+ }
+ _rendering_update();
+}
+
+void TileMapLayer::notify_texture_repeat_changed() {
+ for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = quadrant_map.begin(); F; ++F) {
+ TileMapQuadrant &q = F->value;
+ for (const RID &ci : q.canvas_items) {
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree()));
+ _make_quadrant_dirty(F);
+ }
+ }
+ _rendering_update();
+}
+
+void TileMapLayer::update_dirty_quadrants() {
+ // Update the coords cache.
+ for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
+ q->self()->map_to_local.clear();
+ q->self()->local_to_map.clear();
+ for (const Vector2i &E : q->self()->cells) {
+ Vector2i pk = E;
+ Vector2 pk_local_coords = tile_map_node->map_to_local(pk);
+ q->self()->map_to_local[pk] = pk_local_coords;
+ q->self()->local_to_map[pk_local_coords] = pk;
+ }
+ }
+
+ // Find TileData that need a runtime modification.
+ _build_runtime_update_tile_data(dirty_quadrant_list);
+
+ // Call the update_dirty_quadrant method on plugins.
+ _rendering_update_dirty_quadrants(dirty_quadrant_list);
+ _physics_update_dirty_quadrants(dirty_quadrant_list);
+ _navigation_update_dirty_quadrants(dirty_quadrant_list);
+ _scenes_update_dirty_quadrants(dirty_quadrant_list);
+
+ // Redraw the debug canvas_items.
+ RenderingServer *rs = RenderingServer::get_singleton();
+ for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
+ rs->canvas_item_clear(q->self()->debug_canvas_item);
+ Transform2D xform;
+ xform.set_origin(tile_map_node->map_to_local(q->self()->coords * get_effective_quadrant_size()));
+ rs->canvas_item_set_transform(q->self()->debug_canvas_item, xform);
+
+ _rendering_draw_quadrant_debug(q->self());
+ _physics_draw_quadrant_debug(q->self());
+ _navigation_draw_quadrant_debug(q->self());
+ _scenes_draw_quadrant_debug(q->self());
+ }
+
+ // Clear the list.
+ while (dirty_quadrant_list.first()) {
+ // Clear the runtime tile data.
+ for (const KeyValue<Vector2i, TileData *> &kv : dirty_quadrant_list.first()->self()->runtime_tile_data_cache) {
+ memdelete(kv.value);
+ }
+
+ dirty_quadrant_list.remove(dirty_quadrant_list.first());
+ }
+}
+
+void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
+ // Set the current cell tile (using integer position).
+ Vector2i pk(p_coords);
+ HashMap<Vector2i, TileMapCell>::Iterator E = tile_map.find(pk);
+
+ int source_id = p_source_id;
+ Vector2i atlas_coords = p_atlas_coords;
+ int alternative_tile = p_alternative_tile;
+
+ if ((source_id == TileSet::INVALID_SOURCE || atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE) &&
+ (source_id != TileSet::INVALID_SOURCE || atlas_coords != TileSetSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE)) {
+ source_id = TileSet::INVALID_SOURCE;
+ atlas_coords = TileSetSource::INVALID_ATLAS_COORDS;
+ alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ }
+
+ if (!E && source_id == TileSet::INVALID_SOURCE) {
+ return; // Nothing to do, the tile is already empty.
+ }
+
+ // Get the quadrant
+ Vector2i qk = _coords_to_quadrant_coords(pk);
+
+ HashMap<Vector2i, TileMapQuadrant>::Iterator Q = quadrant_map.find(qk);
+
+ if (source_id == TileSet::INVALID_SOURCE) {
+ // Erase existing cell in the tile map.
+ tile_map.erase(pk);
+
+ // Erase existing cell in the quadrant.
+ ERR_FAIL_COND(!Q);
+ TileMapQuadrant &q = Q->value;
+
+ q.cells.erase(pk);
+
+ // Remove or make the quadrant dirty.
+ if (q.cells.size() == 0) {
+ _erase_quadrant(Q);
+ } else {
+ _make_quadrant_dirty(Q);
+ }
+
+ used_rect_cache_dirty = true;
+ } else {
+ if (!E) {
+ // Insert a new cell in the tile map.
+ E = tile_map.insert(pk, TileMapCell());
+
+ // Create a new quadrant if needed, then insert the cell if needed.
+ if (!Q) {
+ Q = _create_quadrant(qk);
+ }
+ TileMapQuadrant &q = Q->value;
+ q.cells.insert(pk);
+
+ } else {
+ ERR_FAIL_COND(!Q); // TileMapQuadrant should exist...
+
+ if (E->value.source_id == source_id && E->value.get_atlas_coords() == atlas_coords && E->value.alternative_tile == alternative_tile) {
+ return; // Nothing changed.
+ }
+ }
+
+ TileMapCell &c = E->value;
+
+ c.source_id = source_id;
+ c.set_atlas_coords(atlas_coords);
+ c.alternative_tile = alternative_tile;
+
+ _make_quadrant_dirty(Q);
+ used_rect_cache_dirty = true;
+ }
+}
+
+void TileMapLayer::erase_cell(const Vector2i &p_coords) {
+ set_cell(p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+}
+
+int TileMapLayer::get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies) const {
+ // Get a cell source id from position.
+ HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
+
+ if (!E) {
+ return TileSet::INVALID_SOURCE;
+ }
+
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
+ if (p_use_proxies && tile_set.is_valid()) {
+ Array proxyed = tile_set->map_tile_proxy(E->value.source_id, E->value.get_atlas_coords(), E->value.alternative_tile);
+ return proxyed[0];
+ }
+
+ return E->value.source_id;
+}
+
+Vector2i TileMapLayer::get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies) const {
+ // Get a cell source id from position.
+ HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
+
+ if (!E) {
+ return TileSetSource::INVALID_ATLAS_COORDS;
+ }
+
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
+ if (p_use_proxies && tile_set.is_valid()) {
+ Array proxyed = tile_set->map_tile_proxy(E->value.source_id, E->value.get_atlas_coords(), E->value.alternative_tile);
+ return proxyed[1];
+ }
+
+ return E->value.get_atlas_coords();
+}
+
+int TileMapLayer::get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies) const {
+ // Get a cell source id from position.
+ HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
+
+ if (!E) {
+ return TileSetSource::INVALID_TILE_ALTERNATIVE;
+ }
+
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
+ if (p_use_proxies && tile_set.is_valid()) {
+ Array proxyed = tile_set->map_tile_proxy(E->value.source_id, E->value.get_atlas_coords(), E->value.alternative_tile);
+ return proxyed[2];
+ }
+
+ return E->value.alternative_tile;
+}
+
+TileData *TileMapLayer::get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies) const {
+ int source_id = get_cell_source_id(p_coords, p_use_proxies);
+ if (source_id == TileSet::INVALID_SOURCE) {
+ return nullptr;
+ }
+
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
+ Ref<TileSetAtlasSource> source = tile_set->get_source(source_id);
+ if (source.is_valid()) {
+ return source->get_tile_data(get_cell_atlas_coords(p_coords, p_use_proxies), get_cell_alternative_tile(p_coords, p_use_proxies));
+ }
+
+ return nullptr;
+}
+
+void TileMapLayer::clear() {
+ // Remove all tiles.
+ clear_instantiated_scenes();
+ clear_internals();
+ tile_map.clear();
+ recreate_internals();
+ used_rect_cache_dirty = true;
+}
+
+Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_array) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
+ ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
+
+ Ref<TileMapPattern> output;
+ output.instantiate();
+ if (p_coords_array.is_empty()) {
+ return output;
+ }
+
+ Vector2i min = Vector2i(p_coords_array[0]);
+ for (int i = 1; i < p_coords_array.size(); i++) {
+ min = min.min(p_coords_array[i]);
+ }
+
+ Vector<Vector2i> coords_in_pattern_array;
+ coords_in_pattern_array.resize(p_coords_array.size());
+ Vector2i ensure_positive_offset;
+ for (int i = 0; i < p_coords_array.size(); i++) {
+ Vector2i coords = p_coords_array[i];
+ Vector2i coords_in_pattern = coords - min;
+ if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
+ if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
+ coords_in_pattern.x -= 1;
+ if (coords_in_pattern.x < 0) {
+ ensure_positive_offset.x = 1;
+ }
+ } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
+ coords_in_pattern.y -= 1;
+ if (coords_in_pattern.y < 0) {
+ ensure_positive_offset.y = 1;
+ }
+ }
+ } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
+ coords_in_pattern.x += 1;
+ } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
+ coords_in_pattern.y += 1;
+ }
+ }
+ }
+ coords_in_pattern_array.write[i] = coords_in_pattern;
+ }
+
+ for (int i = 0; i < coords_in_pattern_array.size(); i++) {
+ Vector2i coords = p_coords_array[i];
+ Vector2i coords_in_pattern = coords_in_pattern_array[i];
+ output->set_cell(coords_in_pattern + ensure_positive_offset, get_cell_source_id(coords), get_cell_atlas_coords(coords), get_cell_alternative_tile(coords));
+ }
+
+ return output;
+}
+
+void TileMapLayer::set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
+ ERR_FAIL_COND(tile_set.is_null());
+ ERR_FAIL_COND(p_pattern.is_null());
+
+ TypedArray<Vector2i> used_cells = p_pattern->get_used_cells();
+ for (int i = 0; i < used_cells.size(); i++) {
+ Vector2i coords = tile_map_node->map_pattern(p_position, used_cells[i], p_pattern);
+ set_cell(coords, p_pattern->get_cell_source_id(used_cells[i]), p_pattern->get_cell_atlas_coords(used_cells[i]), p_pattern->get_cell_alternative_tile(used_cells[i]));
+ }
+}
+
+void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
Vector<Vector2i> cells_vector;
@@ -2800,16 +2036,16 @@ void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cell
cells_vector.push_back(p_cells[i]);
painted_set.insert(p_cells[i]);
}
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains);
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
if (painted_set.has(kv.key)) {
// Paint a random tile with the correct terrain for the painted path.
TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
- set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
} else {
// Avoids updating the painted path from the output if the new pattern is the same as before.
TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
- TileMapCell cell = get_cell(p_layer, kv.key);
+ TileMapCell cell = get_cell(kv.key);
if (cell.source_id != TileSet::INVALID_SOURCE) {
TileSetSource *source = *tile_set->get_source(cell.source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
@@ -2823,15 +2059,15 @@ void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cell
}
if (in_map_terrain_pattern != kv.value) {
TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
- set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
}
}
}
}
-void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+void TileMapLayer::set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+ const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
ERR_FAIL_COND(!tile_set.is_valid());
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
Vector<Vector2i> vector_path;
@@ -2841,16 +2077,16 @@ void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, i
painted_set.insert(p_path[i]);
}
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(p_layer, vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains);
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
if (painted_set.has(kv.key)) {
// Paint a random tile with the correct terrain for the painted path.
TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
- set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
} else {
// Avoids updating the painted path from the output if the new pattern is the same as before.
TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
- TileMapCell cell = get_cell(p_layer, kv.key);
+ TileMapCell cell = get_cell(kv.key);
if (cell.source_id != TileSet::INVALID_SOURCE) {
TileSetSource *source = *tile_set->get_source(cell.source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
@@ -2864,246 +2100,1236 @@ void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, i
}
if (in_map_terrain_pattern != kv.value) {
TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
- set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
}
}
}
}
-TileMapCell TileMap::get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileMapCell());
- const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- if (!tile_map.has(p_coords)) {
- return TileMapCell();
- } else {
- TileMapCell c = tile_map.find(p_coords)->value;
- if (p_use_proxies && tile_set.is_valid()) {
- Array proxyed = tile_set->map_tile_proxy(c.source_id, c.get_atlas_coords(), c.alternative_tile);
- c.source_id = proxyed[0];
- c.set_atlas_coords(proxyed[1]);
- c.alternative_tile = proxyed[2];
- }
- return c;
+TypedArray<Vector2i> TileMapLayer::get_used_cells() const {
+ // Returns the cells used in the tilemap.
+ TypedArray<Vector2i> a;
+ a.resize(tile_map.size());
+ int i = 0;
+ for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
+ Vector2i p(E.key.x, E.key.y);
+ a[i++] = p;
}
-}
-HashMap<Vector2i, TileMapQuadrant> *TileMap::get_quadrant_map(int p_layer) {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
-
- return &layers[p_layer].quadrant_map;
+ return a;
}
-Vector2i TileMap::get_coords_for_body_rid(RID p_physics_body) {
- ERR_FAIL_COND_V_MSG(!bodies_coords.has(p_physics_body), Vector2i(), vformat("No tiles for the given body RID %d.", p_physics_body));
- return bodies_coords[p_physics_body];
-}
+TypedArray<Vector2i> TileMapLayer::get_used_cells_by_id(int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const {
+ // Returns the cells used in the tilemap.
+ TypedArray<Vector2i> a;
+ for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
+ if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == E.value.source_id) &&
+ (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == E.value.get_atlas_coords()) &&
+ (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == E.value.alternative_tile)) {
+ a.push_back(E.key);
+ }
+ }
-int TileMap::get_layer_for_body_rid(RID p_physics_body) {
- ERR_FAIL_COND_V_MSG(!bodies_layers.has(p_physics_body), int(), vformat("No tiles for the given body RID %d.", p_physics_body));
- return bodies_layers[p_physics_body];
+ return a;
}
-void TileMap::fix_invalid_tiles() {
- ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open.");
+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();
- for (unsigned int i = 0; i < layers.size(); i++) {
- const HashMap<Vector2i, TileMapCell> &tile_map = layers[i].tile_map;
- RBSet<Vector2i> coords;
- for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
- TileSetSource *source = *tile_set->get_source(E.value.source_id);
- if (!source || !source->has_tile(E.value.get_atlas_coords()) || !source->has_alternative_tile(E.value.get_atlas_coords(), E.value.alternative_tile)) {
- coords.insert(E.key);
+ 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;
+ }
+
+ for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
+ used_rect_cache.expand_to(Vector2i(E.key.x, E.key.y));
}
}
- for (const Vector2i &E : coords) {
- set_cell(i, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+
+ 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;
}
+
+ return used_rect_cache;
}
-void TileMap::clear_layer(int p_layer) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
+void TileMapLayer::set_name(String p_name) {
+ if (name == p_name) {
+ return;
+ }
+ name = p_name;
+ tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
+}
- // Remove all tiles.
- _clear_layer_internals(p_layer);
- layers[p_layer].tile_map.clear();
- _recreate_layer_internals(p_layer);
- used_rect_cache_dirty = true;
+String TileMapLayer::get_name() const {
+ return name;
}
-void TileMap::clear() {
- // Remove all tiles.
- _clear_internals();
- for (TileMapLayer &layer : layers) {
- layer.tile_map.clear();
+void TileMapLayer::set_enabled(bool p_enabled) {
+ if (enabled == p_enabled) {
+ return;
}
- _recreate_internals();
- used_rect_cache_dirty = true;
+ enabled = p_enabled;
+ clear_internals();
+ recreate_internals();
+ tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
+
+ tile_map_node->update_configuration_warnings();
}
-void TileMap::force_update(int p_layer) {
- if (p_layer >= 0) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
- _clear_layer_internals(p_layer);
- _recreate_layer_internals(p_layer);
- } else {
- _clear_internals();
- _recreate_internals();
+bool TileMapLayer::is_enabled() const {
+ return enabled;
+}
+
+void TileMapLayer::set_modulate(Color p_modulate) {
+ if (modulate == p_modulate) {
+ return;
}
+ modulate = p_modulate;
+ _rendering_update();
+ tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
}
-void TileMap::_set_tile_data(int p_layer, const Vector<int> &p_data) {
- ERR_FAIL_INDEX(p_layer, (int)layers.size());
- ERR_FAIL_COND(format > FORMAT_3);
+Color TileMapLayer::get_modulate() const {
+ return modulate;
+}
- // Set data for a given tile from raw data.
+void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) {
+ if (y_sort_enabled == p_y_sort_enabled) {
+ return;
+ }
+ y_sort_enabled = p_y_sort_enabled;
+ clear_internals();
+ recreate_internals();
+ tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
- int c = p_data.size();
- const int *r = p_data.ptr();
+ tile_map_node->update_configuration_warnings();
+}
- int offset = (format >= FORMAT_2) ? 3 : 2;
- ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %s. Expected modulo: %s", offset));
+bool TileMapLayer::is_y_sort_enabled() const {
+ return y_sort_enabled;
+}
- clear_layer(p_layer);
+void TileMapLayer::set_y_sort_origin(int p_y_sort_origin) {
+ if (y_sort_origin == p_y_sort_origin) {
+ return;
+ }
+ y_sort_origin = p_y_sort_origin;
+ clear_internals();
+ recreate_internals();
+ tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
+}
-#ifdef DISABLE_DEPRECATED
- ERR_FAIL_COND_MSG(format != FORMAT_3, vformat("Cannot handle deprecated TileMap data format version %d. This Godot version was compiled with no support for deprecated data.", format));
-#endif
+int TileMapLayer::get_y_sort_origin() const {
+ return y_sort_origin;
+}
- for (int i = 0; i < c; i += offset) {
- const uint8_t *ptr = (const uint8_t *)&r[i];
- uint8_t local[12];
- for (int j = 0; j < ((format >= FORMAT_2) ? 12 : 8); j++) {
- local[j] = ptr[j];
+void TileMapLayer::set_z_index(int p_z_index) {
+ if (z_index == p_z_index) {
+ return;
+ }
+ z_index = p_z_index;
+ _rendering_update();
+ tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
+
+ tile_map_node->update_configuration_warnings();
+}
+
+int TileMapLayer::get_z_index() const {
+ return z_index;
+}
+
+void TileMapLayer::set_navigation_map(RID p_map) {
+ ERR_FAIL_COND_MSG(!tile_map_node->is_inside_tree(), "A TileMap navigation map can only be changed while inside the SceneTree.");
+ navigation_map = p_map;
+ uses_world_navigation_map = p_map == tile_map_node->get_world_2d()->get_navigation_map();
+}
+
+RID TileMapLayer::get_navigation_map() const {
+ if (navigation_map.is_valid()) {
+ return navigation_map;
+ }
+ return RID();
+}
+
+void TileMapLayer::force_update() {
+ clear_internals();
+ recreate_internals();
+}
+
+void TileMapLayer::fix_invalid_tiles() {
+ Ref<TileSet> tileset = tile_map_node->get_tileset();
+ ERR_FAIL_COND_MSG(tileset.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet.");
+
+ RBSet<Vector2i> coords;
+ for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
+ TileSetSource *source = *tileset->get_source(E.value.source_id);
+ if (!source || !source->has_tile(E.value.get_atlas_coords()) || !source->has_alternative_tile(E.value.get_atlas_coords(), E.value.alternative_tile)) {
+ coords.insert(E.key);
}
+ }
+ for (const Vector2i &E : coords) {
+ set_cell(E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ }
+}
-#ifdef BIG_ENDIAN_ENABLED
+bool TileMapLayer::has_body_rid(RID p_physics_body) const {
+ return bodies_coords.has(p_physics_body);
+}
- SWAP(local[0], local[3]);
- SWAP(local[1], local[2]);
- SWAP(local[4], local[7]);
- SWAP(local[5], local[6]);
- //TODO: ask someone to check this...
- if (FORMAT >= FORMAT_2) {
- SWAP(local[8], local[11]);
- SWAP(local[9], local[10]);
+Vector2i TileMapLayer::get_coords_for_body_rid(RID p_physics_body) const {
+ return bodies_coords[p_physics_body];
+}
+
+HashMap<Vector2i, TileSet::CellNeighbor> TerrainConstraint::get_overlapping_coords_and_peering_bits() const {
+ HashMap<Vector2i, TileSet::CellNeighbor> output;
+
+ ERR_FAIL_COND_V(is_center_bit(), output);
+
+ Ref<TileSet> ts = tile_map->get_tileset();
+ ERR_FAIL_COND_V(!ts.is_valid(), output);
+
+ TileSet::TileShape shape = ts->get_tile_shape();
+ if (shape == TileSet::TILE_SHAPE_SQUARE) {
+ switch (bit) {
+ case 1:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
+ break;
+ case 2:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
+ break;
+ case 3:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
+ break;
+ default:
+ ERR_FAIL_V(output);
}
-#endif
- // Extracts position in TileMap.
- int16_t x = decode_uint16(&local[0]);
- int16_t y = decode_uint16(&local[2]);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ switch (bit) {
+ case 1:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
+ break;
+ case 2:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
+ break;
+ case 3:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
+ break;
+ default:
+ ERR_FAIL_V(output);
+ }
+ } else {
+ // Half offset shapes.
+ TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis();
+ if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ switch (bit) {
+ case 1:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
+ break;
+ case 2:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
+ break;
+ case 3:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
+ break;
+ case 4:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
+ break;
+ case 5:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
+ break;
+ default:
+ ERR_FAIL_V(output);
+ }
+ } else {
+ switch (bit) {
+ case 1:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
+ break;
+ case 2:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
+ break;
+ case 3:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
+ break;
+ case 4:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
+ break;
+ case 5:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
+ break;
+ default:
+ ERR_FAIL_V(output);
+ }
+ }
+ }
+ return output;
+}
- if (format == FORMAT_3) {
- uint16_t source_id = decode_uint16(&local[4]);
- uint16_t atlas_coords_x = decode_uint16(&local[6]);
- uint16_t atlas_coords_y = decode_uint16(&local[8]);
- uint16_t alternative_tile = decode_uint16(&local[10]);
- set_cell(p_layer, Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile);
+TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain) {
+ tile_map = p_tile_map;
+
+ Ref<TileSet> ts = tile_map->get_tileset();
+ ERR_FAIL_COND(!ts.is_valid());
+
+ bit = 0;
+ base_cell_coords = p_position;
+ terrain = p_terrain;
+}
+
+TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) {
+ // The way we build the constraint make it easy to detect conflicting constraints.
+ tile_map = p_tile_map;
+
+ Ref<TileSet> ts = tile_map->get_tileset();
+ ERR_FAIL_COND(!ts.is_valid());
+
+ TileSet::TileShape shape = ts->get_tile_shape();
+ if (shape == TileSet::TILE_SHAPE_SQUARE) {
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
+ bit = 1;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ bit = 2;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
+ bit = 3;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
+ bit = 1;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_SIDE:
+ bit = 3;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ break;
+ default:
+ ERR_FAIL();
+ break;
+ }
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ bit = 1;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
+ bit = 2;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ bit = 3;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ bit = 1;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_CORNER);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ bit = 3;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ break;
+ default:
+ ERR_FAIL();
+ break;
+ }
+ } else {
+ // Half-offset shapes.
+ TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis();
+ if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
+ bit = 1;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ bit = 2;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ bit = 3;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
+ bit = 4;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ bit = 5;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
+ bit = 1;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ bit = 4;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ bit = 3;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ bit = 5;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ bit = 4;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ break;
+ default:
+ ERR_FAIL();
+ break;
+ }
} else {
-#ifndef DISABLE_DEPRECATED
- // Previous decated format.
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
+ bit = 1;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ bit = 2;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ bit = 3;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
+ bit = 4;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ bit = 1;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ bit = 5;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
+ bit = 3;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ bit = 1;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_SIDE:
+ bit = 4;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ bit = 3;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ bit = 5;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ break;
+ default:
+ ERR_FAIL();
+ break;
+ }
+ }
+ }
+ terrain = p_terrain;
+}
- uint32_t v = decode_uint32(&local[4]);
- // Extract the transform flags that used to be in the tilemap.
- bool flip_h = v & (1UL << 29);
- bool flip_v = v & (1UL << 30);
- bool transpose = v & (1UL << 31);
- v &= (1UL << 29) - 1;
+#define TILEMAP_CALL_FOR_LAYER(layer, function, ...) \
+ if (layer < 0) { \
+ layer = layers.size() + layer; \
+ }; \
+ ERR_FAIL_INDEX(layer, (int)layers.size()); \
+ layers[layer]->function(__VA_ARGS__);
- // Extract autotile/atlas coords.
- int16_t coord_x = 0;
- int16_t coord_y = 0;
- if (format == FORMAT_2) {
- coord_x = decode_uint16(&local[8]);
- coord_y = decode_uint16(&local[10]);
+#define TILEMAP_CALL_FOR_LAYER_V(layer, err_value, function, ...) \
+ if (layer < 0) { \
+ layer = layers.size() + layer; \
+ }; \
+ ERR_FAIL_INDEX_V(layer, (int)layers.size(), err_value); \
+ return layers[layer]->function(__VA_ARGS__);
+
+Vector2i TileMap::transform_coords_layout(const Vector2i &p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) {
+ // Transform to stacked layout.
+ Vector2i output = p_coords;
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
+ SWAP(output.x, output.y);
+ }
+ switch (p_from_layout) {
+ case TileSet::TILE_LAYOUT_STACKED:
+ break;
+ case TileSet::TILE_LAYOUT_STACKED_OFFSET:
+ if (output.y % 2) {
+ output.x -= 1;
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
+ case TileSet::TILE_LAYOUT_STAIRS_DOWN:
+ if ((p_from_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if (output.y < 0 && bool(output.y % 2)) {
+ output = Vector2i(output.x + output.y / 2 - 1, output.y);
+ } else {
+ output = Vector2i(output.x + output.y / 2, output.y);
+ }
+ } else {
+ if (output.x < 0 && bool(output.x % 2)) {
+ output = Vector2i(output.x / 2 - 1, output.x + output.y * 2);
+ } else {
+ output = Vector2i(output.x / 2, output.x + output.y * 2);
+ }
+ }
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
+ case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
+ if ((p_from_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if ((output.x + output.y) < 0 && (output.x - output.y) % 2) {
+ output = Vector2i((output.x + output.y) / 2 - 1, output.y - output.x);
+ } else {
+ output = Vector2i((output.x + output.y) / 2, -output.x + output.y);
+ }
+ } else {
+ if ((output.x - output.y) < 0 && (output.x + output.y) % 2) {
+ output = Vector2i((output.x - output.y) / 2 - 1, output.x + output.y);
+ } else {
+ output = Vector2i((output.x - output.y) / 2, output.x + output.y);
+ }
}
+ break;
+ }
- if (tile_set.is_valid()) {
- Array a = tile_set->compatibility_tilemap_map(v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose);
- if (a.size() == 3) {
- set_cell(p_layer, Vector2i(x, y), a[0], a[1], a[2]);
+ switch (p_to_layout) {
+ case TileSet::TILE_LAYOUT_STACKED:
+ break;
+ case TileSet::TILE_LAYOUT_STACKED_OFFSET:
+ if (output.y % 2) {
+ output.x += 1;
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
+ case TileSet::TILE_LAYOUT_STAIRS_DOWN:
+ if ((p_to_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if (output.y < 0 && (output.y % 2)) {
+ output = Vector2i(output.x - output.y / 2 + 1, output.y);
} else {
- ERR_PRINT(vformat("No valid tile in Tileset for: tile:%s coords:%s flip_h:%s flip_v:%s transpose:%s", v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose));
+ output = Vector2i(output.x - output.y / 2, output.y);
}
} else {
- int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2);
- set_cell(p_layer, Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile);
+ if (output.y % 2) {
+ if (output.y < 0) {
+ output = Vector2i(2 * output.x + 1, -output.x + output.y / 2 - 1);
+ } else {
+ output = Vector2i(2 * output.x + 1, -output.x + output.y / 2);
+ }
+ } else {
+ output = Vector2i(2 * output.x, -output.x + output.y / 2);
+ }
}
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
+ case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
+ if ((p_to_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if (output.y % 2) {
+ if (output.y > 0) {
+ output = Vector2i(output.x - output.y / 2, output.x + output.y / 2 + 1);
+ } else {
+ output = Vector2i(output.x - output.y / 2 + 1, output.x + output.y / 2);
+ }
+ } else {
+ output = Vector2i(output.x - output.y / 2, output.x + output.y / 2);
+ }
+ } else {
+ if (output.y % 2) {
+ if (output.y < 0) {
+ output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2 - 1);
+ } else {
+ output = Vector2i(output.x + output.y / 2 + 1, -output.x + output.y / 2);
+ }
+ } else {
+ output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2);
+ }
+ }
+ break;
+ }
+
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
+ SWAP(output.x, output.y);
+ }
+
+ return output;
+}
+
+void TileMap::set_selected_layer(int p_layer_id) {
+ ERR_FAIL_COND(p_layer_id < -1 || p_layer_id >= (int)layers.size());
+ selected_layer = p_layer_id;
+ emit_signal(CoreStringNames::get_singleton()->changed);
+
+ // Update the layers modulation.
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_selected_layer_changed();
+ }
+}
+
+int TileMap::get_selected_layer() const {
+ return selected_layer;
+}
+
+void TileMap::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _clear_internals();
+ _recreate_internals();
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ _clear_internals();
+ } break;
+ }
+
+ // Transfers the notification to tileset plugins.
+ if (tile_set.is_valid()) {
+ switch (p_what) {
+ case TileMap::NOTIFICATION_ENTER_CANVAS: {
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_canvas_entered();
+ }
+ } break;
+
+ case TileMap::NOTIFICATION_EXIT_CANVAS: {
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_canvas_exited();
+ }
+ } break;
+
+ case NOTIFICATION_DRAW: {
+ // Rendering.
+ if (tile_set.is_valid()) {
+ RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), is_y_sort_enabled());
+ }
+ } break;
+
+ case TileMap::NOTIFICATION_VISIBILITY_CHANGED: {
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_visibility_changed();
+ }
+ } break;
+
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ // Physics.
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_xform_changed();
+ }
+ } break;
+
+ case TileMap::NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+ // Physics.
+ bool in_editor = false;
+#ifdef TOOLS_ENABLED
+ in_editor = Engine::get_singleton()->is_editor_hint();
#endif
+ if (is_inside_tree() && collision_animatable && !in_editor) {
+ // Update transform on the physics tick when in animatable mode.
+ last_valid_transform = new_transform;
+ set_notify_local_transform(false);
+ set_global_transform(new_transform);
+ set_notify_local_transform(true);
+ }
+ } break;
+
+ case TileMap::NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_local_xform_changed();
+ }
+
+ // Physics.
+ bool in_editor = false;
+#ifdef TOOLS_ENABLED
+ in_editor = Engine::get_singleton()->is_editor_hint();
+#endif
+
+ // Only active when animatable. Send the new transform to the physics...
+ if (is_inside_tree() && !in_editor && collision_animatable) {
+ // ... but then revert changes.
+ set_notify_local_transform(false);
+ set_global_transform(last_valid_transform);
+ set_notify_local_transform(true);
+ }
+ } break;
}
}
- emit_signal(SNAME("changed"));
}
-Vector<int> TileMap::_get_tile_data(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), Vector<int>());
+void TileMap::queue_update_dirty_quadrants() {
+ if (pending_update || !is_inside_tree()) {
+ return;
+ }
+ pending_update = true;
+ call_deferred(SNAME("_update_dirty_quadrants"));
+}
- // Export tile data to raw format
- const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- Vector<int> tile_data;
- tile_data.resize(tile_map.size() * 3);
- int *w = tile_data.ptrw();
+void TileMap::_update_dirty_quadrants() {
+ if (!pending_update) {
+ return;
+ }
- // Save in highest format
+ if (!is_inside_tree() || !tile_set.is_valid()) {
+ pending_update = false;
+ return;
+ }
- int idx = 0;
- for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
- uint8_t *ptr = (uint8_t *)&w[idx];
- encode_uint16((int16_t)(E.key.x), &ptr[0]);
- encode_uint16((int16_t)(E.key.y), &ptr[2]);
- encode_uint16(E.value.source_id, &ptr[4]);
- encode_uint16(E.value.coord_x, &ptr[6]);
- encode_uint16(E.value.coord_y, &ptr[8]);
- encode_uint16(E.value.alternative_tile, &ptr[10]);
- idx += 3;
+ // Physics:
+ Transform2D gl_transform = get_global_transform();
+ last_valid_transform = gl_transform;
+ new_transform = gl_transform;
+
+ // Update dirty quadrants on layers.
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->update_dirty_quadrants();
}
- return tile_data;
+ pending_update = false;
+}
+
+void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
+ if (p_tileset == tile_set) {
+ return;
+ }
+
+ // Set the tileset, registering to its changes.
+ if (tile_set.is_valid()) {
+ tile_set->disconnect_changed(callable_mp(this, &TileMap::_tile_set_changed));
+ }
+
+ if (!p_tileset.is_valid()) {
+ _clear_internals();
+ }
+
+ tile_set = p_tileset;
+
+ if (tile_set.is_valid()) {
+ tile_set->connect_changed(callable_mp(this, &TileMap::_tile_set_changed));
+ _clear_internals();
+ _recreate_internals();
+ }
+
+ emit_signal(CoreStringNames::get_singleton()->changed);
}
-void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
- if (GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) {
- SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
- while (q_list_element) {
- TileMapQuadrant &q = *q_list_element->self();
- // Iterate over the cells of the quadrant.
- for (const KeyValue<Vector2, Vector2i> &E_cell : q.local_to_map) {
- TileMapCell c = get_cell(q.layer, E_cell.value, true);
+Ref<TileSet> TileMap::get_tileset() const {
+ return tile_set;
+}
- TileSetSource *source;
- if (tile_set->has_source(c.source_id)) {
- source = *tile_set->get_source(c.source_id);
+void TileMap::set_quadrant_size(int p_size) {
+ ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1.");
- if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
- continue;
- }
+ quadrant_size = p_size;
+ _clear_internals();
+ _recreate_internals();
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
- if (atlas_source) {
- bool ret = false;
- if (GDVIRTUAL_CALL(_use_tile_data_runtime_update, q.layer, E_cell.value, ret) && ret) {
- TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
+int TileMap::get_quadrant_size() const {
+ return quadrant_size;
+}
- // Create the runtime TileData.
- TileData *tile_data_runtime_use = tile_data->duplicate();
- tile_data_runtime_use->set_allow_transform(true);
- q.runtime_tile_data_cache[E_cell.value] = tile_data_runtime_use;
+void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation, const TileData *p_tile_data_override, real_t p_animation_offset) {
+ ERR_FAIL_COND(!p_tile_set.is_valid());
+ ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
+ ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
+ ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile));
+ TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Check for the frame.
+ if (p_frame >= 0) {
+ ERR_FAIL_INDEX(p_frame, atlas_source->get_tile_animation_frames_count(p_atlas_coords));
+ }
- GDVIRTUAL_CALL(_tile_data_runtime_update, q.layer, E_cell.value, tile_data_runtime_use);
- }
- }
- }
+ // Get the texture.
+ Ref<Texture2D> tex = atlas_source->get_runtime_texture();
+ if (!tex.is_valid()) {
+ return;
+ }
+
+ // Check if we are in the texture, return otherwise.
+ Vector2i grid_size = atlas_source->get_atlas_grid_size();
+ if (p_atlas_coords.x >= grid_size.x || p_atlas_coords.y >= grid_size.y) {
+ return;
+ }
+
+ // Get tile data.
+ const TileData *tile_data = p_tile_data_override ? p_tile_data_override : atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile);
+
+ // Get the tile modulation.
+ Color modulate = tile_data->get_modulate() * p_modulation;
+
+ // Compute the offset.
+ Vector2 tile_offset = tile_data->get_texture_origin();
+
+ // Get destination rect.
+ Rect2 dest_rect;
+ dest_rect.size = atlas_source->get_runtime_tile_texture_region(p_atlas_coords).size;
+ dest_rect.size.x += FP_ADJUST;
+ dest_rect.size.y += FP_ADJUST;
+
+ bool transpose = tile_data->get_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()) {
+ dest_rect.size.x = -dest_rect.size.x;
+ }
+
+ if (tile_data->get_flip_v()) {
+ dest_rect.size.y = -dest_rect.size.y;
+ }
+
+ // Draw the tile.
+ if (p_frame >= 0) {
+ Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, p_frame);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ } else if (atlas_source->get_tile_animation_frames_count(p_atlas_coords) == 1) {
+ Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, 0);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ } else {
+ real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords);
+ real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed;
+ real_t time = 0.0;
+ for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) {
+ real_t frame_duration = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame) / speed;
+ RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, time, time + frame_duration, p_animation_offset);
+
+ Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, frame);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+
+ time += frame_duration;
}
- q_list_element = q_list_element->next();
+ RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0);
}
}
}
+int TileMap::get_layers_count() const {
+ return layers.size();
+}
+
+void TileMap::add_layer(int p_to_pos) {
+ if (p_to_pos < 0) {
+ p_to_pos = layers.size() + p_to_pos + 1;
+ }
+
+ ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
+
+ // Must clear before adding the layer.
+ _clear_internals();
+ Ref<TileMapLayer> new_layer;
+ new_layer.instantiate();
+ new_layer->set_tile_map(this);
+ layers.insert(p_to_pos, new_layer);
+ for (unsigned int i = 0; i < layers.size(); i++) {
+ layers[i]->set_layer_index_in_tile_map_node(i);
+ }
+ _recreate_internals();
+ notify_property_list_changed();
+
+ emit_signal(CoreStringNames::get_singleton()->changed);
+
+ update_configuration_warnings();
+}
+
+void TileMap::move_layer(int p_layer, int p_to_pos) {
+ ERR_FAIL_INDEX(p_layer, (int)layers.size());
+ ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
+
+ // Clear before shuffling layers.
+ _clear_internals();
+ Ref<TileMapLayer> layer = layers[p_layer];
+ layers.insert(p_to_pos, layer);
+ layers.remove_at(p_to_pos < p_layer ? p_layer + 1 : p_layer);
+ for (unsigned int i = 0; i < layers.size(); i++) {
+ layers[i]->set_layer_index_in_tile_map_node(i);
+ }
+ _recreate_internals();
+ notify_property_list_changed();
+
+ if (selected_layer == p_layer) {
+ selected_layer = p_to_pos < p_layer ? p_to_pos - 1 : p_to_pos;
+ }
+
+ emit_signal(CoreStringNames::get_singleton()->changed);
+
+ update_configuration_warnings();
+}
+
+void TileMap::remove_layer(int p_layer) {
+ ERR_FAIL_INDEX(p_layer, (int)layers.size());
+
+ // Clear before removing the layer.
+ _clear_internals();
+ layers.remove_at(p_layer);
+ for (unsigned int i = 0; i < layers.size(); i++) {
+ layers[i]->set_layer_index_in_tile_map_node(i);
+ }
+ _recreate_internals();
+ notify_property_list_changed();
+
+ if (selected_layer >= p_layer) {
+ selected_layer -= 1;
+ }
+
+ emit_signal(CoreStringNames::get_singleton()->changed);
+
+ update_configuration_warnings();
+}
+
+void TileMap::set_layer_name(int p_layer, String p_name) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_name, p_name);
+}
+
+String TileMap::get_layer_name(int p_layer) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, "", get_name);
+}
+
+void TileMap::set_layer_enabled(int p_layer, bool p_enabled) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_enabled, p_enabled);
+}
+
+bool TileMap::is_layer_enabled(int p_layer) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, false, is_enabled);
+}
+
+void TileMap::set_layer_modulate(int p_layer, Color p_modulate) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_modulate, p_modulate);
+}
+
+Color TileMap::get_layer_modulate(int p_layer) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, Color(), get_modulate);
+}
+
+void TileMap::set_layer_y_sort_enabled(int p_layer, bool p_y_sort_enabled) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_y_sort_enabled, p_y_sort_enabled);
+}
+
+bool TileMap::is_layer_y_sort_enabled(int p_layer) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, false, is_y_sort_enabled);
+}
+
+void TileMap::set_layer_y_sort_origin(int p_layer, int p_y_sort_origin) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_y_sort_origin, p_y_sort_origin);
+}
+
+int TileMap::get_layer_y_sort_origin(int p_layer) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, 0, get_y_sort_origin);
+}
+
+void TileMap::set_layer_z_index(int p_layer, int p_z_index) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_z_index, p_z_index);
+}
+
+int TileMap::get_layer_z_index(int p_layer) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, 0, get_z_index);
+}
+
+void TileMap::set_layer_navigation_map(int p_layer, RID p_map) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_navigation_map, p_map);
+}
+
+RID TileMap::get_layer_navigation_map(int p_layer) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, RID(), get_navigation_map);
+}
+
+void TileMap::set_collision_animatable(bool p_enabled) {
+ if (collision_animatable == p_enabled) {
+ return;
+ }
+ collision_animatable = p_enabled;
+ _clear_internals();
+ set_notify_local_transform(p_enabled);
+ set_physics_process_internal(p_enabled);
+ _recreate_internals();
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+bool TileMap::is_collision_animatable() const {
+ return collision_animatable;
+}
+
+void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_collision) {
+ if (collision_visibility_mode == p_show_collision) {
+ return;
+ }
+ collision_visibility_mode = p_show_collision;
+ _clear_internals();
+ _recreate_internals();
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+TileMap::VisibilityMode TileMap::get_collision_visibility_mode() {
+ return collision_visibility_mode;
+}
+
+void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navigation) {
+ if (navigation_visibility_mode == p_show_navigation) {
+ return;
+ }
+ navigation_visibility_mode = p_show_navigation;
+ _clear_internals();
+ _recreate_internals();
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() {
+ return navigation_visibility_mode;
+}
+
+void TileMap::set_y_sort_enabled(bool p_enable) {
+ if (is_y_sort_enabled() == p_enable) {
+ return;
+ }
+ Node2D::set_y_sort_enabled(p_enable);
+ _clear_internals();
+ _recreate_internals();
+ emit_signal(CoreStringNames::get_singleton()->changed);
+ update_configuration_warnings();
+}
+
+void TileMap::_clear_internals() {
+ // Clear quadrants.
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->clear_internals();
+ }
+}
+
+void TileMap::_recreate_internals() {
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->recreate_internals();
+ }
+}
+
+/////////////////////////////// Rendering //////////////////////////////////////
+
+void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_cell, p_coords, p_source_id, p_atlas_coords, p_alternative_tile);
+}
+
+void TileMap::erase_cell(int p_layer, const Vector2i &p_coords) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_cell, p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+}
+
+int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSet::INVALID_SOURCE, get_cell_source_id, p_coords, p_use_proxies);
+}
+
+Vector2i TileMap::get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_ATLAS_COORDS, get_cell_atlas_coords, p_coords, p_use_proxies);
+}
+
+int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_TILE_ALTERNATIVE, get_cell_alternative_tile, p_coords, p_use_proxies);
+}
+
+TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, nullptr, get_cell_tile_data, p_coords, p_use_proxies);
+}
+
+Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, Ref<TileMapPattern>(), get_pattern, p_coords_array);
+}
+
+Vector2i TileMap::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) {
+ ERR_FAIL_COND_V(p_pattern.is_null(), Vector2i());
+ ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i());
+
+ Vector2i output = p_position_in_tilemap + p_coords_in_pattern;
+ if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
+ if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
+ output.x += 1;
+ } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
+ output.y += 1;
+ }
+ } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
+ output.x -= 1;
+ } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
+ output.y -= 1;
+ }
+ }
+ }
+
+ return output;
+}
+
+void TileMap::set_pattern(int p_layer, const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_pattern, p_position, p_pattern);
+}
+
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) {
+ HashMap<Vector2i, TileSet::TerrainsPattern> err_value;
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, err_value, terrain_fill_constraints, p_to_replace, p_terrain_set, p_constraints);
+}
+
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+ HashMap<Vector2i, TileSet::TerrainsPattern> err_value;
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, err_value, terrain_fill_connect, p_coords_array, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+}
+
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+ HashMap<Vector2i, TileSet::TerrainsPattern> err_value;
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, err_value, terrain_fill_path, p_coords_array, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+}
+
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) {
+ HashMap<Vector2i, TileSet::TerrainsPattern> err_value;
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, err_value, terrain_fill_pattern, p_coords_array, p_terrain_set, p_terrains_pattern, p_ignore_empty_terrains);
+}
+
+void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_cells_terrain_connect, p_cells, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+}
+
+void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, set_cells_terrain_path, p_path, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+}
+
+TileMapCell TileMap::get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, TileMapCell(), get_cell, p_coords, p_use_proxies);
+}
+
+Vector2i TileMap::get_coords_for_body_rid(RID p_physics_body) {
+ for (const Ref<TileMapLayer> &layer : layers) {
+ if (layer->has_body_rid(p_physics_body)) {
+ return layer->get_coords_for_body_rid(p_physics_body);
+ }
+ }
+ ERR_FAIL_V_MSG(Vector2i(), vformat("No tiles for the given body RID %d.", p_physics_body));
+}
+
+int TileMap::get_layer_for_body_rid(RID p_physics_body) {
+ for (unsigned int i = 0; i < layers.size(); i++) {
+ if (layers[i]->has_body_rid(p_physics_body)) {
+ return i;
+ }
+ }
+ ERR_FAIL_V_MSG(-1, vformat("No tiles for the given body RID %d.", p_physics_body));
+}
+
+void TileMap::fix_invalid_tiles() {
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->fix_invalid_tiles();
+ }
+}
+
+void TileMap::clear_layer(int p_layer) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, clear)
+}
+
+void TileMap::clear() {
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->clear();
+ }
+}
+
+void TileMap::force_update(int p_layer) {
+ if (p_layer >= 0) {
+ TILEMAP_CALL_FOR_LAYER(p_layer, force_update);
+ } else {
+ _clear_internals();
+ _recreate_internals();
+ }
+}
+
#ifdef TOOLS_ENABLED
Rect2 TileMap::_edit_get_rect() const {
- // Return the visible rect of the tilemap
- const_cast<TileMap *>(this)->_recompute_rect_cache();
- return rect_cache;
+ // Return the visible rect of the tilemap.
+ if (layers.is_empty()) {
+ return Rect2();
+ }
+
+ bool any_changed = false;
+ bool changed = false;
+ Rect2 rect = layers[0]->get_rect(changed);
+ any_changed |= changed;
+ for (unsigned int i = 1; i < layers.size(); i++) {
+ rect = rect.merge(layers[i]->get_rect(changed));
+ any_changed |= changed;
+ }
+ const_cast<TileMap *>(this)->item_rect_changed(any_changed);
+ return rect;
}
#endif
@@ -3111,15 +3337,20 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
Vector<String> components = String(p_name).split("/", true, 2);
if (p_name == "format") {
if (p_value.get_type() == Variant::INT) {
- format = (DataFormat)(p_value.operator int64_t()); // Set format used for loading
+ format = (TileMapLayer::DataFormat)(p_value.operator int64_t()); // Set format used for loading.
return true;
}
} else if (p_name == "tile_data") { // Kept for compatibility reasons.
if (p_value.is_array()) {
- if (layers.size() < 1) {
- layers.resize(1);
+ if (layers.size() == 0) {
+ Ref<TileMapLayer> new_layer;
+ new_layer.instantiate();
+ new_layer->set_tile_map(this);
+ new_layer->set_layer_index_in_tile_map_node(0);
+ layers.push_back(new_layer);
}
- _set_tile_data(0, p_value);
+ layers[0]->set_tile_data(format, p_value);
+ emit_signal(CoreStringNames::get_singleton()->changed);
return true;
}
return false;
@@ -3132,12 +3363,16 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
if (index >= (int)layers.size()) {
_clear_internals();
while (index >= (int)layers.size()) {
- layers.push_back(TileMapLayer());
+ Ref<TileMapLayer> new_layer;
+ new_layer.instantiate();
+ new_layer->set_tile_map(this);
+ new_layer->set_layer_index_in_tile_map_node(index);
+ layers.push_back(new_layer);
}
_recreate_internals();
notify_property_list_changed();
- emit_signal(SNAME("changed"));
+ emit_signal(CoreStringNames::get_singleton()->changed);
update_configuration_warnings();
}
@@ -3160,7 +3395,8 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
set_layer_z_index(index, p_value);
return true;
} else if (components[1] == "tile_data") {
- _set_tile_data(index, p_value);
+ layers[index]->set_tile_data(format, p_value);
+ emit_signal(CoreStringNames::get_singleton()->changed);
return true;
} else {
return false;
@@ -3172,7 +3408,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
bool TileMap::_get(const StringName &p_name, Variant &r_ret) const {
Vector<String> components = String(p_name).split("/", true, 2);
if (p_name == "format") {
- r_ret = FORMAT_3; // When saving, always save highest format
+ r_ret = TileMapLayer::FORMAT_MAX - 1; // When saving, always save highest format.
return true;
} else if (components.size() == 2 && components[0].begins_with("layer_") && components[0].trim_prefix("layer_").is_valid_int()) {
int index = components[0].trim_prefix("layer_").to_int();
@@ -3199,7 +3435,7 @@ bool TileMap::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = get_layer_z_index(index);
return true;
} else if (components[1] == "tile_data") {
- r_ret = _get_tile_data(index);
+ r_ret = layers[index]->get_tile_data();
return true;
} else {
return false;
@@ -3223,7 +3459,7 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const {
}
Vector2 TileMap::map_to_local(const Vector2i &p_pos) const {
- // SHOULD RETURN THE CENTER OF THE CELL
+ // SHOULD RETURN THE CENTER OF THE CELL.
ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2());
Vector2 ret = p_pos;
@@ -3232,7 +3468,7 @@ Vector2 TileMap::map_to_local(const Vector2i &p_pos) const {
if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
// Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
- // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap
+ // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap.
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
switch (tile_set->get_tile_layout()) {
case TileSet::TILE_LAYOUT_STACKED:
@@ -3254,7 +3490,7 @@ Vector2 TileMap::map_to_local(const Vector2i &p_pos) const {
ret = Vector2((ret.x - ret.y) / 2, ret.y + ret.x);
break;
}
- } else { // TILE_OFFSET_AXIS_VERTICAL
+ } else { // TILE_OFFSET_AXIS_VERTICAL.
switch (tile_set->get_tile_layout()) {
case TileSet::TILE_LAYOUT_STACKED:
ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 0 ? 0.0 : 0.5));
@@ -3278,7 +3514,7 @@ Vector2 TileMap::map_to_local(const Vector2i &p_pos) const {
}
}
- // Multiply by the overlapping ratio
+ // Multiply by the overlapping ratio.
double overlapping_ratio = 1.0;
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
@@ -3287,7 +3523,7 @@ Vector2 TileMap::map_to_local(const Vector2i &p_pos) const {
overlapping_ratio = 0.75;
}
ret.y *= overlapping_ratio;
- } else { // TILE_OFFSET_AXIS_VERTICAL
+ } else { // TILE_OFFSET_AXIS_VERTICAL.
if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
overlapping_ratio = 0.5;
} else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
@@ -3309,7 +3545,7 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
TileSet::TileOffsetAxis tile_offset_axis = tile_set->get_tile_offset_axis();
TileSet::TileLayout tile_layout = tile_set->get_tile_layout();
- // Divide by the overlapping ratio
+ // Divide by the overlapping ratio.
double overlapping_ratio = 1.0;
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
@@ -3318,7 +3554,7 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
overlapping_ratio = 0.75;
}
ret.y /= overlapping_ratio;
- } else { // TILE_OFFSET_AXIS_VERTICAL
+ } else { // TILE_OFFSET_AXIS_VERTICAL.
if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
overlapping_ratio = 0.5;
} else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
@@ -3330,7 +3566,7 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
// For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the local position accordingly.
if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
// Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
- // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap
+ // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap.
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
// Smart floor of the position
Vector2 raw_pos = ret;
@@ -3340,7 +3576,7 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
ret = ret.floor();
}
- // Compute the tile offset, and if we might the output for a neighbor top tile
+ // Compute the tile offset, and if we might the output for a neighbor top tile.
Vector2 in_tile_pos = raw_pos - ret;
bool in_top_left_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(-0.5, 1.0 / overlapping_ratio - 1)) <= 0;
bool in_top_right_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(0.5, 1.0 / overlapping_ratio - 1)) > 0;
@@ -3395,8 +3631,8 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
}
break;
}
- } else { // TILE_OFFSET_AXIS_VERTICAL
- // Smart floor of the position
+ } else { // TILE_OFFSET_AXIS_VERTICAL.
+ // Smart floor of the position.
Vector2 raw_pos = ret;
if (Math::posmod(Math::floor(ret.x), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) {
ret = Vector2(Math::floor(ret.x), Math::floor(ret.y + 0.5) - 0.5);
@@ -3404,7 +3640,7 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
ret = ret.floor();
}
- // Compute the tile offset, and if we might the output for a neighbor top tile
+ // Compute the tile offset, and if we might the output for a neighbor top tile.
Vector2 in_tile_pos = raw_pos - ret;
bool in_top_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, -0.5)) > 0;
bool in_bottom_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, 0.5)) <= 0;
@@ -3533,7 +3769,7 @@ Vector2i TileMap::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeigh
default:
ERR_FAIL_V(p_coords);
}
- } else { // Half-offset shapes (square and hexagon)
+ } else { // Half-offset shapes (square and hexagon).
switch (tile_set->get_tile_layout()) {
case TileSet::TILE_LAYOUT_STACKED: {
if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
@@ -3843,63 +4079,23 @@ Vector2i TileMap::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeigh
}
TypedArray<Vector2i> TileMap::get_used_cells(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TypedArray<Vector2i>());
-
- // Returns the cells used in the tilemap.
- TypedArray<Vector2i> a;
- a.resize(layers[p_layer].tile_map.size());
- int i = 0;
- for (const KeyValue<Vector2i, TileMapCell> &E : layers[p_layer].tile_map) {
- Vector2i p(E.key.x, E.key.y);
- a[i++] = p;
- }
-
- return a;
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, TypedArray<Vector2i>(), get_used_cells);
}
TypedArray<Vector2i> TileMap::get_used_cells_by_id(int p_layer, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const {
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TypedArray<Vector2i>());
-
- // Returns the cells used in the tilemap.
- TypedArray<Vector2i> a;
- for (const KeyValue<Vector2i, TileMapCell> &E : layers[p_layer].tile_map) {
- if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == E.value.source_id) &&
- (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == E.value.get_atlas_coords()) &&
- (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == E.value.alternative_tile)) {
- a.push_back(E.key);
- }
- }
-
- return a;
+ TILEMAP_CALL_FOR_LAYER_V(p_layer, TypedArray<Vector2i>(), get_used_cells_by_id);
}
-Rect2i TileMap::get_used_rect() { // Not const because of cache
- // Return the rect of the currently used area
- if (used_rect_cache_dirty) {
- bool first = true;
- used_rect_cache = Rect2i();
-
- for (unsigned int i = 0; i < layers.size(); i++) {
- const HashMap<Vector2i, TileMapCell> &tile_map = layers[i].tile_map;
- 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;
- }
-
- for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
- used_rect_cache.expand_to(Vector2i(E.key.x, E.key.y));
- }
- }
- }
-
- 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;
+Rect2i TileMap::get_used_rect() const {
+ // Return the visible rect of the tilemap.
+ if (layers.is_empty()) {
+ return Rect2i();
}
-
- return used_rect_cache;
+ Rect2 rect = layers[0]->get_used_rect();
+ for (unsigned int i = 1; i < layers.size(); i++) {
+ rect = rect.merge(layers[i]->get_used_rect());
+ }
+ return rect;
}
// --- Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems ---
@@ -3907,13 +4103,8 @@ Rect2i TileMap::get_used_rect() { // Not const because of cache
void TileMap::set_light_mask(int p_light_mask) {
// Occlusion: set light mask.
CanvasItem::set_light_mask(p_light_mask);
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
- for (const RID &ci : E.value.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_light_mask(ci, get_light_mask());
- }
- }
- _rendering_update_layer(layer);
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_light_mask_changed();
}
}
@@ -3922,14 +4113,8 @@ void TileMap::set_material(const Ref<Material> &p_material) {
CanvasItem::set_material(p_material);
// Update material for the whole tilemap.
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- for (KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
- TileMapQuadrant &q = E.value;
- for (const RID &ci : q.canvas_items) {
- RS::get_singleton()->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid());
- }
- }
- _rendering_update_layer(layer);
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_material_changed();
}
}
@@ -3938,46 +4123,24 @@ void TileMap::set_use_parent_material(bool p_use_parent_material) {
CanvasItem::set_use_parent_material(p_use_parent_material);
// Update use_parent_material for the whole tilemap.
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- for (KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
- TileMapQuadrant &q = E.value;
- for (const RID &ci : q.canvas_items) {
- RS::get_singleton()->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid());
- }
- }
- _rendering_update_layer(layer);
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_use_parent_material_changed();
}
}
void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
// Set a default texture filter for the whole tilemap.
CanvasItem::set_texture_filter(p_texture_filter);
- TextureFilter target_filter = get_texture_filter_in_tree();
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
- TileMapQuadrant &q = F->value;
- for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(target_filter));
- _make_quadrant_dirty(F);
- }
- }
- _rendering_update_layer(layer);
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_texture_filter_changed();
}
}
void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
// Set a default texture repeat for the whole tilemap.
CanvasItem::set_texture_repeat(p_texture_repeat);
- TextureRepeat target_repeat = get_texture_repeat_in_tree();
- for (unsigned int layer = 0; layer < layers.size(); layer++) {
- for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
- TileMapQuadrant &q = F->value;
- for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(target_repeat));
- _make_quadrant_dirty(F);
- }
- }
- _rendering_update_layer(layer);
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->notify_texture_repeat_changed();
}
}
@@ -4075,15 +4238,15 @@ PackedStringArray TileMap::get_configuration_warnings() const {
// Retrieve the set of Z index values with a Y-sorted layer.
RBSet<int> y_sorted_z_index;
- for (const TileMapLayer &layer : layers) {
- if (layer.y_sort_enabled) {
- y_sorted_z_index.insert(layer.z_index);
+ for (const Ref<TileMapLayer> &layer : layers) {
+ if (layer->is_y_sort_enabled()) {
+ y_sorted_z_index.insert(layer->get_z_index());
}
}
// Check if we have a non-sorted layer in a Z-index with a Y-sorted layer.
- for (const TileMapLayer &layer : layers) {
- if (!layer.y_sort_enabled && y_sorted_z_index.has(layer.z_index)) {
+ for (const Ref<TileMapLayer> &layer : layers) {
+ if (!layer->is_y_sort_enabled() && y_sorted_z_index.has(layer->get_z_index())) {
warnings.push_back(RTR("A Y-sorted layer has the same Z-index value as a not Y-sorted layer.\nThis may lead to unwanted behaviors, as a layer that is not Y-sorted will be Y-sorted as a whole with tiles from Y-sorted layers."));
break;
}
@@ -4091,8 +4254,8 @@ PackedStringArray TileMap::get_configuration_warnings() const {
// Check if Y-sort is enabled on a layer but not on the node.
if (!is_y_sort_enabled()) {
- for (const TileMapLayer &layer : layers) {
- if (layer.y_sort_enabled) {
+ for (const Ref<TileMapLayer> &layer : layers) {
+ if (layer->is_y_sort_enabled()) {
warnings.push_back(RTR("A TileMap layer is set as Y-sorted, but Y-sort is not enabled on the TileMap node itself."));
break;
}
@@ -4103,8 +4266,8 @@ PackedStringArray TileMap::get_configuration_warnings() const {
if (tile_set.is_valid() && tile_set->get_tile_shape() == TileSet::TILE_SHAPE_ISOMETRIC) {
bool warn = !is_y_sort_enabled();
if (!warn) {
- for (const TileMapLayer &layer : layers) {
- if (!layer.y_sort_enabled) {
+ for (const Ref<TileMapLayer> &layer : layers) {
+ if (!layer->is_y_sort_enabled()) {
warn = true;
break;
}
@@ -4142,6 +4305,13 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_layer_y_sort_origin", "layer"), &TileMap::get_layer_y_sort_origin);
ClassDB::bind_method(D_METHOD("set_layer_z_index", "layer", "z_index"), &TileMap::set_layer_z_index);
ClassDB::bind_method(D_METHOD("get_layer_z_index", "layer"), &TileMap::get_layer_z_index);
+ ClassDB::bind_method(D_METHOD("set_layer_navigation_map", "layer", "map"), &TileMap::set_layer_navigation_map);
+ ClassDB::bind_method(D_METHOD("get_layer_navigation_map", "layer"), &TileMap::get_layer_navigation_map);
+
+#ifndef DISABLE_DEPRECATED
+ ClassDB::bind_method(D_METHOD("set_navigation_map", "layer", "map"), &TileMap::set_layer_navigation_map);
+ ClassDB::bind_method(D_METHOD("get_navigation_map", "layer"), &TileMap::get_layer_navigation_map);
+#endif // DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_collision_animatable", "enabled"), &TileMap::set_collision_animatable);
ClassDB::bind_method(D_METHOD("is_collision_animatable"), &TileMap::is_collision_animatable);
@@ -4151,9 +4321,6 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_navigation_visibility_mode", "navigation_visibility_mode"), &TileMap::set_navigation_visibility_mode);
ClassDB::bind_method(D_METHOD("get_navigation_visibility_mode"), &TileMap::get_navigation_visibility_mode);
- ClassDB::bind_method(D_METHOD("set_navigation_map", "layer", "map"), &TileMap::set_navigation_map);
- ClassDB::bind_method(D_METHOD("get_navigation_map", "layer"), &TileMap::get_navigation_map);
-
ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0));
ClassDB::bind_method(D_METHOD("erase_cell", "layer", "coords"), &TileMap::erase_cell);
ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id, DEFVAL(false));
@@ -4203,9 +4370,9 @@ void TileMap::_bind_methods() {
ADD_ARRAY("layers", "layer_");
- ADD_PROPERTY_DEFAULT("format", FORMAT_1);
+ ADD_PROPERTY_DEFAULT("format", TileMapLayer::FORMAT_1);
- ADD_SIGNAL(MethodInfo("changed"));
+ ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed));
BIND_ENUM_CONSTANT(VISIBILITY_MODE_DEFAULT);
BIND_ENUM_CONSTANT(VISIBILITY_MODE_FORCE_HIDE);
@@ -4213,9 +4380,11 @@ void TileMap::_bind_methods() {
}
void TileMap::_tile_set_changed() {
- emit_signal(SNAME("changed"));
+ emit_signal(CoreStringNames::get_singleton()->changed);
_tile_set_changed_deferred_update_needed = true;
- instantiated_scenes.clear();
+ for (Ref<TileMapLayer> &layer : layers) {
+ layer->clear_instantiated_scenes();
+ }
call_deferred(SNAME("_tile_set_changed_deferred_update"));
update_configuration_warnings();
}
@@ -4232,13 +4401,20 @@ TileMap::TileMap() {
set_notify_transform(true);
set_notify_local_transform(false);
- layers.resize(1);
+ Ref<TileMapLayer> new_layer;
+ new_layer.instantiate();
+ new_layer->set_tile_map(this);
+ new_layer->set_layer_index_in_tile_map_node(0);
+ layers.push_back(new_layer);
}
TileMap::~TileMap() {
if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
+ tile_set->disconnect_changed(callable_mp(this, &TileMap::_tile_set_changed));
}
_clear_internals();
}
+
+#undef TILEMAP_CALL_FOR_LAYER
+#undef TILEMAP_CALL_FOR_LAYER_V
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 3c135d1317..0ad47c51da 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -37,6 +37,58 @@
class TileSetAtlasSource;
+class TerrainConstraint {
+private:
+ const TileMap *tile_map = nullptr;
+ Vector2i base_cell_coords;
+ int bit = -1;
+ int terrain = -1;
+
+ int priority = 1;
+
+public:
+ bool operator<(const TerrainConstraint &p_other) const {
+ if (base_cell_coords == p_other.base_cell_coords) {
+ return bit < p_other.bit;
+ }
+ return base_cell_coords < p_other.base_cell_coords;
+ }
+
+ String to_string() const {
+ return vformat("Constraint {pos:%s, bit:%d, terrain:%d, priority:%d}", base_cell_coords, bit, terrain, priority);
+ }
+
+ Vector2i get_base_cell_coords() const {
+ return base_cell_coords;
+ }
+
+ bool is_center_bit() const {
+ return bit == 0;
+ }
+
+ HashMap<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const;
+
+ void set_terrain(int p_terrain) {
+ terrain = p_terrain;
+ }
+
+ int get_terrain() const {
+ return terrain;
+ }
+
+ void set_priority(int p_priority) {
+ priority = p_priority;
+ }
+
+ int get_priority() const {
+ return priority;
+ }
+
+ TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain); // For the center terrain bit
+ TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits
+ TerrainConstraint(){};
+};
+
struct TileMapQuadrant {
struct CoordsWorldComparator {
_ALWAYS_INLINE_ bool operator()(const Vector2 &p_a, const Vector2 &p_b) const {
@@ -52,13 +104,12 @@ struct TileMapQuadrant {
// Dirty list element.
SelfList<TileMapQuadrant> dirty_list_element;
- // Quadrant layer and coords.
- int layer = -1;
+ // Quadrant coords.
Vector2i coords;
- // TileMapCells
+ // TileMapCells.
RBSet<Vector2i> cells;
- // We need those two maps to sort by local position for rendering
+ // We need those two maps to sort by local position for rendering.
// This is kind of workaround, it would be better to sort the cells directly in the "cells" set instead.
RBMap<Vector2i, Vector2> map_to_local;
RBMap<Vector2, Vector2i, CoordsWorldComparator> local_to_map;
@@ -83,7 +134,6 @@ struct TileMapQuadrant {
HashMap<Vector2i, TileData *> runtime_tile_data_cache;
void operator=(const TileMapQuadrant &q) {
- layer = q.layer;
coords = q.coords;
debug_canvas_item = q.debug_canvas_item;
canvas_items = q.canvas_items;
@@ -94,7 +144,6 @@ struct TileMapQuadrant {
TileMapQuadrant(const TileMapQuadrant &q) :
dirty_list_element(this) {
- layer = q.layer;
coords = q.coords;
debug_canvas_item = q.debug_canvas_item;
canvas_items = q.canvas_items;
@@ -108,62 +157,174 @@ struct TileMapQuadrant {
}
};
-class TileMap : public Node2D {
- GDCLASS(TileMap, Node2D);
-
+class TileMapLayer : public RefCounted {
public:
- class TerrainConstraint {
- private:
- const TileMap *tile_map;
- Vector2i base_cell_coords;
- int bit = -1;
- int terrain = -1;
-
- int priority = 1;
-
- public:
- bool operator<(const TerrainConstraint &p_other) const {
- if (base_cell_coords == p_other.base_cell_coords) {
- return bit < p_other.bit;
- }
- return base_cell_coords < p_other.base_cell_coords;
- }
+ enum DataFormat {
+ FORMAT_1 = 0,
+ FORMAT_2,
+ FORMAT_3,
+ FORMAT_MAX,
+ };
- String to_string() const {
- return vformat("Constraint {pos:%s, bit:%d, terrain:%d, priority:%d}", base_cell_coords, bit, terrain, priority);
- }
+private:
+ // Exposed properties.
+ String name;
+ bool enabled = true;
+ Color modulate = Color(1, 1, 1, 1);
+ bool y_sort_enabled = false;
+ int y_sort_origin = 0;
+ int z_index = 0;
+ RID navigation_map;
+ bool uses_world_navigation_map = false;
+
+ // Internal.
+ TileMap *tile_map_node = nullptr;
+ int layer_index_in_tile_map_node = -1;
+ RID canvas_item;
+ bool _rendering_quadrant_order_dirty = false;
+ HashMap<Vector2i, TileMapCell> tile_map;
+ HashMap<Vector2i, TileMapQuadrant> quadrant_map;
+ SelfList<TileMapQuadrant>::List dirty_quadrant_list;
+
+ // Rect cache.
+ mutable Rect2 rect_cache;
+ mutable bool rect_cache_dirty = true;
+ mutable Rect2i used_rect_cache;
+ mutable bool used_rect_cache_dirty = true;
+
+ // Quadrants management.
+ Vector2i _coords_to_quadrant_coords(const Vector2i &p_coords) const;
+ HashMap<Vector2i, TileMapQuadrant>::Iterator _create_quadrant(const Vector2i &p_qk);
+ void _make_quadrant_dirty(HashMap<Vector2i, TileMapQuadrant>::Iterator Q);
+ void _erase_quadrant(HashMap<Vector2i, TileMapQuadrant>::Iterator Q);
- Vector2i get_base_cell_coords() const {
- return base_cell_coords;
- }
+ // Per-system methods.
+ void _rendering_notification(int p_what);
+ void _rendering_update();
+ void _rendering_cleanup();
+ void _rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
+ void _rendering_reorder_quadrants(int &r_index);
+ void _rendering_create_quadrant(TileMapQuadrant *p_quadrant);
+ void _rendering_cleanup_quadrant(TileMapQuadrant *p_quadrant);
+ void _rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
- bool is_center_bit() const {
- return bit == 0;
- }
+ HashMap<RID, Vector2i> bodies_coords; // Mapping for RID to coords.
+ void _physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
+ void _physics_cleanup_quadrant(TileMapQuadrant *p_quadrant);
+ void _physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
- HashMap<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const;
+ void _navigation_update();
+ void _navigation_cleanup();
+ void _navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
+ void _navigation_cleanup_quadrant(TileMapQuadrant *p_quadrant);
+ void _navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
- void set_terrain(int p_terrain) {
- terrain = p_terrain;
- }
+ HashSet<Vector2i> instantiated_scenes;
+ void _scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
+ void _scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant);
+ void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
- int get_terrain() const {
- return terrain;
- }
+ // Runtime tile data.
+ void _build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
- void set_priority(int p_priority) {
- priority = p_priority;
- }
+ // Terrains.
+ TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern);
+ RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const;
+ RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const;
- int get_priority() const {
- return priority;
- }
+public:
+ // TileMap node.
+ void set_tile_map(TileMap *p_tile_map);
+ void set_layer_index_in_tile_map_node(int p_index);
- TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain); // For the center terrain bit
- TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits
- TerrainConstraint(){};
- };
+ // Rect caching.
+ Rect2 get_rect(bool &r_changed) const;
+ // Terrains.
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints); // Not exposed.
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed.
+
+ // Not exposed to users.
+ TileMapCell get_cell(const Vector2i &p_coords, bool p_use_proxies = false) const;
+ int get_effective_quadrant_size() const;
+
+ // For TileMap node's use.
+ void notify_canvas_entered();
+ void notify_visibility_changed();
+ void notify_xform_changed();
+ void notify_local_xform_changed();
+ void notify_canvas_exited();
+ void notify_selected_layer_changed();
+ void notify_light_mask_changed();
+ void notify_material_changed();
+ void notify_use_parent_material_changed();
+ void notify_texture_filter_changed();
+ void notify_texture_repeat_changed();
+ void update_dirty_quadrants();
+ void set_tile_data(DataFormat p_format, const Vector<int> &p_data);
+ Vector<int> get_tile_data() const;
+ void clear_instantiated_scenes();
+ void clear_internals(); // Exposed for now to tilemap, but ideally, we should avoid it.
+ void recreate_internals(); // Exposed for now to tilemap, but ideally, we should avoid it.
+
+ // --- Exposed in TileMap ---
+
+ // Cells manipulation.
+ void set_cell(const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0);
+ void erase_cell(const Vector2i &p_coords);
+
+ int get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies = false) const;
+ Vector2i get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies = false) const;
+ int get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies = false) const;
+ TileData *get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies = false) const; // Helper method to make accessing the data easier.
+ void clear();
+
+ // Patterns.
+ Ref<TileMapPattern> get_pattern(TypedArray<Vector2i> p_coords_array);
+ void set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern);
+
+ // Terrains.
+ void set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
+ void set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
+
+ // Cells usage.
+ TypedArray<Vector2i> get_used_cells() const;
+ TypedArray<Vector2i> get_used_cells_by_id(int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const;
+ Rect2i get_used_rect() const;
+
+ // Layer properties.
+ void set_name(String p_name);
+ String get_name() const;
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+ void set_modulate(Color p_modulate);
+ Color get_modulate() const;
+ void set_y_sort_enabled(bool p_y_sort_enabled);
+ bool is_y_sort_enabled() const;
+ void set_y_sort_origin(int p_y_sort_origin);
+ int get_y_sort_origin() const;
+ void set_z_index(int p_z_index);
+ int get_z_index() const;
+ void set_navigation_map(RID p_map);
+ RID get_navigation_map() const;
+
+ // In case something goes wrong.
+ void force_update();
+
+ // Fixing and clearing methods.
+ void fix_invalid_tiles();
+
+ // Find coords for body.
+ bool has_body_rid(RID p_physics_body) const;
+ Vector2i get_coords_for_body_rid(RID p_physics_body) const; // For finding tiles from collision.
+};
+
+class TileMap : public Node2D {
+ GDCLASS(TileMap, Node2D);
+
+public:
enum VisibilityMode {
VISIBILITY_MODE_DEFAULT,
VISIBILITY_MODE_FORCE_SHOW,
@@ -174,12 +335,7 @@ private:
friend class TileSetPlugin;
// A compatibility enum to specify how is the data if formatted.
- enum DataFormat {
- FORMAT_1 = 0,
- FORMAT_2,
- FORMAT_3
- };
- mutable DataFormat format = FORMAT_3;
+ mutable TileMapLayer::DataFormat format = TileMapLayer::FORMAT_3;
static constexpr float FP_ADJUST = 0.00001;
@@ -190,99 +346,17 @@ private:
VisibilityMode collision_visibility_mode = VISIBILITY_MODE_DEFAULT;
VisibilityMode navigation_visibility_mode = VISIBILITY_MODE_DEFAULT;
- // Updates.
- bool pending_update = false;
-
- // Rect.
- Rect2 rect_cache;
- bool rect_cache_dirty = true;
- Rect2i used_rect_cache;
- bool used_rect_cache_dirty = true;
-
- // TileMap layers.
- struct TileMapLayer {
- String name;
- bool enabled = true;
- Color modulate = Color(1, 1, 1, 1);
- bool y_sort_enabled = false;
- int y_sort_origin = 0;
- int z_index = 0;
- RID canvas_item;
- HashMap<Vector2i, TileMapCell> tile_map;
- HashMap<Vector2i, TileMapQuadrant> quadrant_map;
- SelfList<TileMapQuadrant>::List dirty_quadrant_list;
- RID navigation_map;
- bool uses_world_navigation_map = false;
- };
- LocalVector<TileMapLayer> layers;
+ // Layers.
+ LocalVector<Ref<TileMapLayer>> layers;
int selected_layer = -1;
- // Mapping for RID to coords.
- HashMap<RID, Vector2i> bodies_coords;
- // Mapping for RID to tile layer.
- HashMap<RID, int> bodies_layers;
-
- // Quadrants and internals management.
- Vector2i _coords_to_quadrant_coords(int p_layer, const Vector2i &p_coords) const;
-
- HashMap<Vector2i, TileMapQuadrant>::Iterator _create_quadrant(int p_layer, const Vector2i &p_qk);
-
- void _make_quadrant_dirty(HashMap<Vector2i, TileMapQuadrant>::Iterator Q);
- void _make_all_quadrants_dirty();
- void _queue_update_dirty_quadrants();
-
- void _update_dirty_quadrants();
-
- void _recreate_layer_internals(int p_layer);
- void _recreate_internals();
-
- void _erase_quadrant(HashMap<Vector2i, TileMapQuadrant>::Iterator Q);
- void _clear_layer_internals(int p_layer);
void _clear_internals();
+ void _recreate_internals();
- HashSet<Vector3i> instantiated_scenes;
-
- // Rect caching.
- void _recompute_rect_cache();
-
- // Per-system methods.
- bool _rendering_quadrant_order_dirty = false;
- void _rendering_notification(int p_what);
- void _rendering_update_layer(int p_layer);
- void _rendering_cleanup_layer(int p_layer);
- void _rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
- void _rendering_create_quadrant(TileMapQuadrant *p_quadrant);
- void _rendering_cleanup_quadrant(TileMapQuadrant *p_quadrant);
- void _rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
+ bool pending_update = false;
Transform2D last_valid_transform;
Transform2D new_transform;
- void _physics_notification(int p_what);
- void _physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
- void _physics_cleanup_quadrant(TileMapQuadrant *p_quadrant);
- void _physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
-
- void _navigation_notification(int p_what);
- void _navigation_update_layer(int p_layer);
- void _navigation_cleanup_layer(int p_layer);
- void _navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
- void _navigation_cleanup_quadrant(TileMapQuadrant *p_quadrant);
- void _navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
-
- void _scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
- void _scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant);
- void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
-
- // Terrains.
- TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern);
- RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const;
- RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const;
-
- // Set and get tiles from data arrays.
- void _set_tile_data(int p_layer, const Vector<int> &p_data);
- Vector<int> _get_tile_data(int p_layer) const;
-
- void _build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
void _tile_set_changed();
bool _tile_set_changed_deferred_update_needed = false;
@@ -296,30 +370,36 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ Rect2i _get_used_rect_bind_compat_78328();
+ static void _bind_compatibility_methods();
+#endif
+
public:
static Vector2i transform_coords_layout(const Vector2i &p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout);
- enum {
- INVALID_CELL = -1
- };
-
#ifdef TOOLS_ENABLED
virtual Rect2 _edit_get_rect() const override;
#endif
+ // Called by TileMapLayers.
+ void queue_update_dirty_quadrants();
+ void _update_dirty_quadrants();
+
void set_tileset(const Ref<TileSet> &p_tileset);
Ref<TileSet> get_tileset() const;
void set_quadrant_size(int p_size);
int get_quadrant_size() const;
- static void draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0), const TileData *p_tile_data_override = nullptr);
+ static void draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0), const TileData *p_tile_data_override = nullptr, real_t p_animation_offset = 0.0);
// Layers management.
int get_layers_count() const;
void add_layer(int p_to_pos);
void move_layer(int p_layer, int p_to_pos);
void remove_layer(int p_layer);
+
void set_layer_name(int p_layer, String p_name);
String get_layer_name(int p_layer) const;
void set_layer_enabled(int p_layer, bool p_visible);
@@ -332,6 +412,9 @@ public:
int get_layer_y_sort_origin(int p_layer) const;
void set_layer_z_index(int p_layer, int p_z_index);
int get_layer_z_index(int p_layer) const;
+ void set_layer_navigation_map(int p_layer, RID p_map);
+ RID get_layer_navigation_map(int p_layer) const;
+
void set_selected_layer(int p_layer_id); // For editor use.
int get_selected_layer() const;
@@ -345,9 +428,6 @@ public:
void set_navigation_visibility_mode(VisibilityMode p_show_navigation);
VisibilityMode get_navigation_visibility_mode();
- void set_navigation_map(int p_layer, RID p_map);
- RID get_navigation_map(int p_layer) const;
-
// Cells accessors.
void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0);
void erase_cell(int p_layer, const Vector2i &p_coords);
@@ -362,20 +442,19 @@ public:
Vector2i map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern);
void set_pattern(int p_layer, const Vector2i &p_position, const Ref<TileMapPattern> p_pattern);
- // Terrains.
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints); // Not exposed.
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed.
+ // Terrains (Not exposed).
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints);
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true);
+ // Terrains (exposed).
void set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
void set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
- // Not exposed to users
+ // Not exposed to users.
TileMapCell get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
- HashMap<Vector2i, TileMapQuadrant> *get_quadrant_map(int p_layer);
int get_effective_quadrant_size(int p_layer) const;
- //---
virtual void set_y_sort_enabled(bool p_enable) override;
@@ -387,9 +466,9 @@ public:
TypedArray<Vector2i> get_used_cells(int p_layer) const;
TypedArray<Vector2i> get_used_cells_by_id(int p_layer, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const;
- Rect2i get_used_rect(); // Not const because of cache
+ Rect2i get_used_rect() const;
- // Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems
+ // Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems.
virtual void set_light_mask(int p_light_mask) override;
virtual void set_material(const Ref<Material> &p_material) override;
virtual void set_use_parent_material(bool p_use_parent_material) override;
@@ -404,18 +483,18 @@ public:
// Fixing and clearing methods.
void fix_invalid_tiles();
- // Clears tiles from a given layer
+ // Clears tiles from a given layer.
void clear_layer(int p_layer);
void clear();
- // Force a TileMap update
+ // Force a TileMap update.
void force_update(int p_layer = -1);
// 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());
- // Virtual function to modify the TileData at runtime
+ // Virtual function to modify the TileData at runtime.
GDVIRTUAL2R(bool, _use_tile_data_runtime_update, int, Vector2i);
GDVIRTUAL3(_tile_data_runtime_update, int, Vector2i, TileData *);
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index 7da2fc3cb3..5ed7fadb2a 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -82,11 +82,11 @@ void TouchScreenButton::set_shape(const Ref<Shape2D> &p_shape) {
return;
}
if (shape.is_valid()) {
- shape->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ shape->disconnect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
shape = p_shape;
if (shape.is_valid()) {
- shape->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ shape->connect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
queue_redraw();
}
@@ -369,6 +369,19 @@ bool TouchScreenButton::is_passby_press_enabled() const {
return passby_press;
}
+#ifndef DISABLE_DEPRECATED
+bool TouchScreenButton::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == SNAME("normal")) { // Compatibility with Godot 3.x.
+ set_texture_normal(p_value);
+ return true;
+ } else if (p_name == SNAME("pressed")) { // Compatibility with Godot 3.x.
+ set_texture_pressed(p_value);
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
void TouchScreenButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_normal", "texture"), &TouchScreenButton::set_texture_normal);
ClassDB::bind_method(D_METHOD("get_texture_normal"), &TouchScreenButton::get_texture_normal);
diff --git a/scene/2d/touch_screen_button.h b/scene/2d/touch_screen_button.h
index 492aa377e6..c7dc0a323e 100644
--- a/scene/2d/touch_screen_button.h
+++ b/scene/2d/touch_screen_button.h
@@ -71,6 +71,9 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+#endif // DISABLE_DEPRECATED
public:
#ifdef TOOLS_ENABLED
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index 5a4761892d..37ceb9d1a1 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -31,7 +31,6 @@
#include "camera_3d.h"
#include "collision_object_3d.h"
-#include "core/core_string_names.h"
#include "core/math/projection.h"
#include "scene/main/viewport.h"
@@ -170,6 +169,30 @@ Transform3D Camera3D::get_camera_transform() const {
return tr;
}
+Projection Camera3D::_get_camera_projection(real_t p_near) const {
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+ Projection cm;
+
+ switch (mode) {
+ case PROJECTION_PERSPECTIVE: {
+ cm.set_perspective(fov, viewport_size.aspect(), p_near, far, keep_aspect == KEEP_WIDTH);
+ } break;
+ case PROJECTION_ORTHOGONAL: {
+ cm.set_orthogonal(size, viewport_size.aspect(), p_near, far, keep_aspect == KEEP_WIDTH);
+ } break;
+ case PROJECTION_FRUSTUM: {
+ cm.set_frustum(size, viewport_size.aspect(), frustum_offset, p_near, far);
+ } break;
+ }
+
+ return cm;
+}
+
+Projection Camera3D::get_camera_projection() const {
+ ERR_FAIL_COND_V_MSG(!is_inside_tree(), Projection(), "Camera is not inside the scene tree.");
+ return _get_camera_projection(near);
+}
+
void Camera3D::set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) {
if (!force_change && fov == p_fovy_degrees && p_z_near == near && p_z_far == far && mode == PROJECTION_PERSPECTIVE) {
return;
@@ -286,8 +309,7 @@ Vector3 Camera3D::project_local_ray_normal(const Point2 &p_pos) const {
if (mode == PROJECTION_ORTHOGONAL) {
ray = Vector3(0, 0, -1);
} else {
- Projection cm;
- cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+ Projection cm = _get_camera_projection(near);
Vector2 screen_he = cm.get_viewport_half_extents();
ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -near).normalized();
}
@@ -302,9 +324,7 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const {
Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
ERR_FAIL_COND_V(viewport_size.y == 0, Vector3());
- if (mode == PROJECTION_PERSPECTIVE) {
- return get_camera_transform().origin;
- } else {
+ if (mode == PROJECTION_ORTHOGONAL) {
Vector2 pos = cpos / viewport_size;
real_t vsize, hsize;
if (keep_aspect == KEEP_WIDTH) {
@@ -321,6 +341,8 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const {
ray.z = -near;
ray = get_camera_transform().xform(ray);
return ray;
+ } else {
+ return get_camera_transform().origin;
};
};
@@ -333,15 +355,7 @@ bool Camera3D::is_position_behind(const Vector3 &p_pos) const {
Vector<Vector3> Camera3D::get_near_plane_points() const {
ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector<Vector3>(), "Camera is not inside scene.");
- Size2 viewport_size = get_viewport()->get_visible_rect().size;
-
- Projection cm;
-
- if (mode == PROJECTION_ORTHOGONAL) {
- cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- } else {
- cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- }
+ Projection cm = _get_camera_projection(near);
Vector3 endpoints[8];
cm.get_endpoints(Transform3D(), endpoints);
@@ -361,13 +375,7 @@ Point2 Camera3D::unproject_position(const Vector3 &p_pos) const {
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- Projection cm;
-
- if (mode == PROJECTION_ORTHOGONAL) {
- cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- } else {
- cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- }
+ Projection cm = _get_camera_projection(near);
Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
@@ -389,13 +397,7 @@ Vector3 Camera3D::project_position(const Point2 &p_point, real_t p_z_depth) cons
}
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- Projection cm;
-
- if (mode == PROJECTION_ORTHOGONAL) {
- cm.set_orthogonal(size, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH);
- } else {
- cm.set_perspective(fov, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH);
- }
+ Projection cm = _get_camera_projection(p_z_depth);
Vector2 vp_he = cm.get_viewport_half_extents();
@@ -427,7 +429,7 @@ void Camera3D::set_attributes(const Ref<CameraAttributes> &p_attributes) {
if (attributes.is_valid()) {
CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr());
if (physical_attributes) {
- attributes->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Camera3D::_attributes_changed));
+ attributes->disconnect_changed(callable_mp(this, &Camera3D::_attributes_changed));
}
}
@@ -436,7 +438,7 @@ void Camera3D::set_attributes(const Ref<CameraAttributes> &p_attributes) {
if (attributes.is_valid()) {
CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr());
if (physical_attributes) {
- attributes->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Camera3D::_attributes_changed));
+ attributes->connect_changed(callable_mp(this, &Camera3D::_attributes_changed));
_attributes_changed();
}
@@ -508,6 +510,7 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_current", "enabled"), &Camera3D::set_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera3D::is_current);
ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera3D::get_camera_transform);
+ ClassDB::bind_method(D_METHOD("get_camera_projection"), &Camera3D::get_camera_projection);
ClassDB::bind_method(D_METHOD("get_fov"), &Camera3D::get_fov);
ClassDB::bind_method(D_METHOD("get_frustum_offset"), &Camera3D::get_frustum_offset);
ClassDB::bind_method(D_METHOD("get_size"), &Camera3D::get_size);
@@ -653,13 +656,7 @@ bool Camera3D::get_cull_mask_value(int p_layer_number) const {
Vector<Plane> Camera3D::get_frustum() const {
ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
- Size2 viewport_size = get_viewport()->get_visible_rect().size;
- Projection cm;
- if (mode == PROJECTION_PERSPECTIVE) {
- cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- } else {
- cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- }
+ Projection cm = _get_camera_projection(near);
return cm.get_projection_planes(get_camera_transform());
}
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index 420d0cb939..aa302ded4a 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -105,6 +105,8 @@ protected:
static void _bind_methods();
+ Projection _get_camera_projection(real_t p_near) const;
+
public:
enum {
NOTIFICATION_BECAME_CURRENT = 50,
@@ -138,6 +140,7 @@ public:
void set_frustum_offset(Vector2 p_offset);
virtual Transform3D get_camera_transform() const;
+ virtual Projection get_camera_projection() const;
virtual Vector3 project_ray_normal(const Point2 &p_pos) const;
virtual Vector3 project_ray_origin(const Point2 &p_pos) const;
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 6d8d60dcaa..bfe594adc2 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -394,11 +394,7 @@ void CollisionObject3D::_update_debug_shapes() {
if (s.debug_shape.is_null()) {
s.debug_shape = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_scenario(s.debug_shape, get_world_3d()->get_scenario());
-
- if (!s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_shape_changed))) {
- s.shape->connect("changed", callable_mp(this, &CollisionObject3D::_shape_changed).bind(s.shape), CONNECT_DEFERRED);
- }
-
+ s.shape->connect_changed(callable_mp(this, &CollisionObject3D::_shape_changed).bind(s.shape), CONNECT_DEFERRED);
++debug_shapes_count;
}
@@ -422,8 +418,8 @@ void CollisionObject3D::_clear_debug_shapes() {
if (s.debug_shape.is_valid()) {
RS::get_singleton()->free(s.debug_shape);
s.debug_shape = RID();
- if (s.shape.is_valid() && s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_update_shape_data))) {
- s.shape->disconnect("changed", callable_mp(this, &CollisionObject3D::_update_shape_data));
+ if (s.shape.is_valid()) {
+ s.shape->disconnect_changed(callable_mp(this, &CollisionObject3D::_update_shape_data));
}
}
}
@@ -663,8 +659,8 @@ void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
if (s.debug_shape.is_valid()) {
RS::get_singleton()->free(s.debug_shape);
- if (s.shape.is_valid() && s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_shape_changed))) {
- s.shape->disconnect("changed", callable_mp(this, &CollisionObject3D::_shape_changed));
+ if (s.shape.is_valid()) {
+ s.shape->disconnect_changed(callable_mp(this, &CollisionObject3D::_shape_changed));
}
--debug_shapes_count;
}
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 10eefc784d..0bb0382301 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -112,9 +112,10 @@ void CollisionShape3D::_notification(int p_what) {
}
}
+#ifndef DISABLE_DEPRECATED
void CollisionShape3D::resource_changed(Ref<Resource> res) {
- update_gizmos();
}
+#endif
PackedStringArray CollisionShape3D::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
@@ -145,8 +146,9 @@ PackedStringArray CollisionShape3D::get_configuration_warnings() const {
}
void CollisionShape3D::_bind_methods() {
- //not sure if this should do anything
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &CollisionShape3D::resource_changed);
+#endif
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape3D::set_shape);
ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape3D::get_shape);
ClassDB::bind_method(D_METHOD("set_disabled", "enable"), &CollisionShape3D::set_disabled);
@@ -162,12 +164,12 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
if (p_shape == shape) {
return;
}
- if (!shape.is_null()) {
- shape->unregister_owner(this);
+ if (shape.is_valid()) {
+ shape->disconnect_changed(callable_mp((Node3D *)this, &Node3D::update_gizmos));
}
shape = p_shape;
- if (!shape.is_null()) {
- shape->register_owner(this);
+ if (shape.is_valid()) {
+ shape->connect_changed(callable_mp((Node3D *)this, &Node3D::update_gizmos));
}
update_gizmos();
if (collision_object) {
@@ -206,8 +208,5 @@ CollisionShape3D::CollisionShape3D() {
}
CollisionShape3D::~CollisionShape3D() {
- if (!shape.is_null()) {
- shape->unregister_owner(this);
- }
//RenderingServer::get_singleton()->free(indicator);
}
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index 74928bad6d..bc0e70f8ac 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -43,7 +43,9 @@ class CollisionShape3D : public Node3D {
uint32_t owner_id = 0;
CollisionObject3D *collision_object = nullptr;
+#ifndef DISABLE_DEPRECATED
void resource_changed(Ref<Resource> res);
+#endif
bool disabled = false;
protected:
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 405d478a47..3dc82cfb97 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -33,7 +33,11 @@
#include "scene/3d/camera_3d.h"
#include "scene/3d/gpu_particles_3d.h"
#include "scene/main/viewport.h"
+#include "scene/resources/curve_texture.h"
+#include "scene/resources/gradient_texture.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/particle_process_material.h"
+#include "scene/scene_string_names.h"
AABB CPUParticles3D::get_aabb() const {
return AABB();
@@ -46,6 +50,7 @@ void CPUParticles3D::set_emitting(bool p_emitting) {
emitting = p_emitting;
if (emitting) {
+ active = true;
set_process_internal(true);
// first update before rendering to avoid one frame delay after emitting starts
@@ -220,7 +225,6 @@ PackedStringArray CPUParticles3D::get_configuration_warnings() const {
void CPUParticles3D::restart() {
time = 0;
- inactive_time = 0;
frame_remainder = 0;
cycle = 0;
emitting = false;
@@ -575,21 +579,15 @@ void CPUParticles3D::_update_internal() {
}
double delta = get_process_delta_time();
- if (emitting) {
- inactive_time = 0;
- } else {
- inactive_time += delta;
- if (inactive_time > lifetime * 1.2) {
- set_process_internal(false);
- _set_redraw(false);
+ if (!active && !emitting) {
+ set_process_internal(false);
+ _set_redraw(false);
- //reset variables
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- return;
- }
+ //reset variables
+ time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
}
_set_redraw(true);
@@ -670,6 +668,7 @@ void CPUParticles3D::_particles_process(double p_delta) {
double system_phase = time / lifetime;
+ bool should_be_active = false;
for (int i = 0; i < pcount; i++) {
Particle &p = parray[i];
@@ -1136,6 +1135,12 @@ void CPUParticles3D::_particles_process(double p_delta) {
}
p.transform.origin += p.velocity * local_delta;
+
+ should_be_active = true;
+ }
+ if (!Math::is_equal_approx(time, 0.0) && active && !should_be_active) {
+ active = false;
+ emit_signal(SceneStringNames::get_singleton()->finished);
}
}
@@ -1543,6 +1548,8 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles3D::convert_from_particles);
+ ADD_SIGNAL(MethodInfo("finished"));
+
ADD_GROUP("Emission Shape", "emission_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Box,Points,Directed Points,Ring", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 40ea4e8cdf..a5bc7dddb9 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -81,6 +81,7 @@ public:
private:
bool emitting = false;
+ bool active = false;
struct Particle {
Transform3D transform;
@@ -101,7 +102,6 @@ private:
};
double time = 0.0;
- double inactive_time = 0.0;
double frame_remainder = 0.0;
int cycle = 0;
bool redraw = false;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 4ac81d63b6..3a23cbcff1 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -31,19 +31,37 @@
#include "gpu_particles_3d.h"
#include "scene/resources/particle_process_material.h"
+#include "scene/scene_string_names.h"
AABB GPUParticles3D::get_aabb() const {
return AABB();
}
void GPUParticles3D::set_emitting(bool p_emitting) {
- RS::get_singleton()->particles_set_emitting(particles, p_emitting);
+ // Do not return even if `p_emitting == emitting` because `emitting` is just an approximation.
if (p_emitting && one_shot) {
+ if (!active && !emitting) {
+ // Last cycle ended.
+ active = true;
+ time = 0;
+ signal_cancled = false;
+ emission_time = lifetime;
+ active_time = lifetime * (2 - explosiveness_ratio);
+ } else {
+ signal_cancled = true;
+ }
set_process_internal(true);
} else if (!p_emitting) {
- set_process_internal(false);
+ if (one_shot) {
+ set_process_internal(true);
+ } else {
+ set_process_internal(false);
+ }
}
+
+ emitting = p_emitting;
+ RS::get_singleton()->particles_set_emitting(particles, p_emitting);
}
void GPUParticles3D::set_amount(int p_amount) {
@@ -122,7 +140,7 @@ void GPUParticles3D::set_collision_base_size(real_t p_size) {
}
bool GPUParticles3D::is_emitting() const {
- return RS::get_singleton()->particles_get_emitting(particles);
+ return emitting;
}
int GPUParticles3D::get_amount() const {
@@ -181,7 +199,7 @@ void GPUParticles3D::set_trail_enabled(bool p_enabled) {
}
void GPUParticles3D::set_trail_lifetime(double p_seconds) {
- ERR_FAIL_COND(p_seconds < 0.001);
+ ERR_FAIL_COND(p_seconds < 0.01);
trail_lifetime = p_seconds;
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime);
}
@@ -216,13 +234,13 @@ void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
ERR_FAIL_INDEX(p_pass, draw_passes.size());
if (Engine::get_singleton()->is_editor_hint() && draw_passes.write[p_pass].is_valid()) {
- draw_passes.write[p_pass]->disconnect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings));
+ draw_passes.write[p_pass]->disconnect_changed(callable_mp((Node *)this, &Node::update_configuration_warnings));
}
draw_passes.write[p_pass] = p_mesh;
if (Engine::get_singleton()->is_editor_hint() && draw_passes.write[p_pass].is_valid()) {
- draw_passes.write[p_pass]->connect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings), CONNECT_DEFERRED);
+ draw_passes.write[p_pass]->connect_changed(callable_mp((Node *)this, &Node::update_configuration_warnings), CONNECT_DEFERRED);
}
RID mesh_rid;
@@ -373,6 +391,16 @@ PackedStringArray GPUParticles3D::get_configuration_warnings() const {
void GPUParticles3D::restart() {
RenderingServer::get_singleton()->particles_restart(particles);
RenderingServer::get_singleton()->particles_set_emitting(particles, true);
+
+ emitting = true;
+ active = true;
+ signal_cancled = false;
+ time = 0;
+ emission_time = lifetime * (1 - explosiveness_ratio);
+ active_time = lifetime * (2 - explosiveness_ratio);
+ if (one_shot) {
+ set_process_internal(true);
+ }
}
AABB GPUParticles3D::capture_aabb() const {
@@ -425,9 +453,23 @@ void GPUParticles3D::_notification(int p_what) {
// Use internal process when emitting and one_shot is on so that when
// the shot ends the editor can properly update.
case NOTIFICATION_INTERNAL_PROCESS: {
- if (one_shot && !is_emitting()) {
- notify_property_list_changed();
- set_process_internal(false);
+ if (one_shot) {
+ time += get_process_delta_time();
+ if (time > emission_time) {
+ emitting = false;
+ if (!active) {
+ set_process_internal(false);
+ }
+ }
+ if (time > active_time) {
+ if (active && !signal_cancled) {
+ emit_signal(SceneStringNames::get_singleton()->finished);
+ }
+ active = false;
+ if (!emitting) {
+ set_process_internal(false);
+ }
+ }
}
} break;
@@ -571,6 +613,8 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align);
ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align);
+ ADD_SIGNAL(MethodInfo("finished"));
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 474f5500f8..dba6a8f2ab 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -60,7 +60,10 @@ public:
private:
RID particles;
- bool one_shot;
+ bool emitting = false;
+ bool active = false;
+ bool signal_cancled = false;
+ bool one_shot = false;
int amount = 0;
double lifetime = 0.0;
double pre_process_time = 0.0;
@@ -87,6 +90,10 @@ private:
Vector<Ref<Mesh>> draw_passes;
Ref<Skin> skin;
+ double time = 0.0;
+ double emission_time = 0.0;
+ double active_time = 0.0;
+
void _attach_sub_emitter();
void _skinning_changed();
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index 810c0c5326..b0e7c73253 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -30,7 +30,6 @@
#include "label_3d.h"
-#include "core/core_string_names.h"
#include "scene/main/viewport.h"
#include "scene/resources/theme.h"
#include "scene/scene_string_names.h"
@@ -126,10 +125,6 @@ void Label3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &Label3D::generate_triangle_mesh);
- ClassDB::bind_method(D_METHOD("_queue_update"), &Label3D::_queue_update);
- ClassDB::bind_method(D_METHOD("_font_changed"), &Label3D::_font_changed);
- ClassDB::bind_method(D_METHOD("_im_update"), &Label3D::_im_update);
-
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001,suffix:m"), "set_pixel_size", "get_pixel_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset");
@@ -239,7 +234,7 @@ void Label3D::_queue_update() {
}
pending_update = true;
- call_deferred(SceneStringNames::get_singleton()->_im_update);
+ callable_mp(this, &Label3D::_im_update).call_deferred();
}
AABB Label3D::get_aabb() const {
@@ -766,12 +761,12 @@ void Label3D::_font_changed() {
void Label3D::set_font(const Ref<Font> &p_font) {
if (font_override != p_font) {
if (font_override.is_valid()) {
- font_override->disconnect(CoreStringNames::get_singleton()->changed, Callable(this, "_font_changed"));
+ font_override->disconnect_changed(callable_mp(this, &Label3D::_font_changed));
}
font_override = p_font;
dirty_font = true;
if (font_override.is_valid()) {
- font_override->connect(CoreStringNames::get_singleton()->changed, Callable(this, "_font_changed"));
+ font_override->connect_changed(callable_mp(this, &Label3D::_font_changed));
}
_queue_update();
}
@@ -783,7 +778,7 @@ Ref<Font> Label3D::get_font() const {
Ref<Font> Label3D::_get_font_or_default() const {
if (theme_font.is_valid()) {
- theme_font->disconnect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
+ theme_font->disconnect_changed(callable_mp(const_cast<Label3D *>(this), &Label3D::_font_changed));
theme_font.unref();
}
@@ -801,7 +796,7 @@ Ref<Font> Label3D::_get_font_or_default() const {
Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
+ theme_font->connect_changed(callable_mp(const_cast<Label3D *>(this), &Label3D::_font_changed));
}
return f;
}
@@ -818,7 +813,7 @@ Ref<Font> Label3D::_get_font_or_default() const {
Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
+ theme_font->connect_changed(callable_mp(const_cast<Label3D *>(this), &Label3D::_font_changed));
}
return f;
}
@@ -829,7 +824,7 @@ Ref<Font> Label3D::_get_font_or_default() const {
Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
if (f.is_valid()) {
theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
+ theme_font->connect_changed(callable_mp(const_cast<Label3D *>(this), &Label3D::_font_changed));
}
return f;
}
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 3ee08fd548..b4df06a83e 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -37,6 +37,7 @@
#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/camera_attributes.h"
#include "scene/resources/environment.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/sky.h"
void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) {
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 28a3cd0b13..0b0b098f65 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -31,7 +31,6 @@
#include "mesh_instance_3d.h"
#include "collision_shape_3d.h"
-#include "core/core_string_names.h"
#include "physics_body_3d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
@@ -111,7 +110,7 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) {
}
if (mesh.is_valid()) {
- mesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed));
+ mesh->disconnect_changed(callable_mp(this, &MeshInstance3D::_mesh_changed));
}
mesh = p_mesh;
@@ -120,7 +119,7 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) {
// If mesh is a PrimitiveMesh, calling get_rid on it can trigger a changed callback
// so do this before connecting _mesh_changed.
set_base(mesh->get_rid());
- mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed));
+ mesh->connect_changed(callable_mp(this, &MeshInstance3D::_mesh_changed));
_mesh_changed();
} else {
blend_shape_tracks.clear();
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 63a2ff5534..93acf38fa8 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -220,7 +220,7 @@ void NavigationAgent3D::_notification(int p_what) {
set_agent_parent(get_parent());
set_physics_process_internal(true);
- if (avoidance_enabled) {
+ if (agent_parent && avoidance_enabled) {
NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
}
@@ -273,11 +273,13 @@ void NavigationAgent3D::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+ if (agent_parent && avoidance_enabled) {
+ NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
+ }
if (agent_parent && target_position_submitted) {
if (velocity_submitted) {
velocity_submitted = false;
if (avoidance_enabled) {
- NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
if (!use_3d_avoidance) {
stored_y_velocity = velocity.y;
velocity.y = 0.0;
@@ -801,6 +803,11 @@ void NavigationAgent3D::update_navigation() {
navigation_path_index -= 1;
navigation_finished = true;
target_position_submitted = false;
+ if (avoidance_enabled) {
+ NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
+ NavigationServer3D::get_singleton()->agent_set_velocity(agent, Vector3(0.0, 0.0, 0.0));
+ NavigationServer3D::get_singleton()->agent_set_velocity_forced(agent, Vector3(0.0, 0.0, 0.0));
+ }
emit_signal(SNAME("navigation_finished"));
break;
}
diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp
index 2263d38d6c..70416ca93b 100644
--- a/scene/3d/navigation_link_3d.cpp
+++ b/scene/3d/navigation_link_3d.cpp
@@ -291,15 +291,7 @@ void NavigationLink3D::set_enabled(bool p_enabled) {
enabled = p_enabled;
- if (!is_inside_tree()) {
- return;
- }
-
- if (enabled) {
- NavigationServer3D::get_singleton()->link_set_map(link, get_world_3d()->get_navigation_map());
- } else {
- NavigationServer3D::get_singleton()->link_set_map(link, RID());
- }
+ NavigationServer3D::get_singleton()->link_set_enabled(link, enabled);
#ifdef DEBUG_ENABLED
if (debug_instance.is_valid() && debug_mesh.is_valid()) {
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 4c2f56b7b3..8d66f7ebeb 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -30,7 +30,6 @@
#include "navigation_region_3d.h"
-#include "core/core_string_names.h"
#include "scene/resources/navigation_mesh_source_geometry_data_3d.h"
#include "servers/navigation_server_3d.h"
@@ -41,15 +40,7 @@ void NavigationRegion3D::set_enabled(bool p_enabled) {
enabled = p_enabled;
- if (!is_inside_tree()) {
- return;
- }
-
- if (!enabled) {
- NavigationServer3D::get_singleton()->region_set_map(region, RID());
- } else {
- NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
- }
+ NavigationServer3D::get_singleton()->region_set_enabled(region, enabled);
#ifdef DEBUG_ENABLED
if (debug_instance.is_valid()) {
@@ -169,17 +160,7 @@ RID NavigationRegion3D::get_region_rid() const {
void NavigationRegion3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- if (enabled) {
- NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
- }
- current_global_transform = get_global_transform();
- NavigationServer3D::get_singleton()->region_set_transform(region, current_global_transform);
-
-#ifdef DEBUG_ENABLED
- if (NavigationServer3D::get_singleton()->get_debug_navigation_enabled()) {
- _update_debug_mesh();
- }
-#endif // DEBUG_ENABLED
+ _region_enter_navigation_map();
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -188,31 +169,11 @@ void NavigationRegion3D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
set_physics_process_internal(false);
- if (is_inside_tree()) {
- Transform3D new_global_transform = get_global_transform();
- if (current_global_transform != new_global_transform) {
- current_global_transform = new_global_transform;
- NavigationServer3D::get_singleton()->region_set_transform(region, current_global_transform);
-#ifdef DEBUG_ENABLED
- if (debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_transform(debug_instance, current_global_transform);
- }
-#endif // DEBUG_ENABLED
- }
- }
+ _region_update_transform();
} break;
case NOTIFICATION_EXIT_TREE: {
- NavigationServer3D::get_singleton()->region_set_map(region, RID());
-
-#ifdef DEBUG_ENABLED
- if (debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_visible(debug_instance, false);
- }
- if (debug_edge_connections_instance.is_valid()) {
- RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
- }
-#endif // DEBUG_ENABLED
+ _region_exit_navigation_map();
} break;
}
}
@@ -223,13 +184,13 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_naviga
}
if (navigation_mesh.is_valid()) {
- navigation_mesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed));
+ navigation_mesh->disconnect_changed(callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed));
}
navigation_mesh = p_navigation_mesh;
if (navigation_mesh.is_valid()) {
- navigation_mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed));
+ navigation_mesh->connect_changed(callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed));
}
NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, p_navigation_mesh);
@@ -260,6 +221,25 @@ Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const {
return navigation_mesh;
}
+void NavigationRegion3D::set_navigation_map(RID p_navigation_map) {
+ if (map_override == p_navigation_map) {
+ return;
+ }
+
+ map_override = p_navigation_map;
+
+ NavigationServer3D::get_singleton()->region_set_map(region, map_override);
+}
+
+RID NavigationRegion3D::get_navigation_map() const {
+ if (map_override.is_valid()) {
+ return map_override;
+ } else if (is_inside_tree()) {
+ return get_world_3d()->get_navigation_map();
+ }
+ return RID();
+}
+
struct BakeThreadsArgs {
NavigationRegion3D *nav_region = nullptr;
Ref<NavigationMeshSourceGeometryData3D> source_geometry_data;
@@ -273,11 +253,19 @@ void _bake_navigation_mesh(void *p_user_data) {
Ref<NavigationMeshSourceGeometryData3D> source_geometry_data = args->source_geometry_data;
NavigationServer3D::get_singleton()->bake_from_source_geometry_data(nav_mesh, source_geometry_data);
- args->nav_region->call_deferred(SNAME("_bake_finished"), nav_mesh);
+ if (!Thread::is_main_thread()) {
+ args->nav_region->call_deferred(SNAME("_bake_finished"), nav_mesh);
+ } else {
+ args->nav_region->_bake_finished(nav_mesh);
+ }
memdelete(args);
} else {
ERR_PRINT("Can't bake the navigation mesh if the `NavigationMesh` resource doesn't exist");
- args->nav_region->call_deferred(SNAME("_bake_finished"), Ref<NavigationMesh>());
+ if (!Thread::is_main_thread()) {
+ args->nav_region->call_deferred(SNAME("_bake_finished"), Ref<NavigationMesh>());
+ } else {
+ args->nav_region->_bake_finished(Ref<NavigationMesh>());
+ }
memdelete(args);
}
}
@@ -330,6 +318,9 @@ void NavigationRegion3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion3D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion3D::is_enabled);
+ ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationRegion3D::set_navigation_map);
+ ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationRegion3D::get_navigation_map);
+
ClassDB::bind_method(D_METHOD("set_use_edge_connections", "enabled"), &NavigationRegion3D::set_use_edge_connections);
ClassDB::bind_method(D_METHOD("get_use_edge_connections"), &NavigationRegion3D::get_use_edge_connections);
@@ -397,6 +388,58 @@ void NavigationRegion3D::_navigation_map_changed(RID p_map) {
}
#endif // DEBUG_ENABLED
+void NavigationRegion3D::_region_enter_navigation_map() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (enabled) {
+ if (map_override.is_valid()) {
+ NavigationServer3D::get_singleton()->region_set_map(region, map_override);
+ } else {
+ NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
+ }
+ }
+
+ current_global_transform = get_global_transform();
+ NavigationServer3D::get_singleton()->region_set_transform(region, current_global_transform);
+
+#ifdef DEBUG_ENABLED
+ if (NavigationServer3D::get_singleton()->get_debug_navigation_enabled()) {
+ _update_debug_mesh();
+ }
+#endif // DEBUG_ENABLED
+}
+
+void NavigationRegion3D::_region_exit_navigation_map() {
+ NavigationServer3D::get_singleton()->region_set_map(region, RID());
+#ifdef DEBUG_ENABLED
+ if (debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ }
+ if (debug_edge_connections_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
+ }
+#endif // DEBUG_ENABLED
+}
+
+void NavigationRegion3D::_region_update_transform() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ Transform3D new_global_transform = get_global_transform();
+ if (current_global_transform != new_global_transform) {
+ current_global_transform = new_global_transform;
+ NavigationServer3D::get_singleton()->region_set_transform(region, current_global_transform);
+#ifdef DEBUG_ENABLED
+ if (debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_transform(debug_instance, current_global_transform);
+ }
+#endif // DEBUG_ENABLED
+ }
+}
+
NavigationRegion3D::NavigationRegion3D() {
set_notify_transform(true);
@@ -418,7 +461,7 @@ NavigationRegion3D::~NavigationRegion3D() {
}
if (navigation_mesh.is_valid()) {
- navigation_mesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed));
+ navigation_mesh->disconnect_changed(callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed));
}
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
NavigationServer3D::get_singleton()->free(region);
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index 84b57d064f..e41d07f4cf 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -41,6 +41,7 @@ class NavigationRegion3D : public Node3D {
bool use_edge_connections = true;
RID region;
+ RID map_override;
uint32_t navigation_layers = 1;
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
@@ -77,6 +78,9 @@ public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
+ void set_navigation_map(RID p_navigation_map);
+ RID get_navigation_map() const;
+
void set_use_edge_connections(bool p_enabled);
bool get_use_edge_connections() const;
@@ -106,6 +110,11 @@ public:
NavigationRegion3D();
~NavigationRegion3D();
+
+private:
+ void _region_enter_navigation_map();
+ void _region_exit_navigation_map();
+ void _region_update_transform();
};
#endif // NAVIGATION_REGION_3D_H
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 8fd1df372b..7b535f6169 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -31,7 +31,6 @@
#include "occluder_instance_3d.h"
#include "core/config/project_settings.h"
-#include "core/core_string_names.h"
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/math/triangulate.h"
@@ -441,14 +440,14 @@ void OccluderInstance3D::set_occluder(const Ref<Occluder3D> &p_occluder) {
}
if (occluder.is_valid()) {
- occluder->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &OccluderInstance3D::_occluder_changed));
+ occluder->disconnect_changed(callable_mp(this, &OccluderInstance3D::_occluder_changed));
}
occluder = p_occluder;
if (occluder.is_valid()) {
set_base(occluder->get_rid());
- occluder->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &OccluderInstance3D::_occluder_changed));
+ occluder->connect_changed(callable_mp(this, &OccluderInstance3D::_occluder_changed));
} else {
set_base(RID());
}
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 9516973ae2..6aea063096 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -144,13 +144,13 @@ void Path3D::_curve_changed() {
void Path3D::set_curve(const Ref<Curve3D> &p_curve) {
if (curve.is_valid()) {
- curve->disconnect("changed", callable_mp(this, &Path3D::_curve_changed));
+ curve->disconnect_changed(callable_mp(this, &Path3D::_curve_changed));
}
curve = p_curve;
if (curve.is_valid()) {
- curve->connect("changed", callable_mp(this, &Path3D::_curve_changed));
+ curve->connect_changed(callable_mp(this, &Path3D::_curve_changed));
}
_curve_changed();
}
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 6b31aa0a3c..e49b43c650 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -30,7 +30,6 @@
#include "physics_body_3d.h"
-#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
void PhysicsBody3D::_bind_methods() {
@@ -214,15 +213,13 @@ real_t PhysicsBody3D::get_inverse_mass() const {
void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody3D::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody3D::_reload_physics_characteristics));
- }
+ physics_material_override->disconnect_changed(callable_mp(this, &StaticBody3D::_reload_physics_characteristics));
}
physics_material_override = p_physics_material_override;
if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody3D::_reload_physics_characteristics));
+ physics_material_override->connect_changed(callable_mp(this, &StaticBody3D::_reload_physics_characteristics));
}
_reload_physics_characteristics();
}
@@ -726,15 +723,13 @@ const Vector3 &RigidBody3D::get_center_of_mass() const {
void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
- }
+ physics_material_override->disconnect_changed(callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
}
physics_material_override = p_physics_material_override;
if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
+ physics_material_override->connect_changed(callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
}
_reload_physics_characteristics();
}
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 2dea6418ed..7b04669dad 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -223,6 +223,7 @@ void RayCast3D::_update_raycast_state() {
ray_params.collide_with_bodies = collide_with_bodies;
ray_params.collide_with_areas = collide_with_areas;
ray_params.hit_from_inside = hit_from_inside;
+ ray_params.hit_back_faces = hit_back_faces;
PhysicsDirectSpaceState3D::RayResult rr;
if (dss->intersect_ray(ray_params, rr)) {
@@ -297,6 +298,14 @@ bool RayCast3D::is_hit_from_inside_enabled() const {
return hit_from_inside;
}
+void RayCast3D::set_hit_back_faces(bool p_enabled) {
+ hit_back_faces = p_enabled;
+}
+
+bool RayCast3D::is_hit_back_faces_enabled() const {
+ return hit_back_faces;
+}
+
void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast3D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast3D::is_enabled);
@@ -339,6 +348,9 @@ void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hit_from_inside", "enable"), &RayCast3D::set_hit_from_inside);
ClassDB::bind_method(D_METHOD("is_hit_from_inside_enabled"), &RayCast3D::is_hit_from_inside_enabled);
+ ClassDB::bind_method(D_METHOD("set_hit_back_faces", "enable"), &RayCast3D::set_hit_back_faces);
+ ClassDB::bind_method(D_METHOD("is_hit_back_faces_enabled"), &RayCast3D::is_hit_back_faces_enabled);
+
ClassDB::bind_method(D_METHOD("set_debug_shape_custom_color", "debug_shape_custom_color"), &RayCast3D::set_debug_shape_custom_color);
ClassDB::bind_method(D_METHOD("get_debug_shape_custom_color"), &RayCast3D::get_debug_shape_custom_color);
@@ -350,6 +362,7 @@ void RayCast3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position", PROPERTY_HINT_NONE, "suffix:m"), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_from_inside"), "set_hit_from_inside", "is_hit_from_inside_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_back_faces"), "set_hit_back_faces", "is_hit_back_faces_enabled");
ADD_GROUP("Collide With", "collide_with");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
index e230d61628..1def7a0eca 100644
--- a/scene/3d/ray_cast_3d.h
+++ b/scene/3d/ray_cast_3d.h
@@ -69,6 +69,7 @@ class RayCast3D : public Node3D {
bool collide_with_bodies = true;
bool hit_from_inside = false;
+ bool hit_back_faces = true;
protected:
void _notification(int p_what);
@@ -85,6 +86,9 @@ public:
void set_hit_from_inside(bool p_enabled);
bool is_hit_from_inside_enabled() const;
+ void set_hit_back_faces(bool p_enabled);
+ bool is_hit_back_faces_enabled() const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp
index 75f94b36d3..b6401832ed 100644
--- a/scene/3d/shape_cast_3d.cpp
+++ b/scene/3d/shape_cast_3d.cpp
@@ -30,7 +30,6 @@
#include "shape_cast_3d.h"
-#include "core/core_string_names.h"
#include "scene/3d/collision_object_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
@@ -93,7 +92,9 @@ void ShapeCast3D::_notification(int p_what) {
}
void ShapeCast3D::_bind_methods() {
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &ShapeCast3D::resource_changed);
+#endif
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &ShapeCast3D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &ShapeCast3D::is_enabled);
@@ -312,12 +313,10 @@ real_t ShapeCast3D::get_closest_collision_unsafe_fraction() const {
return collision_unsafe_fraction;
}
+#ifndef DISABLE_DEPRECATED
void ShapeCast3D::resource_changed(Ref<Resource> p_res) {
- if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
- _update_debug_shape();
- }
- update_gizmos();
}
+#endif
void ShapeCast3D::_shape_changed() {
update_gizmos();
@@ -332,13 +331,11 @@ void ShapeCast3D::set_shape(const Ref<Shape3D> &p_shape) {
return;
}
if (shape.is_valid()) {
- shape->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &ShapeCast3D::_shape_changed));
- shape->unregister_owner(this);
+ shape->disconnect_changed(callable_mp(this, &ShapeCast3D::_shape_changed));
}
shape = p_shape;
if (shape.is_valid()) {
- shape->register_owner(this);
- shape->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &ShapeCast3D::_shape_changed));
+ shape->connect_changed(callable_mp(this, &ShapeCast3D::_shape_changed));
shape_rid = shape->get_rid();
}
@@ -633,9 +630,3 @@ void ShapeCast3D::_clear_debug_shape() {
debug_shape = nullptr;
}
-
-ShapeCast3D::~ShapeCast3D() {
- if (!shape.is_null()) {
- shape->unregister_owner(this);
- }
-}
diff --git a/scene/3d/shape_cast_3d.h b/scene/3d/shape_cast_3d.h
index 98158d3c7c..043e35090f 100644
--- a/scene/3d/shape_cast_3d.h
+++ b/scene/3d/shape_cast_3d.h
@@ -40,7 +40,9 @@ class ShapeCast3D : public Node3D {
GDCLASS(ShapeCast3D, Node3D);
bool enabled = true;
+#ifndef DISABLE_DEPRECATED
void resource_changed(Ref<Resource> p_res);
+#endif
Ref<Shape3D> shape;
RID shape_rid;
@@ -74,8 +76,6 @@ class ShapeCast3D : public Node3D {
Array _get_collision_result() const;
- ~ShapeCast3D();
-
protected:
void _notification(int p_what);
void _update_shapecast_state();
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 51359059ef..445c1003b5 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -887,7 +887,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
skin_bindings.insert(skin_ref.operator->());
- skin_ref->skin->connect("changed", callable_mp(skin_ref.operator->(), &SkinReference::_skin_changed));
+ skin_ref->skin->connect_changed(callable_mp(skin_ref.operator->(), &SkinReference::_skin_changed));
_make_dirty(); // Skin needs to be updated, so update skeleton.
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 9f7ff05924..1345cfcdb8 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -30,6 +30,7 @@
#include "sprite_3d.h"
+#include "scene/resources/atlas_texture.h"
#include "scene/scene_string_names.h"
Color SpriteBase3D::_get_color_accum() {
@@ -372,7 +373,7 @@ void SpriteBase3D::_queue_redraw() {
update_gizmos();
pending_update = true;
- call_deferred(SceneStringNames::get_singleton()->_im_update);
+ callable_mp(this, &SpriteBase3D::_im_update).call_deferred();
}
AABB SpriteBase3D::get_aabb() const {
@@ -577,8 +578,6 @@ void SpriteBase3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh);
- ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update);
-
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
@@ -647,11 +646,11 @@ SpriteBase3D::SpriteBase3D() {
// Create basic mesh and store format information.
for (int i = 0; i < 4; i++) {
- mesh_normals.write[i] = Vector3(0.0, 0.0, 0.0);
- mesh_tangents.write[i * 4 + 0] = 0.0;
+ mesh_normals.write[i] = Vector3(0.0, 0.0, 1.0);
+ mesh_tangents.write[i * 4 + 0] = 1.0;
mesh_tangents.write[i * 4 + 1] = 0.0;
mesh_tangents.write[i * 4 + 2] = 0.0;
- mesh_tangents.write[i * 4 + 3] = 0.0;
+ mesh_tangents.write[i * 4 + 3] = 1.0;
mesh_colors.write[i] = Color(1.0, 1.0, 1.0, 1.0);
mesh_uvs.write[i] = Vector2(0.0, 0.0);
mesh_vertices.write[i] = Vector3(0.0, 0.0, 0.0);
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 6a76b5ac16..715d8a5bc1 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -1010,6 +1010,7 @@ double AnimationNodeTransition::_process(double p_time, bool p_seek, bool p_is_e
}
double rem = 0.0;
+ double abs_time = Math::abs(p_time);
if (sync) {
for (int i = 0; i < get_input_count(); i++) {
@@ -1024,9 +1025,9 @@ double AnimationNodeTransition::_process(double p_time, bool p_seek, bool p_is_e
rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
if (p_seek) {
- cur_time = p_time;
+ cur_time = abs_time;
} else {
- cur_time += p_time;
+ cur_time += abs_time;
}
if (input_data[cur_current_index].auto_advance && rem <= xfade_time) {
@@ -1058,10 +1059,10 @@ double AnimationNodeTransition::_process(double p_time, bool p_seek, bool p_is_e
blend_input(cur_prev_index, p_time, use_blend && p_seek, p_is_external_seeking, blend, FILTER_IGNORE, true, p_test_only);
if (p_seek) {
- cur_time = p_time;
+ cur_time = abs_time;
} else {
- cur_time += p_time;
- cur_prev_xfading -= p_time;
+ cur_time += abs_time;
+ cur_prev_xfading -= abs_time;
if (cur_prev_xfading < 0) {
set_parameter(prev_index, -1);
}
@@ -1142,7 +1143,7 @@ void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNod
p_node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed), CONNECT_REFERENCE_COUNTED);
p_node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed), CONNECT_REFERENCE_COUNTED);
p_node->connect("animation_node_removed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed), CONNECT_REFERENCE_COUNTED);
- p_node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_name), CONNECT_REFERENCE_COUNTED);
+ p_node->connect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_name), CONNECT_REFERENCE_COUNTED);
}
Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const {
@@ -1178,8 +1179,6 @@ void AnimationNodeBlendTree::get_child_nodes(List<ChildNode> *r_child_nodes) {
ns.push_back(E.key);
}
- ns.sort_custom<StringName::AlphCompare>();
-
for (int i = 0; i < ns.size(); i++) {
ChildNode cn;
cn.name = ns[i];
@@ -1206,7 +1205,7 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed));
node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed));
node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed));
- node->disconnect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed));
+ node->disconnect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed));
}
nodes.erase(p_name);
@@ -1231,7 +1230,7 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(p_new_name == SceneStringNames::get_singleton()->output);
- nodes[p_name].node->disconnect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed));
+ nodes[p_name].node->disconnect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed));
nodes[p_new_name] = nodes[p_name];
nodes.erase(p_name);
@@ -1245,7 +1244,7 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN
}
}
// Connection must be done with new name.
- nodes[p_new_name].node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_new_name), CONNECT_REFERENCE_COUNTED);
+ nodes[p_new_name].node->connect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_new_name), CONNECT_REFERENCE_COUNTED);
emit_signal(SNAME("animation_node_renamed"), get_instance_id(), p_name, p_new_name);
emit_signal(SNAME("tree_changed"));
@@ -1435,7 +1434,6 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
for (const KeyValue<StringName, Node> &E : nodes) {
names.push_back(E.key);
}
- names.sort_custom<StringName::AlphCompare>();
for (const StringName &E : names) {
String prop_name = E;
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 2139af8a96..bf95c211f6 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -388,7 +388,7 @@ class AnimationNodeBlendTree : public AnimationRootNode {
Vector<StringName> connections;
};
- HashMap<StringName, Node> nodes;
+ RBMap<StringName, Node, StringName::AlphCompare> nodes;
Vector2 graph_offset;
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 071e2e7f37..0254419d22 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -901,18 +901,20 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT
bool is_state_changed = false;
NextInfo next;
- StringName transition_start = current;
+ Vector<StringName> transition_path;
+ transition_path.push_back(current);
while (true) {
next = _find_next(p_tree, p_state_machine);
- if (next.node == transition_start) {
- is_state_changed = false;
- break; // Maybe infinity loop, do noting more.
+ if (transition_path.has(next.node)) {
+ WARN_PRINT_ONCE_ED("AnimationNodeStateMachinePlayback: " + base_path + "playback aborts the transition by detecting one or more looped transitions in the same frame to prevent to infinity loop. You may need to check the transition settings.");
+ break; // Maybe infinity loop, do nothing more.
}
if (!_can_transition_to_next(p_tree, p_state_machine, next, p_test_only)) {
break; // Finish transition.
}
+ transition_path.push_back(next.node);
is_state_changed = true;
// Setting for fading.
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 96e5da5a40..b32b04655d 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -284,10 +284,6 @@ bool Tween::step(double p_delta) {
return false;
}
- if (!running) {
- return true;
- }
-
if (is_bound) {
Node *node = get_bound_node();
if (node) {
@@ -299,6 +295,10 @@ bool Tween::step(double p_delta) {
}
}
+ if (!running) {
+ return true;
+ }
+
if (!started) {
if (tweeners.is_empty()) {
String tween_id;
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index 391388fc04..4b097412d6 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -163,6 +163,7 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra
live_editor->_res_set_func(p_args[0], p_args[1], p_args[2]);
} else if (p_msg == "live_node_call") {
+ ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
LocalVector<Variant> args;
LocalVector<Variant *> argptrs;
args.resize(p_args.size() - 2);
@@ -171,11 +172,10 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra
args[i] = p_args[i + 2];
argptrs[i] = &args[i];
}
- live_editor->_node_call_func(p_args[0], p_args[1], (const Variant **)argptrs.ptr(), argptrs.size());
+ live_editor->_node_call_func(p_args[0], p_args[1], argptrs.size() ? (const Variant **)argptrs.ptr() : nullptr, argptrs.size());
} else if (p_msg == "live_res_call") {
- ERR_FAIL_COND_V(p_args.size() < 10, ERR_INVALID_DATA);
-
+ ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
LocalVector<Variant> args;
LocalVector<Variant *> argptrs;
args.resize(p_args.size() - 2);
@@ -184,7 +184,7 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra
args[i] = p_args[i + 2];
argptrs[i] = &args[i];
}
- live_editor->_res_call_func(p_args[0], p_args[1], (const Variant **)argptrs.ptr(), argptrs.size());
+ live_editor->_res_call_func(p_args[0], p_args[1], argptrs.size() ? (const Variant **)argptrs.ptr() : nullptr, argptrs.size());
} else if (p_msg == "live_create_node") {
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 5804d3250d..430569432a 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -30,7 +30,6 @@
#include "button.h"
-#include "core/core_string_names.h"
#include "core/string/translation.h"
#include "servers/rendering_server.h"
@@ -327,11 +326,8 @@ void Button::_notification(int p_what) {
if (align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER && icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) {
icon_ofs.x = 0.0;
}
- int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width;
- text_buf->set_width((clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? text_clip : -1);
-
- int text_width = MAX(1, (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x);
+ int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width;
if (_internal_margin[SIDE_LEFT] > 0) {
text_clip -= _internal_margin[SIDE_LEFT] + theme_cache.h_separation;
}
@@ -339,6 +335,10 @@ void Button::_notification(int p_what) {
text_clip -= _internal_margin[SIDE_RIGHT] + theme_cache.h_separation;
}
+ text_buf->set_width((clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? text_clip : -1);
+
+ int text_width = MAX(1, (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x);
+
Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_LEFT], 0)) / 2.0;
if (vertical_icon_alignment == VERTICAL_ALIGNMENT_TOP) {
@@ -539,13 +539,13 @@ void Button::set_icon(const Ref<Texture2D> &p_icon) {
}
if (icon.is_valid()) {
- icon->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Button::_texture_changed));
+ icon->disconnect_changed(callable_mp(this, &Button::_texture_changed));
}
icon = p_icon;
if (icon.is_valid()) {
- icon->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Button::_texture_changed));
+ icon->connect_changed(callable_mp(this, &Button::_texture_changed));
}
queue_redraw();
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 1944b8db98..eee59606e3 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -2258,9 +2258,8 @@ bool CodeEdit::is_symbol_lookup_on_click_enabled() const {
return symbol_lookup_on_click_enabled;
}
-String CodeEdit::get_text_for_symbol_lookup() {
+String CodeEdit::get_text_for_symbol_lookup() const {
Point2i mp = get_local_mouse_pos();
-
Point2i pos = get_line_column_at_pos(mp, false);
int line = pos.y;
int col = pos.x;
@@ -2269,25 +2268,29 @@ String CodeEdit::get_text_for_symbol_lookup() {
return String();
}
- StringBuilder lookup_text;
+ return get_text_with_cursor_char(line, col);
+}
+
+String CodeEdit::get_text_with_cursor_char(int p_line, int p_column) const {
const int text_size = get_line_count();
+ StringBuilder result;
for (int i = 0; i < text_size; i++) {
String line_text = get_line(i);
-
- if (i == line) {
- lookup_text += line_text.substr(0, col);
+ if (i == p_line && p_column >= 0 && p_column <= line_text.size()) {
+ result += line_text.substr(0, p_column);
/* Not unicode, represents the cursor. */
- lookup_text += String::chr(0xFFFF);
- lookup_text += line_text.substr(col, line_text.size());
+ result += String::chr(0xFFFF);
+ result += line_text.substr(p_column, line_text.size());
} else {
- lookup_text += line_text;
+ result += line_text;
}
if (i != text_size - 1) {
- lookup_text += "\n";
+ result += "\n";
}
}
- return lookup_text.as_string();
+
+ return result.as_string();
}
void CodeEdit::set_symbol_lookup_word_as_valid(bool p_valid) {
@@ -2472,6 +2475,7 @@ void CodeEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_symbol_lookup_on_click_enabled"), &CodeEdit::is_symbol_lookup_on_click_enabled);
ClassDB::bind_method(D_METHOD("get_text_for_symbol_lookup"), &CodeEdit::get_text_for_symbol_lookup);
+ ClassDB::bind_method(D_METHOD("get_text_with_cursor_char", "line", "column"), &CodeEdit::get_text_with_cursor_char);
ClassDB::bind_method(D_METHOD("set_symbol_lookup_word_as_valid", "valid"), &CodeEdit::set_symbol_lookup_word_as_valid);
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 6933eb9392..a3c968da60 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -455,7 +455,8 @@ public:
void set_symbol_lookup_on_click_enabled(bool p_enabled);
bool is_symbol_lookup_on_click_enabled() const;
- String get_text_for_symbol_lookup();
+ String get_text_for_symbol_lookup() const;
+ String get_text_with_cursor_char(int p_line, int p_column) const;
void set_symbol_lookup_word_as_valid(bool p_valid);
diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp
index 38e6048b91..adea06eee7 100644
--- a/scene/gui/color_mode.cpp
+++ b/scene/gui/color_mode.cpp
@@ -105,6 +105,17 @@ void ColorModeRGB::slider_draw(int p_which) {
slider->draw_polygon(pos, col);
}
+void ColorModeHSV::_value_changed() {
+ Vector<float> values = color_picker->get_active_slider_values();
+
+ if (values[1] > 0 || values[0] != cached_hue) {
+ cached_hue = values[0];
+ }
+ if (values[2] > 0 || values[1] != cached_saturation) {
+ cached_saturation = values[1];
+ }
+}
+
String ColorModeHSV::get_slider_label(int idx) const {
ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label.");
return labels[idx];
@@ -121,14 +132,14 @@ float ColorModeHSV::get_slider_value(int idx) const {
if (color_picker->get_pick_color().get_s() > 0) {
return color_picker->get_pick_color().get_h() * 360.0;
} else {
- return color_picker->get_cached_hue();
+ return cached_hue;
}
}
case 1: {
if (color_picker->get_pick_color().get_v() > 0) {
return color_picker->get_pick_color().get_s() * 100.0;
} else {
- return color_picker->get_cached_saturation();
+ return cached_saturation;
}
}
case 2:
@@ -167,16 +178,16 @@ void ColorModeHSV::slider_draw(int p_which) {
right_color = color;
right_color.a = 1;
} else if (p_which == 0) {
- Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
- slider->draw_texture_rect(hue, Rect2(Vector2(), Vector2(size.x, margin)), false);
- return;
+ float v = color.get_v();
+ left_color = Color(v, v, v);
+ right_color = left_color;
} else {
Color s_col;
Color v_col;
s_col.set_hsv(color.get_h(), 0, color.get_v());
left_color = (p_which == 1) ? s_col : Color(0, 0, 0);
- float s_col_hue = (color.get_s() == 0.0) ? color_picker->get_cached_hue() / 360.0 : color.get_h();
+ float s_col_hue = (Math::is_zero_approx(color.get_s())) ? cached_hue / 360.0 : color.get_h();
s_col.set_hsv(s_col_hue, 1, color.get_v());
v_col.set_hsv(color.get_h(), color.get_s(), 1);
right_color = (p_which == 1) ? s_col : v_col;
@@ -191,6 +202,11 @@ void ColorModeHSV::slider_draw(int p_which) {
pos.set(3, Vector2(0, margin));
slider->draw_polygon(pos, col);
+
+ if (p_which == 0) { // H
+ Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
+ slider->draw_texture_rect(hue, Rect2(Vector2(), Vector2(size.x, margin)), false, Color::from_hsv(0, 0, color.get_v(), color.get_s()));
+ }
}
String ColorModeRAW::get_slider_label(int idx) const {
@@ -262,6 +278,17 @@ bool ColorModeRAW::apply_theme() const {
return true;
}
+void ColorModeOKHSL::_value_changed() {
+ Vector<float> values = color_picker->get_active_slider_values();
+
+ if (values[1] > 0 || values[0] != cached_hue) {
+ cached_hue = values[0];
+ }
+ if (values[2] > 0 || values[1] != cached_saturation) {
+ cached_saturation = values[1];
+ }
+}
+
String ColorModeOKHSL::get_slider_label(int idx) const {
ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label.");
return labels[idx];
@@ -274,10 +301,20 @@ float ColorModeOKHSL::get_slider_max(int idx) const {
float ColorModeOKHSL::get_slider_value(int idx) const {
switch (idx) {
- case 0:
- return color_picker->get_pick_color().get_ok_hsl_h() * 360.0;
- case 1:
- return color_picker->get_pick_color().get_ok_hsl_s() * 100.0;
+ case 0: {
+ if (color_picker->get_pick_color().get_ok_hsl_s() > 0) {
+ return color_picker->get_pick_color().get_ok_hsl_h() * 360.0;
+ } else {
+ return cached_hue;
+ }
+ }
+ case 1: {
+ if (color_picker->get_pick_color().get_ok_hsl_l() > 0) {
+ return color_picker->get_pick_color().get_ok_hsl_s() * 100.0;
+ } else {
+ return cached_saturation;
+ }
+ }
case 2:
return color_picker->get_pick_color().get_ok_hsl_l() * 100.0;
case 3:
@@ -299,12 +336,6 @@ void ColorModeOKHSL::slider_draw(int p_which) {
Size2 size = slider->get_size();
const real_t margin = 16 * color_picker->get_theme_default_base_scale();
- if (p_which == 0) { // H
- Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_okhsl_hue"), SNAME("ColorPicker"));
- slider->draw_texture_rect(hue, Rect2(Vector2(), Vector2(size.x, margin)), false);
- return;
- }
-
Vector<Vector2> pos;
Vector<Color> col;
Color left_color;
@@ -316,8 +347,11 @@ void ColorModeOKHSL::slider_draw(int p_which) {
col.resize(6);
left_color = Color(0, 0, 0);
Color middle_color;
- middle_color.set_ok_hsl(color.get_ok_hsl_h(), color.get_ok_hsl_s(), 0.5);
- right_color.set_ok_hsl(color.get_ok_hsl_h(), color.get_ok_hsl_s(), 1);
+ float slider_hue = (Math::is_zero_approx(color.get_ok_hsl_s())) ? cached_hue / 360.0 : color.get_ok_hsl_h();
+ float slider_sat = (Math::is_zero_approx(color.get_ok_hsl_l())) ? cached_saturation / 100.0 : color.get_ok_hsl_s();
+
+ middle_color.set_ok_hsl(slider_hue, slider_sat, 0.5);
+ right_color.set_ok_hsl(slider_hue, slider_sat, 1);
col.set(0, left_color);
col.set(1, middle_color);
@@ -331,7 +365,7 @@ void ColorModeOKHSL::slider_draw(int p_which) {
pos.set(3, Vector2(size.x, margin));
pos.set(4, Vector2(size.x * 0.5, margin));
pos.set(5, Vector2(0, margin));
- } else { // A / S
+ } else {
pos.resize(4);
col.resize(4);
@@ -342,9 +376,14 @@ void ColorModeOKHSL::slider_draw(int p_which) {
left_color.a = 0;
right_color = color;
right_color.a = 1;
+ } else if (p_which == 0) {
+ float l = color.get_ok_hsl_l();
+ left_color = Color(l, l, l);
+ right_color = left_color;
} else {
left_color.set_ok_hsl(color.get_ok_hsl_h(), 0, color.get_ok_hsl_l());
- right_color.set_ok_hsl(color.get_ok_hsl_h(), 1, color.get_ok_hsl_l());
+ float s_col_hue = (Math::is_zero_approx(color.get_ok_hsl_s())) ? cached_hue / 360.0 : color.get_ok_hsl_h();
+ right_color.set_ok_hsl(s_col_hue, 1, color.get_ok_hsl_l());
}
col.set(0, left_color);
@@ -358,4 +397,10 @@ 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"));
+ 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_mode.h b/scene/gui/color_mode.h
index f681df61d2..bbbf3fbaac 100644
--- a/scene/gui/color_mode.h
+++ b/scene/gui/color_mode.h
@@ -49,6 +49,8 @@ public:
virtual Color get_color() const = 0;
+ virtual void _value_changed(){};
+
virtual void slider_draw(int p_which) = 0;
virtual bool apply_theme() const { return false; }
virtual ColorPicker::PickerShapeType get_shape_override() const { return ColorPicker::SHAPE_MAX; }
@@ -61,6 +63,8 @@ class ColorModeHSV : public ColorMode {
public:
String labels[3] = { "H", "S", "V" };
float slider_max[4] = { 359, 100, 100, 255 };
+ float cached_hue = 0.0;
+ float cached_saturation = 0.0;
virtual String get_name() const override { return "HSV"; }
@@ -71,6 +75,8 @@ public:
virtual Color get_color() const override;
+ virtual void _value_changed() override;
+
virtual void slider_draw(int p_which) override;
ColorModeHSV(ColorPicker *p_color_picker) :
@@ -121,6 +127,8 @@ class ColorModeOKHSL : public ColorMode {
public:
String labels[3] = { "H", "S", "L" };
float slider_max[4] = { 359, 100, 100, 255 };
+ float cached_hue = 0.0;
+ float cached_saturation = 0.0;
virtual String get_name() const override { return "OKHSL"; }
@@ -131,6 +139,8 @@ public:
virtual Color get_color() const override;
+ virtual void _value_changed() override;
+
virtual void slider_draw(int p_which) override;
virtual ColorPicker::PickerShapeType get_shape_override() const override { return ColorPicker::SHAPE_OKHSL_CIRCLE; }
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 604f09a3d9..2a0f85a1be 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -36,6 +36,9 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "scene/gui/color_mode.h"
+#include "scene/resources/image_texture.h"
+#include "scene/resources/style_box_flat.h"
+#include "scene/resources/style_box_texture.h"
#include "servers/display_server.h"
#include "thirdparty/misc/ok_color.h"
#include "thirdparty/misc/ok_color_shader.h"
@@ -375,15 +378,7 @@ void ColorPicker::_value_changed(double) {
}
color = modes[current_mode]->get_color();
-
- if (current_mode == MODE_HSV) {
- if (sliders[1]->get_value() > 0 || sliders[0]->get_value() != cached_hue) {
- cached_hue = sliders[0]->get_value();
- }
- if (sliders[2]->get_value() > 0 || sliders[1]->get_value() != cached_saturation) {
- cached_saturation = sliders[1]->get_value();
- }
- }
+ modes[current_mode]->_value_changed();
if (current_mode == MODE_HSV || current_mode == MODE_OKHSL) {
h = sliders[0]->get_value() / 360.0;
@@ -564,7 +559,7 @@ void ColorPicker::_html_submitted(const String &p_html) {
}
const Color previous_color = color;
- color = Color::from_string(p_html, previous_color);
+ color = Color::from_string(p_html.strip_edges(), previous_color);
if (!is_editing_alpha()) {
color.a = previous_color.a;
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 425213be90..1a4b1b6ee1 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -46,6 +46,7 @@
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
#include "scene/gui/texture_rect.h"
+#include "scene/resources/style_box_flat.h"
class ColorMode;
class ColorModeRGB;
@@ -204,8 +205,6 @@ private:
float h = 0.0;
float s = 0.0;
float v = 0.0;
- float cached_hue = 0.0;
- float cached_saturation = 0.0;
Color last_color;
struct ThemeCache {
@@ -296,9 +295,6 @@ public:
#ifdef TOOLS_ENABLED
void set_editor_settings(Object *p_editor_settings);
#endif
- float get_cached_hue() { return cached_hue; };
- float get_cached_saturation() { return cached_saturation; };
-
HSlider *get_slider(int idx);
Vector<float> get_active_slider_values();
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 78862364d5..0ca04faf9b 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -271,21 +271,21 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) {
if (name.begins_with("theme_override_icons/")) {
String dname = name.get_slicec('/', 1);
if (data.theme_icon_override.has(dname)) {
- data.theme_icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ data.theme_icon_override[dname]->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
data.theme_icon_override.erase(dname);
_notify_theme_override_changed();
} else if (name.begins_with("theme_override_styles/")) {
String dname = name.get_slicec('/', 1);
if (data.theme_style_override.has(dname)) {
- data.theme_style_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ data.theme_style_override[dname]->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
data.theme_style_override.erase(dname);
_notify_theme_override_changed();
} else if (name.begins_with("theme_override_fonts/")) {
String dname = name.get_slicec('/', 1);
if (data.theme_font_override.has(dname)) {
- data.theme_font_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ data.theme_font_override[dname]->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
data.theme_font_override.erase(dname);
_notify_theme_override_changed();
@@ -2468,13 +2468,13 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
}
if (data.theme.is_valid()) {
- data.theme->disconnect("changed", callable_mp(this, &Control::_theme_changed));
+ data.theme->disconnect_changed(callable_mp(this, &Control::_theme_changed));
}
data.theme = p_theme;
if (data.theme.is_valid()) {
data.theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true);
- data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
+ data.theme->connect_changed(callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
return;
}
@@ -2769,11 +2769,11 @@ void Control::add_theme_icon_override(const StringName &p_name, const Ref<Textur
ERR_FAIL_COND(!p_icon.is_valid());
if (data.theme_icon_override.has(p_name)) {
- data.theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ data.theme_icon_override[p_name]->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
data.theme_icon_override[p_name] = p_icon;
- data.theme_icon_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ data.theme_icon_override[p_name]->connect_changed(callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
_notify_theme_override_changed();
}
@@ -2782,11 +2782,11 @@ void Control::add_theme_style_override(const StringName &p_name, const Ref<Style
ERR_FAIL_COND(!p_style.is_valid());
if (data.theme_style_override.has(p_name)) {
- data.theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ data.theme_style_override[p_name]->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
data.theme_style_override[p_name] = p_style;
- data.theme_style_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ data.theme_style_override[p_name]->connect_changed(callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
_notify_theme_override_changed();
}
@@ -2795,11 +2795,11 @@ void Control::add_theme_font_override(const StringName &p_name, const Ref<Font>
ERR_FAIL_COND(!p_font.is_valid());
if (data.theme_font_override.has(p_name)) {
- data.theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ data.theme_font_override[p_name]->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
data.theme_font_override[p_name] = p_font;
- data.theme_font_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ data.theme_font_override[p_name]->connect_changed(callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
_notify_theme_override_changed();
}
@@ -2824,7 +2824,7 @@ void Control::add_theme_constant_override(const StringName &p_name, int p_consta
void Control::remove_theme_icon_override(const StringName &p_name) {
ERR_MAIN_THREAD_GUARD;
if (data.theme_icon_override.has(p_name)) {
- data.theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ data.theme_icon_override[p_name]->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
data.theme_icon_override.erase(p_name);
@@ -2834,7 +2834,7 @@ void Control::remove_theme_icon_override(const StringName &p_name) {
void Control::remove_theme_style_override(const StringName &p_name) {
ERR_MAIN_THREAD_GUARD;
if (data.theme_style_override.has(p_name)) {
- data.theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ data.theme_style_override[p_name]->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
data.theme_style_override.erase(p_name);
@@ -2844,7 +2844,7 @@ void Control::remove_theme_style_override(const StringName &p_name) {
void Control::remove_theme_font_override(const StringName &p_name) {
ERR_MAIN_THREAD_GUARD;
if (data.theme_font_override.has(p_name)) {
- data.theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ data.theme_font_override[p_name]->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
data.theme_font_override.erase(p_name);
@@ -3630,13 +3630,13 @@ Control::~Control() {
// Resources need to be disconnected.
for (KeyValue<StringName, Ref<Texture2D>> &E : data.theme_icon_override) {
- E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ E.value->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
for (KeyValue<StringName, Ref<StyleBox>> &E : data.theme_style_override) {
- E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ E.value->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
for (KeyValue<StringName, Ref<Font>> &E : data.theme_font_override) {
- E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ E.value->disconnect_changed(callable_mp(this, &Control::_notify_theme_override_changed));
}
// Then override maps can be simply cleared.
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 9e99bda60b..902b76c5a7 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -44,6 +44,12 @@ void AcceptDialog::_input_from_window(const Ref<InputEvent> &p_event) {
}
}
+void AcceptDialog::_parent_focused() {
+ if (close_on_escape && !is_exclusive()) {
+ _cancel_pressed();
+ }
+}
+
void AcceptDialog::_update_theme_item_cache() {
Window::_update_theme_item_cache();
@@ -64,6 +70,16 @@ void AcceptDialog::_notification(int p_what) {
get_ok_button()->grab_focus();
}
_update_child_rects();
+
+ parent_visible = get_parent_visible_window();
+ if (parent_visible) {
+ parent_visible->connect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
+ }
+ } else {
+ if (parent_visible) {
+ parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
+ parent_visible = nullptr;
+ }
}
} break;
@@ -76,9 +92,10 @@ void AcceptDialog::_notification(int p_what) {
}
} break;
- case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
- if (close_on_escape && !is_exclusive()) {
- _cancel_pressed();
+ case NOTIFICATION_EXIT_TREE: {
+ if (parent_visible) {
+ parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
+ parent_visible = nullptr;
}
} break;
@@ -112,9 +129,21 @@ void AcceptDialog::_ok_pressed() {
}
void AcceptDialog::_cancel_pressed() {
+ Window *parent_window = parent_visible;
+ if (parent_visible) {
+ parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
+ parent_visible = nullptr;
+ }
+
call_deferred(SNAME("hide"));
+
emit_signal(SNAME("canceled"));
+
cancel_pressed();
+
+ if (parent_window) {
+ //parent_window->grab_focus();
+ }
set_input_as_handled();
}
@@ -257,18 +286,29 @@ void AcceptDialog::_custom_action(const String &p_action) {
custom_action(p_action);
}
+void AcceptDialog::_custom_button_visibility_changed(Button *button) {
+ Control *right_spacer = Object::cast_to<Control>(button->get_meta("__right_spacer"));
+ if (right_spacer) {
+ right_spacer->set_visible(button->is_visible());
+ }
+}
+
Button *AcceptDialog::add_button(const String &p_text, bool p_right, const String &p_action) {
Button *button = memnew(Button);
button->set_text(p_text);
+ Control *right_spacer;
if (p_right) {
buttons_hbox->add_child(button);
- buttons_hbox->add_spacer();
+ right_spacer = buttons_hbox->add_spacer();
} else {
buttons_hbox->add_child(button);
buttons_hbox->move_child(button, 0);
- buttons_hbox->add_spacer(true);
+ right_spacer = buttons_hbox->add_spacer(true);
}
+ button->set_meta("__right_spacer", right_spacer);
+
+ button->connect("visibility_changed", callable_mp(this, &AcceptDialog::_custom_button_visibility_changed).bind(button));
child_controls_changed();
if (is_visible()) {
@@ -301,6 +341,12 @@ void AcceptDialog::remove_button(Control *p_button) {
ERR_FAIL_COND_MSG(button->get_parent() != buttons_hbox, vformat("Cannot remove button %s as it does not belong to this dialog.", button->get_name()));
ERR_FAIL_COND_MSG(button == ok_button, "Cannot remove dialog's OK button.");
+ Control *right_spacer = Object::cast_to<Control>(button->get_meta("__right_spacer"));
+ if (right_spacer) {
+ ERR_FAIL_COND_MSG(right_spacer->get_parent() != buttons_hbox, vformat("Cannot remove button %s as its associated spacer does not belong to this dialog.", button->get_name()));
+ }
+
+ button->disconnect("visibility_changed", callable_mp(this, &AcceptDialog::_custom_button_visibility_changed));
if (button->is_connected("pressed", callable_mp(this, &AcceptDialog::_custom_action))) {
button->disconnect("pressed", callable_mp(this, &AcceptDialog::_custom_action));
}
@@ -308,11 +354,10 @@ void AcceptDialog::remove_button(Control *p_button) {
button->disconnect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
}
- Node *right_spacer = buttons_hbox->get_child(button->get_index() + 1);
- // Should always be valid but let's avoid crashing.
if (right_spacer) {
buttons_hbox->remove_child(right_spacer);
- memdelete(right_spacer);
+ button->remove_meta("__right_spacer");
+ right_spacer->queue_free();
}
buttons_hbox->remove_child(button);
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index ebe5ce326a..109c7172d0 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -44,6 +44,8 @@ class LineEdit;
class AcceptDialog : public Window {
GDCLASS(AcceptDialog, Window);
+ Window *parent_visible = nullptr;
+
Panel *bg_panel = nullptr;
Label *message_label = nullptr;
HBoxContainer *buttons_hbox = nullptr;
@@ -58,11 +60,13 @@ class AcceptDialog : public Window {
} theme_cache;
void _custom_action(const String &p_action);
+ void _custom_button_visibility_changed(Button *button);
void _update_child_rects();
static bool swap_cancel_ok;
void _input_from_window(const Ref<InputEvent> &p_event);
+ void _parent_focused();
protected:
virtual Size2 _get_contents_minimum_size() const override;
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index e1309020a7..d4da4797eb 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -54,6 +54,38 @@ void FileDialog::_focus_file_text() {
}
}
+void FileDialog::popup(const Rect2i &p_rect) {
+ if (access == ACCESS_FILESYSTEM && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
+ DisplayServer::get_singleton()->file_dialog_show(get_title(), dir->get_text(), file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, callable_mp(this, &FileDialog::_native_dialog_cb));
+ } else {
+ ConfirmationDialog::popup(p_rect);
+ }
+}
+
+void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files) {
+ if (p_ok) {
+ if (p_files.size() > 0) {
+ String f = p_files[0];
+ if (mode == FILE_MODE_OPEN_FILES) {
+ emit_signal(SNAME("files_selected"), p_files);
+ } else {
+ if (mode == FILE_MODE_SAVE_FILE) {
+ emit_signal(SNAME("file_selected"), f);
+ } else if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
+ emit_signal(SNAME("file_selected"), f);
+ } else if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_DIR) {
+ emit_signal(SNAME("dir_selected"), f);
+ }
+ }
+ file->set_text(f);
+ dir->set_text(f.get_base_dir());
+ }
+ } else {
+ file->set_text("");
+ emit_signal(SNAME("canceled"));
+ }
+}
+
VBoxContainer *FileDialog::get_vbox() {
return vbox;
}
@@ -833,6 +865,8 @@ void FileDialog::set_file_mode(FileMode p_mode) {
} else {
tree->set_select_mode(Tree::SELECT_SINGLE);
}
+
+ get_ok_button()->set_disabled(_is_open_should_be_disabled());
}
FileDialog::FileMode FileDialog::get_file_mode() const {
@@ -978,6 +1012,8 @@ void FileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root_subfolder"), &FileDialog::get_root_subfolder);
ClassDB::bind_method(D_METHOD("set_show_hidden_files", "show"), &FileDialog::set_show_hidden_files);
ClassDB::bind_method(D_METHOD("is_showing_hidden_files"), &FileDialog::is_showing_hidden_files);
+ ClassDB::bind_method(D_METHOD("set_use_native_dialog", "native"), &FileDialog::set_use_native_dialog);
+ ClassDB::bind_method(D_METHOD("get_use_native_dialog"), &FileDialog::get_use_native_dialog);
ClassDB::bind_method(D_METHOD("deselect_all"), &FileDialog::deselect_all);
ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate);
@@ -988,6 +1024,7 @@ void FileDialog::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_subfolder"), "set_root_subfolder", "get_root_subfolder");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_native_dialog"), "set_use_native_dialog", "get_use_native_dialog");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR, "", PROPERTY_USAGE_NONE), "set_current_dir", "get_current_dir");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file", PROPERTY_HINT_FILE, "*", PROPERTY_USAGE_NONE), "set_current_file", "get_current_file");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_path", "get_current_path");
@@ -1023,6 +1060,14 @@ void FileDialog::set_default_show_hidden_files(bool p_show) {
default_show_hidden_files = p_show;
}
+void FileDialog::set_use_native_dialog(bool p_native) {
+ use_native_dialog = p_native;
+}
+
+bool FileDialog::get_use_native_dialog() const {
+ return use_native_dialog;
+}
+
FileDialog::FileDialog() {
show_hidden_files = default_show_hidden_files;
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 87c41be98b..dece241ca9 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -105,6 +105,7 @@ private:
static bool default_show_hidden_files;
bool show_hidden_files = false;
+ bool use_native_dialog = false;
bool is_invalidating = false;
@@ -158,6 +159,8 @@ private:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
+ void _native_dialog_cb(bool p_ok, const Vector<String> &p_files);
+
bool _is_open_should_be_disabled();
virtual void _post_popup() override;
@@ -169,6 +172,8 @@ protected:
static void _bind_methods();
//bind helpers
public:
+ virtual void popup(const Rect2i &p_rect = Rect2i()) override;
+
void popup_file_dialog();
void clear_filters();
void add_filter(const String &p_filter, const String &p_description = "");
@@ -191,6 +196,9 @@ public:
void set_mode_overrides_title(bool p_override);
bool is_mode_overriding_title() const;
+ void set_use_native_dialog(bool p_native);
+ bool get_use_native_dialog() const;
+
void set_file_mode(FileMode p_mode);
FileMode get_file_mode() const;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 2c37017fa1..cb9fba44e5 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -35,10 +35,18 @@
#include "core/os/keyboard.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
+#include "scene/gui/graph_edit_arranger.h"
#include "scene/gui/view_panner.h"
+#include "scene/resources/style_box_flat.h"
constexpr int MINIMAP_OFFSET = 12;
constexpr int MINIMAP_PADDING = 5;
+constexpr int MIN_DRAG_DISTANCE_FOR_VALID_CONNECTION = 20;
+constexpr int MAX_CONNECTION_LINE_CURVE_TESSELATION_STAGES = 5;
+constexpr int GRID_MINOR_STEPS_PER_MAJOR_LINE = 10;
+constexpr int GRID_MIN_SNAPPING_DISTANCE = 2;
+constexpr int GRID_MAX_SNAPPING_DISTANCE = 100;
+constexpr float CONNECTING_TARGET_LINE_COLOR_BRIGHTENING = 0.4;
bool GraphEditFilter::has_point(const Point2 &p_point) const {
return ge->_filter_input(p_point);
@@ -75,23 +83,23 @@ void GraphEditMinimap::update_minimap() {
Vector2 graph_offset = _get_graph_offset();
Vector2 graph_size = _get_graph_size();
- camera_position = ge->get_scroll_ofs() - graph_offset;
+ camera_position = ge->get_scroll_offset() - graph_offset;
camera_size = ge->get_size();
Vector2 render_size = _get_render_size();
- float target_ratio = render_size.x / render_size.y;
- float graph_ratio = graph_size.x / graph_size.y;
+ float target_ratio = render_size.width / render_size.height;
+ float graph_ratio = graph_size.width / graph_size.height;
graph_proportions = graph_size;
graph_padding = Vector2(0, 0);
if (graph_ratio > target_ratio) {
- graph_proportions.x = graph_size.x;
- graph_proportions.y = graph_size.x / target_ratio;
- graph_padding.y = Math::abs(graph_size.y - graph_proportions.y) / 2;
+ graph_proportions.width = graph_size.width;
+ graph_proportions.height = graph_size.width / target_ratio;
+ graph_padding.y = Math::abs(graph_size.height - graph_proportions.y) / 2;
} else {
- graph_proportions.x = graph_size.y * target_ratio;
- graph_proportions.y = graph_size.y;
- graph_padding.x = Math::abs(graph_size.x - graph_proportions.x) / 2;
+ graph_proportions.width = graph_size.height * target_ratio;
+ graph_proportions.height = graph_size.height;
+ graph_padding.x = Math::abs(graph_size.width - graph_proportions.x) / 2;
}
// This centers minimap inside the minimap rectangle.
@@ -114,17 +122,17 @@ Vector2 GraphEditMinimap::_get_render_size() {
}
Vector2 GraphEditMinimap::_get_graph_offset() {
- return Vector2(ge->h_scroll->get_min(), ge->v_scroll->get_min());
+ return Vector2(ge->h_scrollbar->get_min(), ge->v_scrollbar->get_min());
}
Vector2 GraphEditMinimap::_get_graph_size() {
- Vector2 graph_size = Vector2(ge->h_scroll->get_max(), ge->v_scroll->get_max()) - Vector2(ge->h_scroll->get_min(), ge->v_scroll->get_min());
+ Vector2 graph_size = Vector2(ge->h_scrollbar->get_max(), ge->v_scrollbar->get_max()) - Vector2(ge->h_scrollbar->get_min(), ge->v_scrollbar->get_min());
- if (graph_size.x == 0) {
- graph_size.x = 1;
+ if (graph_size.width == 0) {
+ graph_size.width = 1;
}
- if (graph_size.y == 0) {
- graph_size.y = 1;
+ if (graph_size.height == 0) {
+ graph_size.height = 1;
}
return graph_size;
@@ -134,8 +142,8 @@ Vector2 GraphEditMinimap::_convert_from_graph_position(const Vector2 &p_position
Vector2 map_position = Vector2(0, 0);
Vector2 render_size = _get_render_size();
- map_position.x = p_position.x * render_size.x / graph_proportions.x;
- map_position.y = p_position.y * render_size.y / graph_proportions.y;
+ map_position.x = p_position.x * render_size.width / graph_proportions.x;
+ map_position.y = p_position.y * render_size.height / graph_proportions.y;
return map_position;
}
@@ -144,8 +152,8 @@ Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position)
Vector2 graph_position = Vector2(0, 0);
Vector2 render_size = _get_render_size();
- graph_position.x = p_position.x * graph_proportions.x / render_size.x;
- graph_position.y = p_position.y * graph_proportions.y / render_size.y;
+ graph_position.x = p_position.x * graph_proportions.x / render_size.width;
+ graph_position.y = p_position.y * graph_proportions.y / render_size.height;
return graph_position;
}
@@ -179,10 +187,10 @@ void GraphEditMinimap::gui_input(const Ref<InputEvent> &p_ev) {
accept_event();
} else if (mm.is_valid() && is_pressing) {
if (is_resizing) {
- // Prevent setting minimap wider than GraphEdit
+ // Prevent setting minimap wider than GraphEdit.
Vector2 new_minimap_size;
- new_minimap_size.x = MIN(get_size().x - mm->get_relative().x, ge->get_size().x - 2.0 * minimap_padding.x);
- new_minimap_size.y = MIN(get_size().y - mm->get_relative().y, ge->get_size().y - 2.0 * minimap_padding.y);
+ new_minimap_size.width = MIN(get_size().width - mm->get_relative().x, ge->get_size().width - 2.0 * minimap_padding.x);
+ new_minimap_size.height = MIN(get_size().height - mm->get_relative().y, ge->get_size().height - 2.0 * minimap_padding.y);
ge->set_minimap_size(new_minimap_size);
queue_redraw();
@@ -196,7 +204,7 @@ void GraphEditMinimap::gui_input(const Ref<InputEvent> &p_ev) {
void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) {
Vector2 graph_offset = _get_graph_offset();
- ge->set_scroll_ofs(p_offset + graph_offset - camera_size / 2);
+ ge->set_scroll_offset(p_offset + graph_offset - camera_size / 2);
}
Control::CursorShape GraphEdit::get_cursor_shape(const Point2 &p_pos) const {
@@ -220,9 +228,9 @@ Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const S
return OK;
}
Connection c;
- c.from = p_from;
+ c.from_node = p_from;
c.from_port = p_from_port;
- c.to = p_to;
+ c.to_node = p_to;
c.to_port = p_to_port;
c.activity = 0;
connections.push_back(c);
@@ -236,7 +244,7 @@ Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const S
bool GraphEdit::is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port) {
for (const Connection &E : connections) {
- if (E.from == p_from && E.from_port == p_from_port && E.to == p_to && E.to_port == p_to_port) {
+ if (E.from_node == p_from && E.from_port == p_from_port && E.to_node == p_to && E.to_port == p_to_port) {
return true;
}
}
@@ -246,7 +254,7 @@ bool GraphEdit::is_node_connected(const StringName &p_from, int p_from_port, con
void GraphEdit::disconnect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port) {
for (const List<Connection>::Element *E = connections.front(); E; E = E->next()) {
- if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) {
+ if (E->get().from_node == p_from && E->get().from_port == p_from_port && E->get().to_node == p_to && E->get().to_port == p_to_port) {
connections.erase(E);
top_layer->queue_redraw();
minimap->queue_redraw();
@@ -261,21 +269,21 @@ void GraphEdit::get_connection_list(List<Connection> *r_connections) const {
*r_connections = connections;
}
-void GraphEdit::set_scroll_ofs(const Vector2 &p_ofs) {
- setting_scroll_ofs = true;
- h_scroll->set_value(p_ofs.x);
- v_scroll->set_value(p_ofs.y);
+void GraphEdit::set_scroll_offset(const Vector2 &p_offset) {
+ setting_scroll_offset = true;
+ h_scrollbar->set_value(p_offset.x);
+ v_scrollbar->set_value(p_offset.y);
_update_scroll();
- setting_scroll_ofs = false;
+ setting_scroll_offset = false;
}
-Vector2 GraphEdit::get_scroll_ofs() const {
- return Vector2(h_scroll->get_value(), v_scroll->get_value());
+Vector2 GraphEdit::get_scroll_offset() const {
+ return Vector2(h_scrollbar->get_value(), v_scrollbar->get_value());
}
void GraphEdit::_scroll_moved(double) {
if (!awaiting_scroll_offset_update) {
- call_deferred(SNAME("_update_scroll_offset"));
+ callable_mp(this, &GraphEdit::_update_scroll_offset).call_deferred();
awaiting_scroll_offset_update = true;
}
top_layer->queue_redraw();
@@ -287,25 +295,26 @@ void GraphEdit::_update_scroll_offset() {
set_block_minimum_size_adjust(true);
for (int i = 0; i < get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (!graph_node) {
continue;
}
- Point2 pos = gn->get_position_offset() * zoom;
- pos -= Point2(h_scroll->get_value(), v_scroll->get_value());
- gn->set_position(pos);
- if (gn->get_scale() != Vector2(zoom, zoom)) {
- gn->set_scale(Vector2(zoom, zoom));
+ Point2 pos = graph_node->get_position_offset() * zoom;
+ pos -= Point2(h_scrollbar->get_value(), v_scrollbar->get_value());
+ graph_node->set_position(pos);
+ if (graph_node->get_scale() != Vector2(zoom, zoom)) {
+ graph_node->set_scale(Vector2(zoom, zoom));
}
}
- connections_layer->set_position(-Point2(h_scroll->get_value(), v_scroll->get_value()));
+ connections_layer->set_position(-Point2(h_scrollbar->get_value(), v_scrollbar->get_value()));
set_block_minimum_size_adjust(false);
awaiting_scroll_offset_update = false;
- if (!setting_scroll_ofs) { //in godot, signals on change value are avoided as a convention
- emit_signal(SNAME("scroll_offset_changed"), get_scroll_ofs());
+ // In Godot, signals on value change are avoided by convention.
+ if (!setting_scroll_offset) {
+ emit_signal(SNAME("scroll_offset_changed"), get_scroll_offset());
}
}
@@ -313,90 +322,93 @@ void GraphEdit::_update_scroll() {
if (updating) {
return;
}
-
updating = true;
set_block_minimum_size_adjust(true);
- Rect2 screen;
+ Rect2 screen_rect;
for (int i = 0; i < get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (!graph_node) {
continue;
}
- Rect2 r;
- r.position = gn->get_position_offset() * zoom;
- r.size = gn->get_size() * zoom;
- screen = screen.merge(r);
+ Rect2 node_rect;
+ node_rect.position = graph_node->get_position_offset() * zoom;
+ node_rect.size = graph_node->get_size() * zoom;
+ screen_rect = screen_rect.merge(node_rect);
}
- screen.position -= get_size();
- screen.size += get_size() * 2.0;
+ screen_rect.position -= get_size();
+ screen_rect.size += get_size() * 2.0;
- h_scroll->set_min(screen.position.x);
- h_scroll->set_max(screen.position.x + screen.size.x);
- h_scroll->set_page(get_size().x);
- if (h_scroll->get_max() - h_scroll->get_min() <= h_scroll->get_page()) {
- h_scroll->hide();
+ h_scrollbar->set_min(screen_rect.position.x);
+ h_scrollbar->set_max(screen_rect.position.x + screen_rect.size.width);
+ h_scrollbar->set_page(get_size().x);
+ if (h_scrollbar->get_max() - h_scrollbar->get_min() <= h_scrollbar->get_page()) {
+ h_scrollbar->hide();
} else {
- h_scroll->show();
+ h_scrollbar->show();
}
- v_scroll->set_min(screen.position.y);
- v_scroll->set_max(screen.position.y + screen.size.y);
- v_scroll->set_page(get_size().y);
+ v_scrollbar->set_min(screen_rect.position.y);
+ v_scrollbar->set_max(screen_rect.position.y + screen_rect.size.height);
+ v_scrollbar->set_page(get_size().height);
- if (v_scroll->get_max() - v_scroll->get_min() <= v_scroll->get_page()) {
- v_scroll->hide();
+ if (v_scrollbar->get_max() - v_scrollbar->get_min() <= v_scrollbar->get_page()) {
+ v_scrollbar->hide();
} else {
- v_scroll->show();
+ v_scrollbar->show();
}
- Size2 hmin = h_scroll->get_combined_minimum_size();
- Size2 vmin = v_scroll->get_combined_minimum_size();
+ Size2 hmin = h_scrollbar->get_combined_minimum_size();
+ Size2 vmin = v_scrollbar->get_combined_minimum_size();
// Avoid scrollbar overlapping.
- h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, v_scroll->is_visible() ? -vmin.width : 0);
- v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, h_scroll->is_visible() ? -hmin.height : 0);
+ h_scrollbar->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, v_scrollbar->is_visible() ? -vmin.width : 0);
+ v_scrollbar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, h_scrollbar->is_visible() ? -hmin.height : 0);
set_block_minimum_size_adjust(false);
if (!awaiting_scroll_offset_update) {
- call_deferred(SNAME("_update_scroll_offset"));
+ callable_mp(this, &GraphEdit::_update_scroll_offset).call_deferred();
awaiting_scroll_offset_update = true;
}
updating = false;
}
-void GraphEdit::_graph_node_raised(Node *p_gn) {
- GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
- ERR_FAIL_NULL(gn);
- if (gn->is_comment()) {
- move_child(gn, 0);
- } else {
- gn->move_to_front();
- }
+void GraphEdit::_graph_node_moved_to_front(Node *p_gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_NULL(graph_node);
+
+ graph_node->move_to_front();
}
void GraphEdit::_graph_node_selected(Node *p_gn) {
- GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
- ERR_FAIL_NULL(gn);
+ GraphNode *graph_node = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_NULL(graph_node);
- emit_signal(SNAME("node_selected"), gn);
+ emit_signal(SNAME("node_selected"), graph_node);
}
void GraphEdit::_graph_node_deselected(Node *p_gn) {
- GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
- ERR_FAIL_NULL(gn);
+ GraphNode *graph_node = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_NULL(graph_node);
- emit_signal(SNAME("node_deselected"), gn);
+ emit_signal(SNAME("node_deselected"), graph_node);
+}
+
+void GraphEdit::_graph_node_resized(Vector2 p_new_minsize, Node *p_gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_NULL(graph_node);
+
+ graph_node->set_custom_minimum_size(p_new_minsize);
}
void GraphEdit::_graph_node_moved(Node *p_gn) {
- GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
- ERR_FAIL_NULL(gn);
+ GraphNode *graph_node = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_NULL(graph_node);
top_layer->queue_redraw();
minimap->queue_redraw();
queue_redraw();
@@ -404,8 +416,8 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
}
void GraphEdit::_graph_node_slot_updated(int p_index, Node *p_gn) {
- GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
- ERR_FAIL_NULL(gn);
+ GraphNode *graph_node = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_NULL(graph_node);
top_layer->queue_redraw();
minimap->queue_redraw();
queue_redraw();
@@ -415,20 +427,22 @@ void GraphEdit::_graph_node_slot_updated(int p_index, Node *p_gn) {
void GraphEdit::add_child_notify(Node *p_child) {
Control::add_child_notify(p_child);
- top_layer->call_deferred(SNAME("raise")); // Top layer always on top!
+ // Keep the top layer always on top!
+ callable_mp((CanvasItem *)top_layer, &CanvasItem::move_to_front).call_deferred();
- GraphNode *gn = Object::cast_to<GraphNode>(p_child);
- if (gn) {
- gn->set_scale(Vector2(zoom, zoom));
- gn->connect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved).bind(gn));
- gn->connect("node_selected", callable_mp(this, &GraphEdit::_graph_node_selected).bind(gn));
- gn->connect("node_deselected", callable_mp(this, &GraphEdit::_graph_node_deselected).bind(gn));
- gn->connect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated).bind(gn));
- gn->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised).bind(gn));
- gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw));
- gn->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw));
- _graph_node_moved(gn);
- gn->set_mouse_filter(MOUSE_FILTER_PASS);
+ GraphNode *graph_node = Object::cast_to<GraphNode>(p_child);
+ if (graph_node) {
+ graph_node->set_scale(Vector2(zoom, zoom));
+ graph_node->connect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved).bind(graph_node));
+ graph_node->connect("node_selected", callable_mp(this, &GraphEdit::_graph_node_selected).bind(graph_node));
+ graph_node->connect("node_deselected", callable_mp(this, &GraphEdit::_graph_node_deselected).bind(graph_node));
+ graph_node->connect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated).bind(graph_node));
+ graph_node->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_moved_to_front).bind(graph_node));
+ graph_node->connect("resize_request", callable_mp(this, &GraphEdit::_graph_node_resized).bind(graph_node));
+ graph_node->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw));
+ graph_node->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw));
+ _graph_node_moved(graph_node);
+ graph_node->set_mouse_filter(MOUSE_FILTER_PASS);
}
}
@@ -443,99 +457,100 @@ void GraphEdit::remove_child_notify(Node *p_child) {
}
if (top_layer != nullptr && is_inside_tree()) {
- top_layer->call_deferred(SNAME("raise")); // Top layer always on top!
+ // Keep the top layer always on top!
+ callable_mp((CanvasItem *)top_layer, &CanvasItem::move_to_front).call_deferred();
}
- GraphNode *gn = Object::cast_to<GraphNode>(p_child);
- if (gn) {
- gn->disconnect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
- gn->disconnect("node_selected", callable_mp(this, &GraphEdit::_graph_node_selected));
- gn->disconnect("node_deselected", callable_mp(this, &GraphEdit::_graph_node_deselected));
- gn->disconnect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated));
- gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised));
+ GraphNode *graph_node = Object::cast_to<GraphNode>(p_child);
+ if (graph_node) {
+ graph_node->disconnect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
+ graph_node->disconnect("node_selected", callable_mp(this, &GraphEdit::_graph_node_selected));
+ graph_node->disconnect("node_deselected", callable_mp(this, &GraphEdit::_graph_node_deselected));
+ graph_node->disconnect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated));
+ graph_node->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_moved_to_front));
// In case of the whole GraphEdit being destroyed these references can already be freed.
if (connections_layer != nullptr && connections_layer->is_inside_tree()) {
- gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw));
+ graph_node->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw));
}
if (minimap != nullptr && minimap->is_inside_tree()) {
- gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw));
+ graph_node->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw));
}
}
}
void GraphEdit::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
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->set_icon(get_theme_icon(SNAME("minus")));
- zoom_reset->set_icon(get_theme_icon(SNAME("reset")));
- zoom_plus->set_icon(get_theme_icon(SNAME("more")));
- snap_button->set_icon(get_theme_icon(SNAME("snap")));
- minimap_button->set_icon(get_theme_icon(SNAME("minimap")));
+ 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")));
+
+ 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")));
zoom_label->set_custom_minimum_size(Size2(48, 0) * get_theme_default_base_scale());
} break;
case NOTIFICATION_READY: {
- Size2 hmin = h_scroll->get_combined_minimum_size();
- Size2 vmin = v_scroll->get_combined_minimum_size();
-
- h_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0);
- h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
- h_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height);
- h_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);
-
- v_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -vmin.width);
- v_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
- v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0);
- v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);
+ Size2 hmin = h_scrollbar->get_combined_minimum_size();
+ Size2 vmin = v_scrollbar->get_combined_minimum_size();
+
+ h_scrollbar->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0);
+ h_scrollbar->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
+ h_scrollbar->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height);
+ h_scrollbar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);
+
+ v_scrollbar->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -vmin.width);
+ v_scrollbar->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
+ v_scrollbar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0);
+ v_scrollbar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);
} break;
case NOTIFICATION_DRAW: {
- draw_style_box(get_theme_stylebox(SNAME("bg")), Rect2(Point2(), get_size()));
+ // Draw background fill.
+ draw_style_box(get_theme_stylebox(SNAME("panel")), Rect2(Point2(), get_size()));
- if (is_using_snap()) {
- // Draw grid.
- int snap = get_snap();
-
- Vector2 offset = get_scroll_ofs() / zoom;
+ // Draw background grid.
+ if (show_grid) {
+ Vector2 offset = get_scroll_offset() / zoom;
Size2 size = get_size() / zoom;
- Point2i from = (offset / float(snap)).floor();
- Point2i len = (size / float(snap)).floor() + Vector2(1, 1);
+ 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.x; i < from.x + len.x; i++) {
+ for (int i = from_pos.x; i < from_pos.x + len.x; i++) {
Color color;
- if (ABS(i) % 10 == 0) {
+ if (ABS(i) % GRID_MINOR_STEPS_PER_MAJOR_LINE == 0) {
color = grid_major;
} else {
color = grid_minor;
}
- float base_ofs = i * snap * zoom - offset.x * zoom;
- draw_line(Vector2(base_ofs, 0), Vector2(base_ofs, get_size().height), color);
+ float base_offset = i * snapping_distance * zoom - offset.x * zoom;
+ draw_line(Vector2(base_offset, 0), Vector2(base_offset, get_size().height), color);
}
- for (int i = from.y; i < from.y + len.y; i++) {
+ for (int i = from_pos.y; i < from_pos.y + len.y; i++) {
Color color;
- if (ABS(i) % 10 == 0) {
+ if (ABS(i) % GRID_MINOR_STEPS_PER_MAJOR_LINE == 0) {
color = grid_major;
} else {
color = grid_minor;
}
- float base_ofs = i * snap * zoom - offset.y * zoom;
- draw_line(Vector2(0, base_ofs), Vector2(get_size().width, base_ofs), color);
+ float base_offset = i * snapping_distance * zoom - offset.y * zoom;
+ draw_line(Vector2(0, base_offset), Vector2(get_size().width, base_offset), color);
}
}
} break;
@@ -548,65 +563,38 @@ void GraphEdit::_notification(int p_what) {
}
}
-void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes) {
- Rect2 comment_node_rect = p_node->get_rect();
-
- Vector<GraphNode *> enclosed_nodes;
- for (int i = 0; i < get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn || gn->is_selected()) {
- continue;
- }
-
- Rect2 node_rect = gn->get_rect();
-
- bool included = comment_node_rect.encloses(node_rect);
- if (included) {
- enclosed_nodes.push_back(gn);
- }
- }
-
- p_comment_enclosed_nodes.insert(p_node->get_name(), enclosed_nodes);
-}
-
-void GraphEdit::_set_drag_comment_enclosed_nodes(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes, bool p_drag) {
- for (int i = 0; i < p_comment_enclosed_nodes[p_node->get_name()].size(); i++) {
- p_comment_enclosed_nodes[p_node->get_name()][i]->set_drag(p_drag);
- }
-}
-
-void GraphEdit::_set_position_of_comment_enclosed_nodes(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes, Vector2 p_drag_accum) {
- for (int i = 0; i < p_comment_enclosed_nodes[p_node->get_name()].size(); i++) {
- Vector2 pos = (p_comment_enclosed_nodes[p_node->get_name()][i]->get_drag_from() * zoom + drag_accum) / zoom;
- if (is_using_snap() ^ Input::get_singleton()->is_key_pressed(Key::CTRL)) {
- const int snap = get_snap();
- pos = pos.snapped(Vector2(snap, snap));
- }
- p_comment_enclosed_nodes[p_node->get_name()][i]->set_position_offset(pos);
- }
-}
-
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 *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (!graph_node || !graph_node->is_visible_in_tree()) {
continue;
}
- for (int j = 0; j < gn->get_connection_input_count(); j++) {
+ for (int j = 0; j < graph_node->get_connection_input_count(); j++) {
Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
- port_size.height = MAX(port_size.height, gn->get_connection_input_height(j));
- if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) {
+
+ // Determine slot height.
+ int slot_index = graph_node->get_connection_input_slot(j);
+ Control *child = Object::cast_to<Control>(graph_node->get_child(slot_index));
+
+ port_size.height = MAX(port_size.height, child ? child->get_size().y : 0);
+
+ if (is_in_input_hotzone(graph_node, j, p_point / zoom, port_size)) {
return true;
}
}
- for (int j = 0; j < gn->get_connection_output_count(); j++) {
+ for (int j = 0; j < graph_node->get_connection_output_count(); j++) {
Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
- port_size.height = MAX(port_size.height, gn->get_connection_output_height(j));
- if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) {
+
+ // Determine slot height.
+ int slot_index = graph_node->get_connection_output_slot(j);
+ Control *child = Object::cast_to<Control>(graph_node->get_child(slot_index));
+ port_size.height = MAX(port_size.height, child ? child->get_size().y : 0);
+
+ if (is_in_output_hotzone(graph_node, j, p_point / zoom, port_size)) {
return true;
}
}
@@ -623,24 +611,28 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_valid = false;
click_pos = mb->get_position() / zoom;
for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (!graph_node || !graph_node->is_visible_in_tree()) {
continue;
}
- for (int j = 0; j < gn->get_connection_output_count(); j++) {
- Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
+ for (int j = 0; j < graph_node->get_connection_output_count(); j++) {
+ Vector2 pos = graph_node->get_connection_output_position(j) * zoom + graph_node->get_position();
Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
- port_size.height = MAX(port_size.height, gn->get_connection_output_height(j));
- if (is_in_output_hotzone(gn, j, click_pos, port_size)) {
- if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
- //check disconnect
+ // Determine slot height.
+ int slot_index = graph_node->get_connection_output_slot(j);
+ Control *child = Object::cast_to<Control>(graph_node->get_child(slot_index));
+ port_size.height = MAX(port_size.height, child ? child->get_size().y : 0);
+
+ if (is_in_output_hotzone(graph_node, j, click_pos, port_size)) {
+ if (valid_left_disconnect_types.has(graph_node->get_connection_output_type(j))) {
+ // Check disconnect.
for (const Connection &E : connections) {
- if (E.from == gn->get_name() && E.from_port == j) {
- Node *to = get_node(NodePath(E.to));
+ if (E.from_node == graph_node->get_name() && E.from_port == j) {
+ Node *to = get_node(NodePath(E.to_node));
if (Object::cast_to<GraphNode>(to)) {
- connecting_from = E.to;
+ connecting_from = E.to_node;
connecting_index = E.to_port;
connecting_out = false;
connecting_type = Object::cast_to<GraphNode>(to)->get_connection_input_type(E.to_port);
@@ -651,7 +643,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
if (connecting_type >= 0) {
just_disconnected = true;
- emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
+ emit_signal(SNAME("disconnection_request"), E.from_node, E.from_port, E.to_node, E.to_port);
to = get_node(NodePath(connecting_from)); // Maybe it was erased.
if (Object::cast_to<GraphNode>(to)) {
connecting = true;
@@ -664,11 +656,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- connecting_from = gn->get_name();
+ connecting_from = graph_node->get_name();
connecting_index = j;
connecting_out = true;
- connecting_type = gn->get_connection_output_type(j);
- connecting_color = gn->get_connection_output_color(j);
+ connecting_type = graph_node->get_connection_output_type(j);
+ connecting_color = graph_node->get_connection_output_color(j);
connecting_target = false;
connecting_to = pos;
if (connecting_type >= 0) {
@@ -680,20 +672,24 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- for (int j = 0; j < gn->get_connection_input_count(); j++) {
- Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
+ for (int j = 0; j < graph_node->get_connection_input_count(); j++) {
+ Vector2 pos = graph_node->get_connection_input_position(j) + graph_node->get_position();
Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
- port_size.height = MAX(port_size.height, gn->get_connection_input_height(j));
- if (is_in_input_hotzone(gn, j, click_pos, port_size)) {
- if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
+ // Determine slot height.
+ int slot_index = graph_node->get_connection_input_slot(j);
+ Control *child = Object::cast_to<Control>(graph_node->get_child(slot_index));
+ port_size.height = MAX(port_size.height, child ? child->get_size().y : 0);
+
+ if (is_in_input_hotzone(graph_node, j, click_pos, port_size)) {
+ if (right_disconnects || valid_right_disconnect_types.has(graph_node->get_connection_input_type(j))) {
// Check disconnect.
for (const Connection &E : connections) {
- if (E.to == gn->get_name() && E.to_port == j) {
- Node *fr = get_node(NodePath(E.from));
+ if (E.to_node == graph_node->get_name() && E.to_port == j) {
+ Node *fr = get_node(NodePath(E.from_node));
if (Object::cast_to<GraphNode>(fr)) {
- connecting_from = E.from;
+ connecting_from = E.from_node;
connecting_index = E.from_port;
connecting_out = true;
connecting_type = Object::cast_to<GraphNode>(fr)->get_connection_output_type(E.from_port);
@@ -703,8 +699,8 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
just_disconnected = true;
if (connecting_type >= 0) {
- emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
- fr = get_node(NodePath(connecting_from)); // Maybe it was erased.
+ emit_signal(SNAME("disconnection_request"), E.from_node, E.from_port, E.to_node, E.to_port);
+ fr = get_node(NodePath(connecting_from));
if (Object::cast_to<GraphNode>(fr)) {
connecting = true;
emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
@@ -716,11 +712,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- connecting_from = gn->get_name();
+ connecting_from = graph_node->get_name();
connecting_index = j;
connecting_out = false;
- connecting_type = gn->get_connection_input_type(j);
- connecting_color = gn->get_connection_input_color(j);
+ connecting_type = graph_node->get_connection_input_type(j);
+ connecting_color = graph_node->get_connection_input_color(j);
connecting_target = false;
connecting_to = pos;
if (connecting_type >= 0) {
@@ -740,49 +736,61 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_target = false;
top_layer->queue_redraw();
minimap->queue_redraw();
- connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0;
+
+ connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > MIN_DRAG_DISTANCE_FOR_VALID_CONNECTION;
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 *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (!graph_node || !graph_node->is_visible_in_tree()) {
continue;
}
if (!connecting_out) {
- for (int j = 0; j < gn->get_connection_output_count(); j++) {
- Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
+ for (int j = 0; j < graph_node->get_connection_output_count(); j++) {
+ Vector2 pos = graph_node->get_connection_output_position(j) + graph_node->get_position();
Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
- port_size.height = MAX(port_size.height, gn->get_connection_output_height(j));
- int type = gn->get_connection_output_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_output_hotzone(gn, j, mpos, port_size)) {
- if (!is_node_hover_valid(gn->get_name(), j, connecting_from, connecting_index)) {
+ // Determine slot height.
+ int slot_index = graph_node->get_connection_output_slot(j);
+ Control *child = Object::cast_to<Control>(graph_node->get_child(slot_index));
+ port_size.height = MAX(port_size.height, child ? child->get_size().y : 0);
+
+ int type = graph_node->get_connection_output_type(j);
+ if ((type == connecting_type ||
+ valid_connection_types.has(ConnectionType(connecting_type, 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;
}
connecting_target = true;
connecting_to = pos;
- connecting_target_to = gn->get_name();
+ connecting_target_to = graph_node->get_name();
connecting_target_index = j;
return;
}
}
} else {
- for (int j = 0; j < gn->get_connection_input_count(); j++) {
- Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
+ for (int j = 0; j < graph_node->get_connection_input_count(); j++) {
+ Vector2 pos = graph_node->get_connection_input_position(j) + graph_node->get_position();
Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
- port_size.height = MAX(port_size.height, gn->get_connection_input_height(j));
- int type = gn->get_connection_input_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_input_hotzone(gn, j, mpos, port_size)) {
- if (!is_node_hover_valid(connecting_from, connecting_index, gn->get_name(), j)) {
+ // Determine slot height.
+ int slot_index = graph_node->get_connection_input_slot(j);
+ Control *child = Object::cast_to<Control>(graph_node->get_child(slot_index));
+ port_size.height = MAX(port_size.height, child ? child->get_size().y : 0);
+
+ int type = graph_node->get_connection_input_type(j);
+ if ((type == connecting_type || valid_connection_types.has(ConnectionType(connecting_type, type))) &&
+ is_in_input_hotzone(graph_node, j, mpos, port_size)) {
+ if (!is_node_hover_valid(connecting_from, connecting_index, graph_node->get_name(), j)) {
continue;
}
connecting_target = true;
connecting_to = pos;
- connecting_target_to = gn->get_name();
+ connecting_target_to = graph_node->get_name();
connecting_target_index = j;
return;
}
@@ -843,30 +851,30 @@ bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos
}
}
-bool GraphEdit::is_in_input_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
+bool GraphEdit::is_in_input_hotzone(GraphNode *p_graph_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
bool success;
- if (GDVIRTUAL_CALL(_is_in_input_hotzone, p_node, p_port, p_mouse_pos, success)) {
+ if (GDVIRTUAL_CALL(_is_in_input_hotzone, p_graph_node, p_port, p_mouse_pos, success)) {
return success;
} else {
- Vector2 pos = p_node->get_connection_input_position(p_port) + p_node->get_position();
+ Vector2 pos = p_graph_node->get_connection_input_position(p_port) + p_graph_node->get_position();
return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, true);
}
}
-bool GraphEdit::is_in_output_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
- if (p_node->is_resizable()) {
- Ref<Texture2D> resizer = p_node->get_theme_icon(SNAME("resizer"));
- Rect2 resizer_rect = Rect2(p_node->get_position() / zoom + p_node->get_size() - resizer->get_size(), resizer->get_size());
+bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_port, 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"));
+ 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;
}
}
bool success;
- if (GDVIRTUAL_CALL(_is_in_output_hotzone, p_node, p_port, p_mouse_pos, success)) {
+ if (GDVIRTUAL_CALL(_is_in_output_hotzone, p_graph_node, p_port, p_mouse_pos, success)) {
return success;
} else {
- Vector2 pos = p_node->get_connection_output_position(p_port) + p_node->get_position();
+ Vector2 pos = p_graph_node->get_connection_output_position(p_port) + p_graph_node->get_position();
return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, false);
}
}
@@ -925,7 +933,7 @@ PackedVector2Array GraphEdit::get_connection_line(const Vector2 &p_from, const V
curve.set_point_in(1, Vector2(-cp_offset, 0));
if (lines_curvature > 0) {
- return curve.tessellate(5, 2.0);
+ return curve.tessellate(MAX_CONNECTION_LINE_CURVE_TESSELATION_STAGES, 2.0);
} else {
return curve.tessellate(1);
}
@@ -948,31 +956,32 @@ void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from
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()) {
const Connection &c = E->get();
- Node *from = get_node(NodePath(c.from));
- GraphNode *gfrom = Object::cast_to<GraphNode>(from);
+ Node *from = get_node(NodePath(c.from_node));
+ GraphNode *gnode_from = Object::cast_to<GraphNode>(from);
- if (!gfrom) {
+ if (!gnode_from) {
to_erase.push_back(E);
continue;
}
- Node *to = get_node(NodePath(c.to));
- GraphNode *gto = Object::cast_to<GraphNode>(to);
+ Node *to = get_node(NodePath(c.to_node));
+ GraphNode *gnode_to = Object::cast_to<GraphNode>(to);
- if (!gto) {
+ if (!gnode_to) {
to_erase.push_back(E);
continue;
}
- Vector2 frompos = gfrom->get_connection_output_position(c.from_port) + gfrom->get_position_offset() * zoom;
- Color color = gfrom->get_connection_output_color(c.from_port);
- Vector2 topos = gto->get_connection_input_position(c.to_port) + gto->get_position_offset() * zoom;
- Color tocolor = gto->get_connection_input_color(c.to_port);
+ Vector2 frompos = gnode_from->get_connection_output_position(c.from_port) + gnode_from->get_position_offset() * zoom;
+ Color color = gnode_from->get_connection_output_color(c.from_port);
+ Vector2 topos = gnode_to->get_connection_input_position(c.to_port) + gnode_to->get_position_offset() * zoom;
+ Color tocolor = gnode_to->get_connection_input_color(c.to_port);
if (c.activity > 0) {
color = color.lerp(activity_color, c.activity);
@@ -990,33 +999,32 @@ void GraphEdit::_top_layer_draw() {
_update_scroll();
if (connecting) {
- Node *fromn = get_node_or_null(NodePath(connecting_from));
- ERR_FAIL_NULL(fromn);
- GraphNode *from = Object::cast_to<GraphNode>(fromn);
- ERR_FAIL_NULL(from);
+ Node *node_from = get_node_or_null(NodePath(connecting_from));
+ ERR_FAIL_NULL(node_from);
+ GraphNode *graph_node_from = Object::cast_to<GraphNode>(node_from);
+ ERR_FAIL_NULL(graph_node_from);
Vector2 pos;
if (connecting_out) {
- pos = from->get_connection_output_position(connecting_index);
+ pos = graph_node_from->get_connection_output_position(connecting_index);
} else {
- pos = from->get_connection_input_position(connecting_index);
+ pos = graph_node_from->get_connection_input_position(connecting_index);
}
- pos += from->get_position();
+ pos += graph_node_from->get_position();
- Vector2 topos;
- topos = connecting_to;
-
- Color col = connecting_color;
+ Vector2 to_pos = connecting_to;
+ Color line_color = connecting_color;
+ // Draw the line to the mouse cursor brighter when it's over a valid target port.
if (connecting_target) {
- col.r += 0.4;
- col.g += 0.4;
- col.b += 0.4;
+ line_color.r += CONNECTING_TARGET_LINE_COLOR_BRIGHTENING;
+ line_color.g += CONNECTING_TARGET_LINE_COLOR_BRIGHTENING;
+ line_color.b += CONNECTING_TARGET_LINE_COLOR_BRIGHTENING;
}
if (!connecting_out) {
- SWAP(pos, topos);
+ SWAP(pos, to_pos);
}
- _draw_connection_line(top_layer, pos, topos, col, col, lines_thickness, zoom);
+ _draw_connection_line(top_layer, pos, to_pos, line_color, line_color, lines_thickness, zoom);
}
if (box_selecting) {
@@ -1034,51 +1042,28 @@ 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("bg")), minimap_rect);
+ minimap->draw_style_box(minimap->get_theme_stylebox(SNAME("panel")), minimap_rect);
Vector2 graph_offset = minimap->_get_graph_offset();
Vector2 minimap_offset = minimap->minimap_offset;
- // Draw comment graph nodes.
+ // Draw graph nodes.
for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn || !gn->is_comment()) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (!graph_node || !graph_node->is_visible()) {
continue;
}
- Vector2 node_position = minimap->_convert_from_graph_position(gn->get_position_offset() * zoom - graph_offset) + minimap_offset;
- Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom);
+ Vector2 node_position = minimap->_convert_from_graph_position(graph_node->get_position_offset() * zoom - graph_offset) + minimap_offset;
+ 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();
// Override default values with colors provided by the GraphNode's stylebox, if possible.
- Ref<StyleBoxFlat> sbf = gn->get_theme_stylebox(gn->is_selected() ? "comment_focus" : "comment");
- if (sbf.is_valid()) {
- Color node_color = sbf->get_bg_color();
- sb_minimap->set_bg_color(node_color);
- }
-
- minimap->draw_style_box(sb_minimap, node_rect);
- }
-
- // Draw regular graph nodes.
- for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn || gn->is_comment()) {
- continue;
- }
-
- Vector2 node_position = minimap->_convert_from_graph_position(gn->get_position_offset() * zoom - graph_offset) + minimap_offset;
- Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom);
- Rect2 node_rect = Rect2(node_position, node_size);
-
- Ref<StyleBoxFlat> sb_minimap = minimap->get_theme_stylebox(SNAME("node"))->duplicate();
-
- // Override default values with colors provided by the GraphNode's stylebox, if possible.
- Ref<StyleBoxFlat> sbf = gn->get_theme_stylebox(gn->is_selected() ? "selected_frame" : "frame");
- if (sbf.is_valid()) {
- Color node_color = sbf->get_border_color();
+ Ref<StyleBoxFlat> sb_frame = graph_node->get_theme_stylebox(graph_node->is_selected() ? "selected_frame" : "frame");
+ if (sb_frame.is_valid()) {
+ Color node_color = sb_frame->get_bg_color();
sb_minimap->set_bg_color(node_color);
}
@@ -1088,24 +1073,24 @@ 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));
- GraphNode *gfrom = Object::cast_to<GraphNode>(from);
- if (!gfrom) {
+ Node *from = get_node(NodePath(E.from_node));
+ GraphNode *graph_node_from = Object::cast_to<GraphNode>(from);
+ if (!graph_node_from) {
continue;
}
- Node *to = get_node(NodePath(E.to));
- GraphNode *gto = Object::cast_to<GraphNode>(to);
- if (!gto) {
+ Node *node_to = get_node(NodePath(E.to_node));
+ GraphNode *graph_node_to = Object::cast_to<GraphNode>(node_to);
+ if (!graph_node_to) {
continue;
}
- Vector2 from_port_position = gfrom->get_position_offset() * zoom + gfrom->get_connection_output_position(E.from_port);
+ Vector2 from_port_position = graph_node_from->get_position_offset() + graph_node_from->get_connection_output_position(E.from_port);
Vector2 from_position = minimap->_convert_from_graph_position(from_port_position - graph_offset) + minimap_offset;
- Color from_color = gfrom->get_connection_output_color(E.from_port);
- Vector2 to_port_position = gto->get_position_offset() * zoom + gto->get_connection_input_position(E.to_port);
+ Color from_color = graph_node_from->get_connection_output_color(E.from_port);
+ Vector2 to_port_position = graph_node_to->get_position_offset() + graph_node_to->get_connection_input_position(E.to_port);
Vector2 to_position = minimap->_convert_from_graph_position(to_port_position - graph_offset) + minimap_offset;
- Color to_color = gto->get_connection_input_color(E.to_port);
+ Color to_color = graph_node_to->get_connection_input_color(E.to_port);
if (E.activity > 0) {
from_color = from_color.lerp(activity_color, E.activity);
@@ -1126,12 +1111,12 @@ void GraphEdit::_minimap_draw() {
void GraphEdit::set_selected(Node *p_child) {
for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (!graph_node) {
continue;
}
- gn->set_selected(gn == p_child);
+ graph_node->set_selected(graph_node == p_child);
}
}
@@ -1152,21 +1137,17 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
just_selected = true;
drag_accum += mm->get_relative();
for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (gn && gn->is_selected() && gn->is_draggable()) {
- Vector2 pos = (gn->get_drag_from() * zoom + drag_accum) / zoom;
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (graph_node && graph_node->is_selected() && graph_node->is_draggable()) {
+ Vector2 pos = (graph_node->get_drag_from() * zoom + drag_accum) / zoom;
// Snapping can be toggled temporarily by holding down Ctrl.
// This is done here as to not toggle the grid when holding down Ctrl.
- if (is_using_snap() ^ Input::get_singleton()->is_key_pressed(Key::CTRL)) {
- const int snap = get_snap();
- pos = pos.snapped(Vector2(snap, snap));
+ if (snapping_enabled ^ Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ pos = pos.snapped(Vector2(snapping_distance, snapping_distance));
}
- gn->set_position_offset(pos);
- if (gn->is_comment()) {
- _set_position_of_comment_enclosed_nodes(gn, comment_enclosed_nodes, drag_accum);
- }
+ graph_node->set_position_offset(pos);
}
}
}
@@ -1177,18 +1158,18 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
box_selecting_rect = Rect2(box_selecting_from.min(box_selecting_to), (box_selecting_from - box_selecting_to).abs());
for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (!graph_node) {
continue;
}
- Rect2 r = gn->get_rect();
+ Rect2 r = graph_node->get_rect();
bool in_box = r.intersects(box_selecting_rect);
if (in_box) {
- gn->set_selected(box_selection_mode_additive);
+ graph_node->set_selected(box_selection_mode_additive);
} else {
- gn->set_selected(previous_selected.find(gn) != nullptr);
+ graph_node->set_selected(prev_selected.find(graph_node) != nullptr);
}
}
@@ -1202,12 +1183,12 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (box_selecting) {
box_selecting = false;
for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (!graph_node) {
continue;
}
- gn->set_selected(previous_selected.find(gn) != nullptr);
+ graph_node->set_selected(prev_selected.find(graph_node) != nullptr);
}
top_layer->queue_redraw();
minimap->queue_redraw();
@@ -1222,14 +1203,14 @@ 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)) {
- //deselect current node
+ // Deselect current node.
for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
- if (gn) {
- Rect2 r = gn->get_rect();
+ if (graph_node) {
+ Rect2 r = graph_node->get_rect();
if (r.has_point(mb->get_position())) {
- gn->set_selected(false);
+ graph_node->set_selected(false);
}
}
}
@@ -1237,12 +1218,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (drag_accum != Vector2()) {
for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (gn && gn->is_selected()) {
- gn->set_drag(false);
- if (gn->is_comment()) {
- _set_drag_comment_enclosed_nodes(gn, comment_enclosed_nodes, false);
- }
+ GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
+ if (graph_node && graph_node->is_selected()) {
+ graph_node->set_drag(false);
}
}
}
@@ -1260,28 +1238,29 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
connections_layer->queue_redraw();
}
+ // Node selection logic.
if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
- GraphNode *gn = nullptr;
+ GraphNode *graph_node = nullptr;
// Find node which was clicked on.
for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn_selected = Object::cast_to<GraphNode>(get_child(i));
+ GraphNode *selected_gcontrol = Object::cast_to<GraphNode>(get_child(i));
- if (!gn_selected) {
+ if (!selected_gcontrol) {
continue;
}
- if (gn_selected->is_resizing()) {
+ if (selected_gcontrol->is_resizing()) {
continue;
}
- if (gn_selected->has_point((mb->get_position() - gn_selected->get_position()) / zoom)) {
- gn = gn_selected;
+ if (selected_gcontrol->has_point((mb->get_position() - selected_gcontrol->get_position()) / zoom)) {
+ graph_node = selected_gcontrol;
break;
}
}
- if (gn) {
+ if (graph_node) {
if (_filter_input(mb->get_position())) {
return;
}
@@ -1289,19 +1268,19 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
// Left-clicked on a node, select it.
dragging = true;
drag_accum = Vector2();
- just_selected = !gn->is_selected();
- if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ just_selected = !graph_node->is_selected();
+ if (!graph_node->is_selected() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (!o_gn) {
continue;
}
- o_gn->set_selected(o_gn == gn);
+ o_gn->set_selected(o_gn == graph_node);
}
}
- gn->set_selected(true);
+ graph_node->set_selected(true);
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (!o_gn) {
@@ -1309,10 +1288,6 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
if (o_gn->is_selected()) {
o_gn->set_drag(true);
- if (o_gn->is_comment()) {
- _update_comment_enclosed_nodes_list(o_gn, comment_enclosed_nodes);
- _set_drag_comment_enclosed_nodes(o_gn, comment_enclosed_nodes, true);
- }
}
}
@@ -1329,29 +1304,29 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
box_selecting_from = mb->get_position();
if (mb->is_ctrl_pressed()) {
box_selection_mode_additive = true;
- previous_selected.clear();
+ prev_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2 || !gn2->is_selected()) {
continue;
}
- previous_selected.push_back(gn2);
+ prev_selected.push_back(gn2);
}
} else if (mb->is_shift_pressed()) {
box_selection_mode_additive = false;
- previous_selected.clear();
+ prev_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2 || !gn2->is_selected()) {
continue;
}
- previous_selected.push_back(gn2);
+ prev_selected.push_back(gn2);
}
} else {
box_selection_mode_additive = true;
- previous_selected.clear();
+ prev_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2) {
@@ -1368,7 +1343,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
// Box selection ended. Nodes were selected during mouse movement.
box_selecting = false;
box_selecting_rect = Rect2();
- previous_selected.clear();
+ prev_selected.clear();
top_layer->queue_redraw();
minimap->queue_redraw();
}
@@ -1392,7 +1367,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (!gn) {
continue;
}
- if (gn->is_selected() && gn->is_close_button_visible()) {
+ if (gn->is_selected()) {
nodes.push_back(gn->get_name());
}
}
@@ -1404,8 +1379,8 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
void GraphEdit::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) {
- h_scroll->set_value(h_scroll->get_value() - p_scroll_vec.x);
- v_scroll->set_value(v_scroll->get_value() - p_scroll_vec.y);
+ h_scrollbar->set_value(h_scrollbar->get_value() - p_scroll_vec.x);
+ v_scrollbar->set_value(v_scrollbar->get_value() - p_scroll_vec.y);
}
void GraphEdit::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
@@ -1414,9 +1389,9 @@ void GraphEdit::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputE
void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port, float p_activity) {
for (Connection &E : connections) {
- if (E.from == p_from && E.from_port == p_from_port && E.to == p_to && E.to_port == p_to_port) {
+ if (E.from_node == p_from && E.from_port == p_from_port && E.to_node == p_to && E.to_port == p_to_port) {
if (Math::is_equal_approx(E.activity, p_activity)) {
- //update only if changed
+ // Update only if changed.
top_layer->queue_redraw();
minimap->queue_redraw();
connections_layer->queue_redraw();
@@ -1470,22 +1445,22 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
return;
}
- Vector2 sbofs = (Vector2(h_scroll->get_value(), v_scroll->get_value()) + p_center) / zoom;
+ Vector2 scrollbar_offset = (Vector2(h_scrollbar->get_value(), v_scrollbar->get_value()) + p_center) / zoom;
zoom = p_zoom;
top_layer->queue_redraw();
- zoom_minus->set_disabled(zoom == zoom_min);
- zoom_plus->set_disabled(zoom == zoom_max);
+ zoom_minus_button->set_disabled(zoom == zoom_min);
+ zoom_plus_button->set_disabled(zoom == zoom_max);
_update_scroll();
minimap->queue_redraw();
connections_layer->queue_redraw();
if (is_visible_in_tree()) {
- Vector2 ofs = sbofs * zoom - p_center;
- h_scroll->set_value(ofs.x);
- v_scroll->set_value(ofs.y);
+ Vector2 offset = scrollbar_offset * zoom - p_center;
+ h_scrollbar->set_value(offset.x);
+ v_scrollbar->set_value(offset.y);
}
_update_zoom_label();
@@ -1583,9 +1558,9 @@ TypedArray<Dictionary> GraphEdit::_get_connection_list() const {
TypedArray<Dictionary> arr;
for (const Connection &E : conns) {
Dictionary d;
- d["from"] = E.from;
+ d["from_node"] = E.from_node;
d["from_port"] = E.from_port;
- d["to"] = E.to;
+ d["to_node"] = E.to_node;
d["to_port"] = E.to_port;
arr.push_back(d);
}
@@ -1611,47 +1586,71 @@ void GraphEdit::_update_zoom_label() {
}
void GraphEdit::add_valid_connection_type(int p_type, int p_with_type) {
- ConnType ct(p_type, p_with_type);
+ ConnectionType ct(p_type, p_with_type);
valid_connection_types.insert(ct);
}
void GraphEdit::remove_valid_connection_type(int p_type, int p_with_type) {
- ConnType ct(p_type, p_with_type);
+ ConnectionType ct(p_type, p_with_type);
valid_connection_types.erase(ct);
}
bool GraphEdit::is_valid_connection_type(int p_type, int p_with_type) const {
- ConnType ct(p_type, p_with_type);
+ ConnectionType ct(p_type, p_with_type);
return valid_connection_types.has(ct);
}
-void GraphEdit::set_use_snap(bool p_enable) {
- if (snap_button->is_pressed() == p_enable) {
+void GraphEdit::set_snapping_enabled(bool p_enable) {
+ if (snapping_enabled == p_enable) {
return;
}
- snap_button->set_pressed(p_enable);
+
+ snapping_enabled = p_enable;
+ toggle_snapping_button->set_pressed(p_enable);
queue_redraw();
}
-bool GraphEdit::is_using_snap() const {
- return snap_button->is_pressed();
+bool GraphEdit::is_snapping_enabled() const {
+ return snapping_enabled;
+}
+
+void GraphEdit::set_snapping_distance(int p_snapping_distance) {
+ ERR_FAIL_COND_MSG(p_snapping_distance < GRID_MIN_SNAPPING_DISTANCE || p_snapping_distance > GRID_MAX_SNAPPING_DISTANCE,
+ vformat("GraphEdit's snapping distance must be between %d and %d (inclusive)", GRID_MIN_SNAPPING_DISTANCE, GRID_MAX_SNAPPING_DISTANCE));
+ snapping_distance = p_snapping_distance;
+ snapping_distance_spinbox->set_value(p_snapping_distance);
+ queue_redraw();
}
-int GraphEdit::get_snap() const {
- return snap_amount->get_value();
+int GraphEdit::get_snapping_distance() const {
+ return snapping_distance;
}
-void GraphEdit::set_snap(int p_snap) {
- ERR_FAIL_COND(p_snap < 5);
- snap_amount->set_value(p_snap);
+void GraphEdit::set_show_grid(bool p_show) {
+ if (show_grid == p_show) {
+ return;
+ }
+
+ show_grid = p_show;
+ show_grid_button->set_pressed(p_show);
queue_redraw();
}
-void GraphEdit::_snap_toggled() {
+bool GraphEdit::is_showing_grid() const {
+ return show_grid;
+}
+
+void GraphEdit::_snapping_toggled() {
+ snapping_enabled = toggle_snapping_button->is_pressed();
+}
+
+void GraphEdit::_snapping_distance_changed(double) {
+ snapping_distance = snapping_distance_spinbox->get_value();
queue_redraw();
}
-void GraphEdit::_snap_value_changed(double) {
+void GraphEdit::_show_grid_toggled() {
+ show_grid = show_grid_button->is_pressed();
queue_redraw();
}
@@ -1660,8 +1659,8 @@ void GraphEdit::set_minimap_size(Vector2 p_size) {
Vector2 minimap_size = minimap->get_size(); // The size might've been adjusted by the minimum size.
minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT);
- minimap->set_offset(Side::SIDE_LEFT, -minimap_size.x - MINIMAP_OFFSET);
- minimap->set_offset(Side::SIDE_TOP, -minimap_size.y - MINIMAP_OFFSET);
+ minimap->set_offset(Side::SIDE_LEFT, -minimap_size.width - MINIMAP_OFFSET);
+ minimap->set_offset(Side::SIDE_TOP, -minimap_size.height - MINIMAP_OFFSET);
minimap->set_offset(Side::SIDE_RIGHT, -MINIMAP_OFFSET);
minimap->set_offset(Side::SIDE_BOTTOM, -MINIMAP_OFFSET);
minimap->queue_redraw();
@@ -1752,8 +1751,8 @@ bool GraphEdit::is_connection_lines_antialiased() const {
return lines_antialiased;
}
-HBoxContainer *GraphEdit::get_zoom_hbox() {
- return zoom_hb;
+HBoxContainer *GraphEdit::get_menu_hbox() {
+ return menu_hbox;
}
Ref<ViewPanner> GraphEdit::get_panner() {
@@ -1764,526 +1763,8 @@ void GraphEdit::set_warped_panning(bool p_warped) {
warped_panning = p_warped;
}
-int GraphEdit::_set_operations(SET_OPERATIONS p_operation, HashSet<StringName> &r_u, const HashSet<StringName> &r_v) {
- switch (p_operation) {
- case GraphEdit::IS_EQUAL: {
- for (const StringName &E : r_u) {
- if (!r_v.has(E)) {
- return 0;
- }
- }
- return r_u.size() == r_v.size();
- } break;
- case GraphEdit::IS_SUBSET: {
- if (r_u.size() == r_v.size() && !r_u.size()) {
- return 1;
- }
- for (const StringName &E : r_u) {
- if (!r_v.has(E)) {
- return 0;
- }
- }
- return 1;
- } break;
- case GraphEdit::DIFFERENCE: {
- for (HashSet<StringName>::Iterator E = r_u.begin(); E;) {
- HashSet<StringName>::Iterator N = E;
- ++N;
- if (r_v.has(*E)) {
- r_u.remove(E);
- }
- E = N;
- }
- return r_u.size();
- } break;
- case GraphEdit::UNION: {
- for (const StringName &E : r_v) {
- if (!r_u.has(E)) {
- r_u.insert(E);
- }
- }
- return r_u.size();
- } break;
- default:
- break;
- }
- return -1;
-}
-
-HashMap<int, Vector<StringName>> GraphEdit::_layering(const HashSet<StringName> &r_selected_nodes, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours) {
- HashMap<int, Vector<StringName>> l;
-
- HashSet<StringName> p = r_selected_nodes, q = r_selected_nodes, u, z;
- int current_layer = 0;
- bool selected = false;
-
- while (!_set_operations(GraphEdit::IS_EQUAL, q, u)) {
- _set_operations(GraphEdit::DIFFERENCE, p, u);
- for (const StringName &E : p) {
- HashSet<StringName> n = r_upper_neighbours[E];
- if (_set_operations(GraphEdit::IS_SUBSET, n, z)) {
- Vector<StringName> t;
- t.push_back(E);
- if (!l.has(current_layer)) {
- l.insert(current_layer, Vector<StringName>{});
- }
- selected = true;
- t.append_array(l[current_layer]);
- l.insert(current_layer, t);
- HashSet<StringName> V;
- V.insert(E);
- _set_operations(GraphEdit::UNION, u, V);
- }
- }
- if (!selected) {
- current_layer++;
- uint32_t previous_size_z = z.size();
- _set_operations(GraphEdit::UNION, z, u);
- if (z.size() == previous_size_z) {
- WARN_PRINT("Graph contains cycle(s). The cycle(s) will not be rearranged accurately.");
- Vector<StringName> t;
- if (l.has(0)) {
- t.append_array(l[0]);
- }
- for (const StringName &E : p) {
- t.push_back(E);
- }
- l.insert(0, t);
- break;
- }
- }
- selected = false;
- }
-
- return l;
-}
-
-Vector<StringName> GraphEdit::_split(const Vector<StringName> &r_layer, const HashMap<StringName, Dictionary> &r_crossings) {
- if (!r_layer.size()) {
- return Vector<StringName>();
- }
-
- StringName p = r_layer[Math::random(0, r_layer.size() - 1)];
- Vector<StringName> left;
- Vector<StringName> right;
-
- for (int i = 0; i < r_layer.size(); i++) {
- if (p != r_layer[i]) {
- StringName q = r_layer[i];
- int cross_pq = r_crossings[p][q];
- int cross_qp = r_crossings[q][p];
- if (cross_pq > cross_qp) {
- left.push_back(q);
- } else {
- right.push_back(q);
- }
- }
- }
-
- left.push_back(p);
- left.append_array(right);
- return left;
-}
-
-void GraphEdit::_horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours, const HashSet<StringName> &r_selected_nodes) {
- for (const StringName &E : r_selected_nodes) {
- r_root[E] = E;
- r_align[E] = E;
- }
-
- if (r_layers.size() == 1) {
- return;
- }
-
- for (unsigned int i = 1; i < r_layers.size(); i++) {
- Vector<StringName> lower_layer = r_layers[i];
- Vector<StringName> upper_layer = r_layers[i - 1];
- int r = -1;
-
- for (int j = 0; j < lower_layer.size(); j++) {
- Vector<Pair<int, StringName>> up;
- StringName current_node = lower_layer[j];
- for (int k = 0; k < upper_layer.size(); k++) {
- StringName adjacent_neighbour = upper_layer[k];
- if (r_upper_neighbours[current_node].has(adjacent_neighbour)) {
- up.push_back(Pair<int, StringName>(k, adjacent_neighbour));
- }
- }
-
- int start = (up.size() - 1) / 2;
- int end = (up.size() - 1) % 2 ? start + 1 : start;
- for (int p = start; p <= end; p++) {
- StringName Align = r_align[current_node];
- if (Align == current_node && r < up[p].first) {
- r_align[up[p].second] = lower_layer[j];
- r_root[current_node] = r_root[up[p].second];
- r_align[current_node] = r_root[up[p].second];
- r = up[p].first;
- }
- }
- }
- }
-}
-
-void GraphEdit::_crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours) {
- if (r_layers.size() == 1) {
- return;
- }
-
- for (unsigned int i = 1; i < r_layers.size(); i++) {
- Vector<StringName> upper_layer = r_layers[i - 1];
- Vector<StringName> lower_layer = r_layers[i];
- HashMap<StringName, Dictionary> c;
-
- for (int j = 0; j < lower_layer.size(); j++) {
- StringName p = lower_layer[j];
- Dictionary d;
-
- for (int k = 0; k < lower_layer.size(); k++) {
- unsigned int crossings = 0;
- StringName q = lower_layer[k];
-
- if (j != k) {
- for (int h = 1; h < upper_layer.size(); h++) {
- if (r_upper_neighbours[p].has(upper_layer[h])) {
- for (int g = 0; g < h; g++) {
- if (r_upper_neighbours[q].has(upper_layer[g])) {
- crossings++;
- }
- }
- }
- }
- }
- d[q] = crossings;
- }
- c.insert(p, d);
- }
-
- r_layers.insert(i, _split(lower_layer, c));
- }
-}
-
-void GraphEdit::_calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const HashSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info) {
- for (const StringName &E : r_block_heads) {
- real_t left = 0;
- StringName u = E;
- StringName v = r_align[u];
- while (u != v && (StringName)r_root[u] != v) {
- String _connection = String(u) + " " + String(v);
- GraphNode *gfrom = Object::cast_to<GraphNode>(r_node_names[u]);
- GraphNode *gto = Object::cast_to<GraphNode>(r_node_names[v]);
-
- Pair<int, int> ports = r_port_info[_connection];
- int pfrom = ports.first;
- int pto = ports.second;
- Vector2 frompos = gfrom->get_connection_output_position(pfrom);
- Vector2 topos = gto->get_connection_input_position(pto);
-
- real_t s = (real_t)r_inner_shifts[u] + (frompos.y - topos.y) / zoom;
- r_inner_shifts[v] = s;
- left = MIN(left, s);
-
- u = v;
- v = (StringName)r_align[v];
- }
-
- u = E;
- do {
- r_inner_shifts[u] = (real_t)r_inner_shifts[u] - left;
- u = (StringName)r_align[u];
- } while (u != E);
- }
-}
-
-float GraphEdit::_calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions) {
-#define MAX_ORDER 2147483647
-#define ORDER(node, layers) \
- for (unsigned int i = 0; i < layers.size(); i++) { \
- int index = layers[i].find(node); \
- if (index > 0) { \
- order = index; \
- break; \
- } \
- order = MAX_ORDER; \
- }
-
- int order = MAX_ORDER;
- float threshold = p_current_threshold;
- if (p_v == p_w) {
- int min_order = MAX_ORDER;
- Connection incoming;
- for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
- if (E->get().to == p_w) {
- ORDER(E->get().from, r_layers);
- if (min_order > order) {
- min_order = order;
- incoming = E->get();
- }
- }
- }
-
- if (incoming.from != StringName()) {
- GraphNode *gfrom = Object::cast_to<GraphNode>(r_node_names[incoming.from]);
- GraphNode *gto = Object::cast_to<GraphNode>(r_node_names[p_w]);
- Vector2 frompos = gfrom->get_connection_output_position(incoming.from_port);
- Vector2 topos = gto->get_connection_input_position(incoming.to_port);
-
- //If connected block node is selected, calculate thershold or add current block to list
- if (gfrom->is_selected()) {
- Vector2 connected_block_pos = r_node_positions[r_root[incoming.from]];
- if (connected_block_pos.y != FLT_MAX) {
- //Connected block is placed. Calculate threshold
- threshold = connected_block_pos.y + (real_t)r_inner_shift[incoming.from] - (real_t)r_inner_shift[p_w] + frompos.y - topos.y;
- }
- }
- }
- }
- if (threshold == FLT_MIN && (StringName)r_align[p_w] == p_v) {
- //This time, pick an outgoing edge and repeat as above!
- int min_order = MAX_ORDER;
- Connection outgoing;
- for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
- if (E->get().from == p_w) {
- ORDER(E->get().to, r_layers);
- if (min_order > order) {
- min_order = order;
- outgoing = E->get();
- }
- }
- }
-
- if (outgoing.to != StringName()) {
- GraphNode *gfrom = Object::cast_to<GraphNode>(r_node_names[p_w]);
- GraphNode *gto = Object::cast_to<GraphNode>(r_node_names[outgoing.to]);
- Vector2 frompos = gfrom->get_connection_output_position(outgoing.from_port);
- Vector2 topos = gto->get_connection_input_position(outgoing.to_port);
-
- //If connected block node is selected, calculate thershold or add current block to list
- if (gto->is_selected()) {
- Vector2 connected_block_pos = r_node_positions[r_root[outgoing.to]];
- if (connected_block_pos.y != FLT_MAX) {
- //Connected block is placed. Calculate threshold
- threshold = connected_block_pos.y + (real_t)r_inner_shift[outgoing.to] - (real_t)r_inner_shift[p_w] + frompos.y - topos.y;
- }
- }
- }
- }
-#undef MAX_ORDER
-#undef ORDER
- return threshold;
-}
-
-void GraphEdit::_place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions) {
-#define PRED(node, layers) \
- for (unsigned int i = 0; i < layers.size(); i++) { \
- int index = layers[i].find(node); \
- if (index > 0) { \
- predecessor = layers[i][index - 1]; \
- break; \
- } \
- predecessor = StringName(); \
- }
-
- StringName predecessor;
- StringName successor;
- Vector2 pos = r_node_positions[p_v];
-
- if (pos.y == FLT_MAX) {
- pos.y = 0;
- bool initial = false;
- StringName w = p_v;
- real_t threshold = FLT_MIN;
- do {
- PRED(w, r_layers);
- if (predecessor != StringName()) {
- StringName u = r_root[predecessor];
- _place_block(u, p_delta, r_layers, r_root, r_align, r_node_name, r_inner_shift, r_sink, r_shift, r_node_positions);
- threshold = _calculate_threshold(p_v, w, r_node_name, r_layers, r_root, r_align, r_inner_shift, threshold, r_node_positions);
- if ((StringName)r_sink[p_v] == p_v) {
- r_sink[p_v] = r_sink[u];
- }
-
- Vector2 predecessor_root_pos = r_node_positions[u];
- Vector2 predecessor_node_size = Object::cast_to<GraphNode>(r_node_name[predecessor])->get_size();
- if (r_sink[p_v] != r_sink[u]) {
- real_t sc = pos.y + (real_t)r_inner_shift[w] - predecessor_root_pos.y - (real_t)r_inner_shift[predecessor] - predecessor_node_size.y - p_delta;
- r_shift[r_sink[u]] = MIN(sc, (real_t)r_shift[r_sink[u]]);
- } else {
- real_t sb = predecessor_root_pos.y + (real_t)r_inner_shift[predecessor] + predecessor_node_size.y - (real_t)r_inner_shift[w] + p_delta;
- sb = MAX(sb, threshold);
- if (initial) {
- pos.y = sb;
- } else {
- pos.y = MAX(pos.y, sb);
- }
- initial = false;
- }
- }
- threshold = _calculate_threshold(p_v, w, r_node_name, r_layers, r_root, r_align, r_inner_shift, threshold, r_node_positions);
- w = r_align[w];
- } while (w != p_v);
- r_node_positions.insert(p_v, pos);
- }
-
-#undef PRED
-}
-
void GraphEdit::arrange_nodes() {
- if (!arranging_graph) {
- arranging_graph = true;
- } else {
- return;
- }
-
- Dictionary node_names;
- HashSet<StringName> selected_nodes;
-
- bool arrange_entire_graph = true;
- for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
- continue;
- }
-
- node_names[gn->get_name()] = gn;
-
- if (gn->is_selected()) {
- arrange_entire_graph = false;
- }
- }
-
- HashMap<StringName, HashSet<StringName>> upper_neighbours;
- HashMap<StringName, Pair<int, int>> port_info;
- Vector2 origin(FLT_MAX, FLT_MAX);
-
- float gap_v = 100.0f;
- float gap_h = 100.0f;
-
- for (int i = get_child_count() - 1; i >= 0; i--) {
- GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (!gn) {
- continue;
- }
-
- if (gn->is_selected() || arrange_entire_graph) {
- selected_nodes.insert(gn->get_name());
- HashSet<StringName> s;
- for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
- GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from]);
- if (E->get().to == gn->get_name() && (p_from->is_selected() || arrange_entire_graph) && E->get().to != E->get().from) {
- if (!s.has(p_from->get_name())) {
- s.insert(p_from->get_name());
- }
- String s_connection = String(p_from->get_name()) + " " + String(E->get().to);
- StringName _connection(s_connection);
- Pair<int, int> ports(E->get().from_port, E->get().to_port);
- if (port_info.has(_connection)) {
- Pair<int, int> p_ports = port_info[_connection];
- if (p_ports.first < ports.first) {
- ports = p_ports;
- }
- }
- port_info.insert(_connection, ports);
- }
- }
- upper_neighbours.insert(gn->get_name(), s);
- }
- }
-
- if (!selected_nodes.size()) {
- arranging_graph = false;
- return;
- }
-
- HashMap<int, Vector<StringName>> layers = _layering(selected_nodes, upper_neighbours);
- _crossing_minimisation(layers, upper_neighbours);
-
- Dictionary root, align, sink, shift;
- _horizontal_alignment(root, align, layers, upper_neighbours, selected_nodes);
-
- HashMap<StringName, Vector2> new_positions;
- Vector2 default_position(FLT_MAX, FLT_MAX);
- Dictionary inner_shift;
- HashSet<StringName> block_heads;
-
- for (const StringName &E : selected_nodes) {
- inner_shift[E] = 0.0f;
- sink[E] = E;
- shift[E] = FLT_MAX;
- new_positions.insert(E, default_position);
- if ((StringName)root[E] == E) {
- block_heads.insert(E);
- }
- }
-
- _calculate_inner_shifts(inner_shift, root, node_names, align, block_heads, port_info);
-
- for (const StringName &E : block_heads) {
- _place_block(E, gap_v, layers, root, align, node_names, inner_shift, sink, shift, new_positions);
- }
- origin.y = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().y - (new_positions[layers[0][0]].y + (float)inner_shift[layers[0][0]]);
- origin.x = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().x;
-
- for (const StringName &E : block_heads) {
- StringName u = E;
- float start_from = origin.y + new_positions[E].y;
- do {
- Vector2 cal_pos;
- cal_pos.y = start_from + (real_t)inner_shift[u];
- new_positions.insert(u, cal_pos);
- u = align[u];
- } while (u != E);
- }
-
- // Compute horizontal coordinates individually for layers to get uniform gap.
- float start_from = origin.x;
- float largest_node_size = 0.0f;
-
- for (unsigned int i = 0; i < layers.size(); i++) {
- Vector<StringName> layer = layers[i];
- for (int j = 0; j < layer.size(); j++) {
- float current_node_size = Object::cast_to<GraphNode>(node_names[layer[j]])->get_size().x;
- largest_node_size = MAX(largest_node_size, current_node_size);
- }
-
- for (int j = 0; j < layer.size(); j++) {
- float current_node_size = Object::cast_to<GraphNode>(node_names[layer[j]])->get_size().x;
- Vector2 cal_pos = new_positions[layer[j]];
-
- if (current_node_size == largest_node_size) {
- cal_pos.x = start_from;
- } else {
- float current_node_start_pos = start_from;
- if (current_node_size < largest_node_size / 2) {
- if (!(i || j)) {
- start_from -= (largest_node_size - current_node_size);
- }
- current_node_start_pos = start_from + largest_node_size - current_node_size;
- }
- cal_pos.x = current_node_start_pos;
- }
- new_positions.insert(layer[j], cal_pos);
- }
-
- start_from += largest_node_size + gap_h;
- largest_node_size = 0.0f;
- }
-
- emit_signal(SNAME("begin_node_move"));
- for (const StringName &E : selected_nodes) {
- GraphNode *gn = Object::cast_to<GraphNode>(node_names[E]);
- gn->set_drag(true);
- Vector2 pos = (new_positions[E]);
-
- if (is_using_snap()) {
- const int snap = get_snap();
- pos = pos.snapped(Vector2(snap, snap));
- }
- gn->set_position_offset(pos);
- gn->set_drag(false);
- }
- emit_signal(SNAME("end_node_move"));
- arranging_graph = false;
+ arranger->arrange_nodes();
}
void GraphEdit::_bind_methods() {
@@ -2294,8 +1775,8 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_connection_list"), &GraphEdit::_get_connection_list);
ClassDB::bind_method(D_METHOD("clear_connections"), &GraphEdit::clear_connections);
ClassDB::bind_method(D_METHOD("force_connection_drag_end"), &GraphEdit::force_connection_drag_end);
- ClassDB::bind_method(D_METHOD("get_scroll_ofs"), &GraphEdit::get_scroll_ofs);
- ClassDB::bind_method(D_METHOD("set_scroll_ofs", "offset"), &GraphEdit::set_scroll_ofs);
+ ClassDB::bind_method(D_METHOD("get_scroll_offset"), &GraphEdit::get_scroll_offset);
+ ClassDB::bind_method(D_METHOD("set_scroll_offset", "offset"), &GraphEdit::set_scroll_offset);
ClassDB::bind_method(D_METHOD("add_valid_right_disconnect_type", "type"), &GraphEdit::add_valid_right_disconnect_type);
ClassDB::bind_method(D_METHOD("remove_valid_right_disconnect_type", "type"), &GraphEdit::remove_valid_right_disconnect_type);
@@ -2324,11 +1805,14 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_show_zoom_label", "enable"), &GraphEdit::set_show_zoom_label);
ClassDB::bind_method(D_METHOD("is_showing_zoom_label"), &GraphEdit::is_showing_zoom_label);
- ClassDB::bind_method(D_METHOD("set_snap", "pixels"), &GraphEdit::set_snap);
- ClassDB::bind_method(D_METHOD("get_snap"), &GraphEdit::get_snap);
+ ClassDB::bind_method(D_METHOD("set_show_grid", "enable"), &GraphEdit::set_show_grid);
+ ClassDB::bind_method(D_METHOD("is_showing_grid"), &GraphEdit::is_showing_grid);
+
+ ClassDB::bind_method(D_METHOD("set_snapping_enabled", "enable"), &GraphEdit::set_snapping_enabled);
+ ClassDB::bind_method(D_METHOD("is_snapping_enabled"), &GraphEdit::is_snapping_enabled);
- ClassDB::bind_method(D_METHOD("set_use_snap", "enable"), &GraphEdit::set_use_snap);
- ClassDB::bind_method(D_METHOD("is_using_snap"), &GraphEdit::is_using_snap);
+ ClassDB::bind_method(D_METHOD("set_snapping_distance", "pixels"), &GraphEdit::set_snapping_distance);
+ ClassDB::bind_method(D_METHOD("get_snapping_distance"), &GraphEdit::get_snapping_distance);
ClassDB::bind_method(D_METHOD("set_connection_lines_curvature", "curvature"), &GraphEdit::set_connection_lines_curvature);
ClassDB::bind_method(D_METHOD("get_connection_lines_curvature"), &GraphEdit::get_connection_lines_curvature);
@@ -2353,11 +1837,10 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_right_disconnects", "enable"), &GraphEdit::set_right_disconnects);
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
- ClassDB::bind_method(D_METHOD("_update_scroll_offset"), &GraphEdit::_update_scroll_offset);
GDVIRTUAL_BIND(_is_in_input_hotzone, "in_node", "in_port", "mouse_position");
GDVIRTUAL_BIND(_is_in_output_hotzone, "in_node", "in_port", "mouse_position");
- ClassDB::bind_method(D_METHOD("get_zoom_hbox"), &GraphEdit::get_zoom_hbox);
+ ClassDB::bind_method(D_METHOD("get_menu_hbox"), &GraphEdit::get_menu_hbox);
ClassDB::bind_method(D_METHOD("arrange_nodes"), &GraphEdit::arrange_nodes);
@@ -2367,9 +1850,10 @@ void GraphEdit::_bind_methods() {
GDVIRTUAL_BIND(_is_node_hover_valid, "from_node", "from_port", "to_node", "to_port");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "right_disconnects"), "set_right_disconnects", "is_right_disconnects_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_scroll_ofs", "get_scroll_ofs");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance", PROPERTY_HINT_NONE, "suffix:px"), "set_snap", "get_snap");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_snap"), "set_use_snap", "is_using_snap");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_scroll_offset", "get_scroll_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_grid"), "set_show_grid", "is_showing_grid");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snapping_enabled"), "set_snapping_enabled", "is_snapping_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "snapping_distance", PROPERTY_HINT_NONE, "suffix:px"), "set_snapping_distance", "get_snapping_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "panning_scheme", PROPERTY_HINT_ENUM, "Scroll Zooms,Scroll Pans"), "set_panning_scheme", "get_panning_scheme");
ADD_GROUP("Connection Lines", "connection_lines");
@@ -2435,93 +1919,103 @@ GraphEdit::GraphEdit() {
top_layer->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key));
connections_layer = memnew(Control);
- add_child(connections_layer, false, INTERNAL_MODE_FRONT);
+ add_child(connections_layer, false);
connections_layer->connect("draw", callable_mp(this, &GraphEdit::_connections_layer_draw));
- connections_layer->set_name("CLAYER");
- connections_layer->set_disable_visibility_clip(true); // so it can draw freely and be offset
+ connections_layer->set_name("_connection_layer");
+ connections_layer->set_disable_visibility_clip(true); // Necessary, so it can draw freely and be offset.
connections_layer->set_mouse_filter(MOUSE_FILTER_IGNORE);
- h_scroll = memnew(HScrollBar);
- h_scroll->set_name("_h_scroll");
- top_layer->add_child(h_scroll);
+ h_scrollbar = memnew(HScrollBar);
+ h_scrollbar->set_name("_h_scroll");
+ top_layer->add_child(h_scrollbar);
- v_scroll = memnew(VScrollBar);
- v_scroll->set_name("_v_scroll");
- top_layer->add_child(v_scroll);
+ v_scrollbar = memnew(VScrollBar);
+ v_scrollbar->set_name("_v_scroll");
+ top_layer->add_child(v_scrollbar);
- //set large minmax so it can scroll even if not resized yet
- h_scroll->set_min(-10000);
- h_scroll->set_max(10000);
+ // Set large minmax so it can scroll even if not resized yet.
+ h_scrollbar->set_min(-10000);
+ h_scrollbar->set_max(10000);
- v_scroll->set_min(-10000);
- v_scroll->set_max(10000);
+ v_scrollbar->set_min(-10000);
+ v_scrollbar->set_max(10000);
- h_scroll->connect("value_changed", callable_mp(this, &GraphEdit::_scroll_moved));
- v_scroll->connect("value_changed", callable_mp(this, &GraphEdit::_scroll_moved));
+ h_scrollbar->connect("value_changed", callable_mp(this, &GraphEdit::_scroll_moved));
+ v_scrollbar->connect("value_changed", callable_mp(this, &GraphEdit::_scroll_moved));
- zoom_hb = memnew(HBoxContainer);
- top_layer->add_child(zoom_hb);
- zoom_hb->set_position(Vector2(10, 10));
+ menu_hbox = memnew(HBoxContainer);
+ top_layer->add_child(menu_hbox);
+ menu_hbox->set_position(Vector2(10, 10));
zoom_label = memnew(Label);
- zoom_hb->add_child(zoom_label);
+ menu_hbox->add_child(zoom_label);
zoom_label->set_visible(false);
zoom_label->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
zoom_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
zoom_label->set_custom_minimum_size(Size2(48, 0));
_update_zoom_label();
- zoom_minus = memnew(Button);
- zoom_minus->set_flat(true);
- zoom_hb->add_child(zoom_minus);
- zoom_minus->set_tooltip_text(RTR("Zoom Out"));
- zoom_minus->connect("pressed", callable_mp(this, &GraphEdit::_zoom_minus));
- zoom_minus->set_focus_mode(FOCUS_NONE);
-
- zoom_reset = memnew(Button);
- zoom_reset->set_flat(true);
- zoom_hb->add_child(zoom_reset);
- zoom_reset->set_tooltip_text(RTR("Zoom Reset"));
- zoom_reset->connect("pressed", callable_mp(this, &GraphEdit::_zoom_reset));
- zoom_reset->set_focus_mode(FOCUS_NONE);
-
- zoom_plus = memnew(Button);
- zoom_plus->set_flat(true);
- zoom_hb->add_child(zoom_plus);
- zoom_plus->set_tooltip_text(RTR("Zoom In"));
- zoom_plus->connect("pressed", callable_mp(this, &GraphEdit::_zoom_plus));
- zoom_plus->set_focus_mode(FOCUS_NONE);
-
- snap_button = memnew(Button);
- snap_button->set_flat(true);
- snap_button->set_toggle_mode(true);
- snap_button->set_tooltip_text(RTR("Enable snap and show grid."));
- snap_button->connect("pressed", callable_mp(this, &GraphEdit::_snap_toggled));
- snap_button->set_pressed(true);
- snap_button->set_focus_mode(FOCUS_NONE);
- zoom_hb->add_child(snap_button);
-
- snap_amount = memnew(SpinBox);
- snap_amount->set_min(5);
- snap_amount->set_max(100);
- snap_amount->set_step(1);
- snap_amount->set_value(20);
- snap_amount->connect("value_changed", callable_mp(this, &GraphEdit::_snap_value_changed));
- zoom_hb->add_child(snap_amount);
+ zoom_minus_button = memnew(Button);
+ zoom_minus_button->set_flat(true);
+ menu_hbox->add_child(zoom_minus_button);
+ zoom_minus_button->set_tooltip_text(RTR("Zoom Out"));
+ zoom_minus_button->connect("pressed", callable_mp(this, &GraphEdit::_zoom_minus));
+ zoom_minus_button->set_focus_mode(FOCUS_NONE);
+
+ zoom_reset_button = memnew(Button);
+ zoom_reset_button->set_flat(true);
+ menu_hbox->add_child(zoom_reset_button);
+ zoom_reset_button->set_tooltip_text(RTR("Zoom Reset"));
+ zoom_reset_button->connect("pressed", callable_mp(this, &GraphEdit::_zoom_reset));
+ zoom_reset_button->set_focus_mode(FOCUS_NONE);
+
+ zoom_plus_button = memnew(Button);
+ zoom_plus_button->set_flat(true);
+ menu_hbox->add_child(zoom_plus_button);
+ zoom_plus_button->set_tooltip_text(RTR("Zoom In"));
+ zoom_plus_button->connect("pressed", callable_mp(this, &GraphEdit::_zoom_plus));
+ zoom_plus_button->set_focus_mode(FOCUS_NONE);
+
+ show_grid_button = memnew(Button);
+ show_grid_button->set_flat(true);
+ show_grid_button->set_toggle_mode(true);
+ show_grid_button->set_tooltip_text(RTR("Toggle the visual grid."));
+ show_grid_button->connect("pressed", callable_mp(this, &GraphEdit::_show_grid_toggled));
+ show_grid_button->set_pressed(true);
+ show_grid_button->set_focus_mode(FOCUS_NONE);
+ menu_hbox->add_child(show_grid_button);
+
+ toggle_snapping_button = memnew(Button);
+ toggle_snapping_button->set_flat(true);
+ toggle_snapping_button->set_toggle_mode(true);
+ toggle_snapping_button->set_tooltip_text(RTR("Toggle snapping to the grid."));
+ toggle_snapping_button->connect("pressed", callable_mp(this, &GraphEdit::_snapping_toggled));
+ toggle_snapping_button->set_pressed(snapping_enabled);
+ toggle_snapping_button->set_focus_mode(FOCUS_NONE);
+ menu_hbox->add_child(toggle_snapping_button);
+
+ snapping_distance_spinbox = memnew(SpinBox);
+ snapping_distance_spinbox->set_min(GRID_MIN_SNAPPING_DISTANCE);
+ snapping_distance_spinbox->set_max(GRID_MAX_SNAPPING_DISTANCE);
+ snapping_distance_spinbox->set_step(1);
+ snapping_distance_spinbox->set_value(snapping_distance);
+ snapping_distance_spinbox->set_tooltip_text(RTR("Change the snapping distance."));
+ snapping_distance_spinbox->connect("value_changed", callable_mp(this, &GraphEdit::_snapping_distance_changed));
+ menu_hbox->add_child(snapping_distance_spinbox);
minimap_button = memnew(Button);
minimap_button->set_flat(true);
minimap_button->set_toggle_mode(true);
- minimap_button->set_tooltip_text(RTR("Enable grid minimap."));
+ minimap_button->set_tooltip_text(RTR("Toggle the graph minimap."));
minimap_button->connect("pressed", callable_mp(this, &GraphEdit::_minimap_toggled));
- minimap_button->set_pressed(true);
+ minimap_button->set_pressed(show_grid);
minimap_button->set_focus_mode(FOCUS_NONE);
- zoom_hb->add_child(minimap_button);
+ menu_hbox->add_child(minimap_button);
layout_button = memnew(Button);
layout_button->set_flat(true);
- zoom_hb->add_child(layout_button);
- layout_button->set_tooltip_text(RTR("Arrange nodes."));
+ menu_hbox->add_child(layout_button);
+ layout_button->set_tooltip_text(RTR("Automatically arrange selected nodes."));
layout_button->connect("pressed", callable_mp(this, &GraphEdit::arrange_nodes));
layout_button->set_focus_mode(FOCUS_NONE);
@@ -2536,11 +2030,13 @@ GraphEdit::GraphEdit() {
minimap->set_custom_minimum_size(Vector2(50, 50));
minimap->set_size(minimap_size);
minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT);
- minimap->set_offset(Side::SIDE_LEFT, -minimap_size.x - MINIMAP_OFFSET);
- minimap->set_offset(Side::SIDE_TOP, -minimap_size.y - MINIMAP_OFFSET);
+ minimap->set_offset(Side::SIDE_LEFT, -minimap_size.width - MINIMAP_OFFSET);
+ minimap->set_offset(Side::SIDE_TOP, -minimap_size.height - MINIMAP_OFFSET);
minimap->set_offset(Side::SIDE_RIGHT, -MINIMAP_OFFSET);
minimap->set_offset(Side::SIDE_BOTTOM, -MINIMAP_OFFSET);
minimap->connect("draw", callable_mp(this, &GraphEdit::_minimap_draw));
set_clip_contents(true);
+
+ arranger = Ref<GraphEditArranger>(memnew(GraphEditArranger(this)));
}
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 8b02fbfddc..614e9b9695 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -39,6 +39,7 @@
#include "scene/gui/spin_box.h"
class GraphEdit;
+class GraphEditArranger;
class ViewPanner;
class GraphEditFilter : public Control {
@@ -47,6 +48,7 @@ class GraphEditFilter : public Control {
friend class GraphEdit;
friend class GraphEditMinimap;
GraphEdit *ge = nullptr;
+
virtual bool has_point(const Point2 &p_point) const override;
public:
@@ -58,9 +60,9 @@ class GraphEditMinimap : public Control {
friend class GraphEdit;
friend class GraphEditFilter;
+
GraphEdit *ge = nullptr;
-protected:
public:
GraphEditMinimap(GraphEdit *p_edit);
@@ -97,8 +99,8 @@ class GraphEdit : public Control {
public:
struct Connection {
- StringName from;
- StringName to;
+ StringName from_node;
+ StringName to_node;
int from_port = 0;
int to_port = 0;
float activity = 0.0;
@@ -111,33 +113,57 @@ public:
};
private:
- Label *zoom_label = nullptr;
- Button *zoom_minus = nullptr;
- Button *zoom_reset = nullptr;
- Button *zoom_plus = nullptr;
+ struct ConnectionType {
+ union {
+ struct {
+ uint32_t type_a;
+ uint32_t type_b;
+ };
+ uint64_t key = 0;
+ };
- Button *snap_button = nullptr;
- SpinBox *snap_amount = nullptr;
+ static uint32_t hash(const ConnectionType &p_conn) {
+ return hash_one_uint64(p_conn.key);
+ }
+ bool operator==(const ConnectionType &p_type) const {
+ return key == p_type.key;
+ }
+
+ ConnectionType(uint32_t a = 0, uint32_t b = 0) {
+ type_a = a;
+ type_b = b;
+ }
+ };
+
+ Label *zoom_label = nullptr;
+ Button *zoom_minus_button = nullptr;
+ Button *zoom_reset_button = nullptr;
+ Button *zoom_plus_button = nullptr;
+ Button *toggle_snapping_button = nullptr;
+ SpinBox *snapping_distance_spinbox = nullptr;
+ Button *show_grid_button = nullptr;
Button *minimap_button = nullptr;
Button *layout_button = nullptr;
- HScrollBar *h_scroll = nullptr;
- VScrollBar *v_scroll = nullptr;
+ 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;
- 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);
bool arrange_nodes_button_hidden = false;
+ bool snapping_enabled = true;
+ int snapping_distance = 20;
+ bool show_grid = true;
+
bool connecting = false;
- StringName connecting_from;
+ String connecting_from;
bool connecting_out = false;
int connecting_index = 0;
int connecting_type = 0;
@@ -146,8 +172,10 @@ private:
Vector2 connecting_to;
StringName connecting_target_to;
int connecting_target_index = 0;
+
bool just_disconnected = false;
bool connecting_valid = false;
+
Vector2 click_pos;
PanningScheme panning_scheme = SCROLL_ZOOMS;
@@ -162,19 +190,14 @@ private:
float zoom_min = 0.0;
float zoom_max = 0.0;
- void _zoom_minus();
- void _zoom_reset();
- void _zoom_plus();
- void _update_zoom_label();
-
bool box_selecting = false;
bool box_selection_mode_additive = false;
Point2 box_selecting_from;
Point2 box_selecting_to;
Rect2 box_selecting_rect;
- List<GraphNode *> previous_selected;
+ List<GraphNode *> prev_selected;
- bool setting_scroll_ofs = false;
+ bool setting_scroll_offset = false;
bool right_disconnects = false;
bool updating = false;
bool awaiting_scroll_offset_update = false;
@@ -184,102 +207,69 @@ private:
float lines_curvature = 0.5f;
bool lines_antialiased = true;
+ HBoxContainer *menu_hbox = nullptr;
+ Control *connections_layer = nullptr;
+ GraphEditFilter *top_layer = nullptr;
+ GraphEditMinimap *minimap = nullptr;
+
+ Ref<GraphEditArranger> arranger;
+
+ HashSet<ConnectionType, ConnectionType> valid_connection_types;
+ HashSet<int> valid_left_disconnect_types;
+ HashSet<int> valid_right_disconnect_types;
+
+ void _scroll_callback(Vector2 p_scroll_vec, bool p_alt);
+ 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);
+
+ void _zoom_minus();
+ void _zoom_reset();
+ void _zoom_plus();
+ void _update_zoom_label();
+
PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to);
void _draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom);
void _graph_node_selected(Node *p_gn);
void _graph_node_deselected(Node *p_gn);
- void _graph_node_raised(Node *p_gn);
+ void _graph_node_moved_to_front(Node *p_gn);
+ void _graph_node_resized(Vector2 p_new_minsize, Node *p_gn);
void _graph_node_moved(Node *p_gn);
void _graph_node_slot_updated(int p_index, Node *p_gn);
void _update_scroll();
+ void _update_scroll_offset();
void _scroll_moved(double);
virtual void gui_input(const Ref<InputEvent> &p_ev) override;
-
- Control *connections_layer = nullptr;
- GraphEditFilter *top_layer = nullptr;
- GraphEditMinimap *minimap = nullptr;
void _top_layer_input(const Ref<InputEvent> &p_ev);
- bool is_in_input_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
- bool is_in_output_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
- bool is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left);
+ bool is_in_input_hotzone(GraphNode *p_graph_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
+ bool is_in_output_hotzone(GraphNode *p_graph_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
+ bool is_in_port_hotzone(const Vector2 &p_pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left);
void _top_layer_draw();
void _connections_layer_draw();
void _minimap_draw();
- void _update_scroll_offset();
TypedArray<Dictionary> _get_connection_list() const;
- bool lines_on_bg = false;
-
- struct ConnType {
- union {
- struct {
- uint32_t type_a;
- uint32_t type_b;
- };
- uint64_t key = 0;
- };
-
- static uint32_t hash(const ConnType &p_conn) {
- return hash_one_uint64(p_conn.key);
- }
- bool operator==(const ConnType &p_type) const {
- return key == p_type.key;
- }
-
- ConnType(uint32_t a = 0, uint32_t b = 0) {
- type_a = a;
- type_b = b;
- }
- };
-
- HashSet<ConnType, ConnType> valid_connection_types;
- HashSet<int> valid_left_disconnect_types;
- HashSet<int> valid_right_disconnect_types;
-
- HashMap<StringName, Vector<GraphNode *>> comment_enclosed_nodes;
- void _update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes);
- void _set_drag_comment_enclosed_nodes(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes, bool p_drag);
- void _set_position_of_comment_enclosed_nodes(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes, Vector2 p_pos);
-
- HBoxContainer *zoom_hb = nullptr;
-
friend class GraphEditFilter;
bool _filter_input(const Point2 &p_point);
- void _snap_toggled();
- void _snap_value_changed(double);
+ void _snapping_toggled();
+ void _snapping_distance_changed(double);
+ void _show_grid_toggled();
friend class GraphEditMinimap;
void _minimap_toggled();
bool _check_clickable_control(Control *p_control, const Vector2 &r_mouse_pos, const Vector2 &p_offset);
- bool arranging_graph = false;
-
- enum SET_OPERATIONS {
- IS_EQUAL,
- IS_SUBSET,
- DIFFERENCE,
- UNION,
- };
-
- int _set_operations(SET_OPERATIONS p_operation, HashSet<StringName> &r_u, const HashSet<StringName> &r_v);
- HashMap<int, Vector<StringName>> _layering(const HashSet<StringName> &r_selected_nodes, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours);
- Vector<StringName> _split(const Vector<StringName> &r_layer, const HashMap<StringName, Dictionary> &r_crossings);
- void _horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours, const HashSet<StringName> &r_selected_nodes);
- void _crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours);
- void _calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const HashSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info);
- float _calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions);
- void _place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions);
-
protected:
static void _bind_methods();
+
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
+
void _notification(int p_what);
GDVIRTUAL2RC(Vector<Vector2>, _get_connection_line, Vector2, Vector2)
@@ -337,6 +327,7 @@ public:
GraphEditFilter *get_top_layer() const { return top_layer; }
GraphEditMinimap *get_minimap() const { return minimap; }
+
void get_connection_list(List<Connection> *r_connections) const;
void set_right_disconnects(bool p_enable);
@@ -348,16 +339,19 @@ public:
void add_valid_left_disconnect_type(int p_type);
void remove_valid_left_disconnect_type(int p_type);
- void set_scroll_ofs(const Vector2 &p_ofs);
- Vector2 get_scroll_ofs() const;
+ void set_scroll_offset(const Vector2 &p_ofs);
+ Vector2 get_scroll_offset() const;
void set_selected(Node *p_child);
- void set_use_snap(bool p_enable);
- bool is_using_snap() const;
+ void set_snapping_enabled(bool p_enable);
+ bool is_snapping_enabled() const;
+
+ void set_snapping_distance(int p_snapping_distance);
+ int get_snapping_distance() const;
- int get_snap() const;
- void set_snap(int p_snap);
+ void set_show_grid(bool p_enable);
+ bool is_showing_grid() const;
void set_connection_lines_curvature(float p_curvature);
float get_connection_lines_curvature() const;
@@ -368,7 +362,7 @@ public:
void set_connection_lines_antialiased(bool p_antialiased);
bool is_connection_lines_antialiased() const;
- HBoxContainer *get_zoom_hbox();
+ HBoxContainer *get_menu_hbox();
Ref<ViewPanner> get_panner();
void set_warped_panning(bool p_warped);
diff --git a/scene/gui/graph_edit_arranger.cpp b/scene/gui/graph_edit_arranger.cpp
new file mode 100644
index 0000000000..f4d9dcbf95
--- /dev/null
+++ b/scene/gui/graph_edit_arranger.cpp
@@ -0,0 +1,565 @@
+/**************************************************************************/
+/* graph_edit_arranger.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 "graph_edit_arranger.h"
+
+#include "scene/gui/graph_edit.h"
+
+void GraphEditArranger::arrange_nodes() {
+ ERR_FAIL_COND(!graph_edit);
+
+ if (!arranging_graph) {
+ arranging_graph = true;
+ } else {
+ return;
+ }
+
+ Dictionary node_names;
+ HashSet<StringName> selected_nodes;
+
+ bool arrange_entire_graph = true;
+ for (int i = graph_edit->get_child_count() - 1; i >= 0; i--) {
+ GraphNode *graph_element = Object::cast_to<GraphNode>(graph_edit->get_child(i));
+ if (!graph_element) {
+ continue;
+ }
+
+ node_names[graph_element->get_name()] = graph_element;
+
+ if (graph_element->is_selected()) {
+ arrange_entire_graph = false;
+ }
+ }
+
+ HashMap<StringName, HashSet<StringName>> upper_neighbours;
+ HashMap<StringName, Pair<int, int>> port_info;
+ Vector2 origin(FLT_MAX, FLT_MAX);
+
+ float gap_v = 100.0f;
+ float gap_h = 100.0f;
+
+ for (int i = graph_edit->get_child_count() - 1; i >= 0; i--) {
+ GraphNode *graph_element = Object::cast_to<GraphNode>(graph_edit->get_child(i));
+ if (!graph_element) {
+ continue;
+ }
+
+ if (graph_element->is_selected() || arrange_entire_graph) {
+ selected_nodes.insert(graph_element->get_name());
+ HashSet<StringName> s;
+ List<GraphEdit::Connection> connection_list;
+ graph_edit->get_connection_list(&connection_list);
+ for (List<GraphEdit::Connection>::Element *E = connection_list.front(); E; E = E->next()) {
+ GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from_node]);
+ if (E->get().to_node == graph_element->get_name() && (p_from->is_selected() || arrange_entire_graph) && E->get().to_node != E->get().from_node) {
+ if (!s.has(p_from->get_name())) {
+ s.insert(p_from->get_name());
+ }
+ String s_connection = String(p_from->get_name()) + " " + String(E->get().to_node);
+ StringName _connection(s_connection);
+ Pair<int, int> ports(E->get().from_port, E->get().to_port);
+ if (port_info.has(_connection)) {
+ Pair<int, int> p_ports = port_info[_connection];
+ if (p_ports.first < ports.first) {
+ ports = p_ports;
+ }
+ }
+ port_info.insert(_connection, ports);
+ }
+ }
+ upper_neighbours.insert(graph_element->get_name(), s);
+ }
+ }
+
+ if (!selected_nodes.size()) {
+ arranging_graph = false;
+ return;
+ }
+
+ HashMap<int, Vector<StringName>> layers = _layering(selected_nodes, upper_neighbours);
+ _crossing_minimisation(layers, upper_neighbours);
+
+ Dictionary root, align, sink, shift;
+ _horizontal_alignment(root, align, layers, upper_neighbours, selected_nodes);
+
+ HashMap<StringName, Vector2> new_positions;
+ Vector2 default_position(FLT_MAX, FLT_MAX);
+ Dictionary inner_shift;
+ HashSet<StringName> block_heads;
+
+ for (const StringName &E : selected_nodes) {
+ inner_shift[E] = 0.0f;
+ sink[E] = E;
+ shift[E] = FLT_MAX;
+ new_positions.insert(E, default_position);
+ if ((StringName)root[E] == E) {
+ block_heads.insert(E);
+ }
+ }
+
+ _calculate_inner_shifts(inner_shift, root, node_names, align, block_heads, port_info);
+
+ for (const StringName &E : block_heads) {
+ _place_block(E, gap_v, layers, root, align, node_names, inner_shift, sink, shift, new_positions);
+ }
+ origin.y = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().y - (new_positions[layers[0][0]].y + (float)inner_shift[layers[0][0]]);
+ origin.x = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().x;
+
+ for (const StringName &E : block_heads) {
+ StringName u = E;
+ float start_from = origin.y + new_positions[E].y;
+ do {
+ Vector2 cal_pos;
+ cal_pos.y = start_from + (real_t)inner_shift[u];
+ new_positions.insert(u, cal_pos);
+ u = align[u];
+ } while (u != E);
+ }
+
+ // Compute horizontal coordinates individually for layers to get uniform gap.
+ float start_from = origin.x;
+ float largest_node_size = 0.0f;
+
+ for (unsigned int i = 0; i < layers.size(); i++) {
+ Vector<StringName> layer = layers[i];
+ for (int j = 0; j < layer.size(); j++) {
+ float current_node_size = Object::cast_to<GraphNode>(node_names[layer[j]])->get_size().x;
+ largest_node_size = MAX(largest_node_size, current_node_size);
+ }
+
+ for (int j = 0; j < layer.size(); j++) {
+ float current_node_size = Object::cast_to<GraphNode>(node_names[layer[j]])->get_size().x;
+ Vector2 cal_pos = new_positions[layer[j]];
+
+ if (current_node_size == largest_node_size) {
+ cal_pos.x = start_from;
+ } else {
+ float current_node_start_pos = start_from;
+ if (current_node_size < largest_node_size / 2) {
+ if (!(i || j)) {
+ start_from -= (largest_node_size - current_node_size);
+ }
+ current_node_start_pos = start_from + largest_node_size - current_node_size;
+ }
+ cal_pos.x = current_node_start_pos;
+ }
+ new_positions.insert(layer[j], cal_pos);
+ }
+
+ start_from += largest_node_size + gap_h;
+ largest_node_size = 0.0f;
+ }
+
+ graph_edit->emit_signal(SNAME("begin_node_move"));
+ for (const StringName &E : selected_nodes) {
+ GraphNode *graph_node = Object::cast_to<GraphNode>(node_names[E]);
+ graph_node->set_drag(true);
+ Vector2 pos = (new_positions[E]);
+
+ if (graph_edit->is_snapping_enabled()) {
+ float snapping_distance = graph_edit->get_snapping_distance();
+ pos = pos.snapped(Vector2(snapping_distance, snapping_distance));
+ }
+ graph_node->set_position_offset(pos);
+ graph_node->set_drag(false);
+ }
+ graph_edit->emit_signal(SNAME("end_node_move"));
+ arranging_graph = false;
+}
+
+int GraphEditArranger::_set_operations(SET_OPERATIONS p_operation, HashSet<StringName> &r_u, const HashSet<StringName> &r_v) {
+ switch (p_operation) {
+ case GraphEditArranger::IS_EQUAL: {
+ for (const StringName &E : r_u) {
+ if (!r_v.has(E)) {
+ return 0;
+ }
+ }
+ return r_u.size() == r_v.size();
+ } break;
+ case GraphEditArranger::IS_SUBSET: {
+ if (r_u.size() == r_v.size() && !r_u.size()) {
+ return 1;
+ }
+ for (const StringName &E : r_u) {
+ if (!r_v.has(E)) {
+ return 0;
+ }
+ }
+ return 1;
+ } break;
+ case GraphEditArranger::DIFFERENCE: {
+ for (HashSet<StringName>::Iterator E = r_u.begin(); E;) {
+ HashSet<StringName>::Iterator N = E;
+ ++N;
+ if (r_v.has(*E)) {
+ r_u.remove(E);
+ }
+ E = N;
+ }
+ return r_u.size();
+ } break;
+ case GraphEditArranger::UNION: {
+ for (const StringName &E : r_v) {
+ if (!r_u.has(E)) {
+ r_u.insert(E);
+ }
+ }
+ return r_u.size();
+ } break;
+ default:
+ break;
+ }
+ return -1;
+}
+
+HashMap<int, Vector<StringName>> GraphEditArranger::_layering(const HashSet<StringName> &r_selected_nodes, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours) {
+ HashMap<int, Vector<StringName>> l;
+
+ HashSet<StringName> p = r_selected_nodes, q = r_selected_nodes, u, z;
+ int current_layer = 0;
+ bool selected = false;
+
+ while (!_set_operations(GraphEditArranger::IS_EQUAL, q, u)) {
+ _set_operations(GraphEditArranger::DIFFERENCE, p, u);
+ for (const StringName &E : p) {
+ HashSet<StringName> n = r_upper_neighbours[E];
+ if (_set_operations(GraphEditArranger::IS_SUBSET, n, z)) {
+ Vector<StringName> t;
+ t.push_back(E);
+ if (!l.has(current_layer)) {
+ l.insert(current_layer, Vector<StringName>{});
+ }
+ selected = true;
+ t.append_array(l[current_layer]);
+ l.insert(current_layer, t);
+ HashSet<StringName> V;
+ V.insert(E);
+ _set_operations(GraphEditArranger::UNION, u, V);
+ }
+ }
+ if (!selected) {
+ current_layer++;
+ uint32_t previous_size_z = z.size();
+ _set_operations(GraphEditArranger::UNION, z, u);
+ if (z.size() == previous_size_z) {
+ WARN_PRINT("Graph contains cycle(s). The cycle(s) will not be rearranged accurately.");
+ Vector<StringName> t;
+ if (l.has(0)) {
+ t.append_array(l[0]);
+ }
+ for (const StringName &E : p) {
+ t.push_back(E);
+ }
+ l.insert(0, t);
+ break;
+ }
+ }
+ selected = false;
+ }
+
+ return l;
+}
+
+Vector<StringName> GraphEditArranger::_split(const Vector<StringName> &r_layer, const HashMap<StringName, Dictionary> &r_crossings) {
+ if (!r_layer.size()) {
+ return Vector<StringName>();
+ }
+
+ StringName p = r_layer[Math::random(0, r_layer.size() - 1)];
+ Vector<StringName> left;
+ Vector<StringName> right;
+
+ for (int i = 0; i < r_layer.size(); i++) {
+ if (p != r_layer[i]) {
+ StringName q = r_layer[i];
+ int cross_pq = r_crossings[p][q];
+ int cross_qp = r_crossings[q][p];
+ if (cross_pq > cross_qp) {
+ left.push_back(q);
+ } else {
+ right.push_back(q);
+ }
+ }
+ }
+
+ left.push_back(p);
+ left.append_array(right);
+ return left;
+}
+
+void GraphEditArranger::_horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours, const HashSet<StringName> &r_selected_nodes) {
+ for (const StringName &E : r_selected_nodes) {
+ r_root[E] = E;
+ r_align[E] = E;
+ }
+
+ if (r_layers.size() == 1) {
+ return;
+ }
+
+ for (unsigned int i = 1; i < r_layers.size(); i++) {
+ Vector<StringName> lower_layer = r_layers[i];
+ Vector<StringName> upper_layer = r_layers[i - 1];
+ int r = -1;
+
+ for (int j = 0; j < lower_layer.size(); j++) {
+ Vector<Pair<int, StringName>> up;
+ StringName current_node = lower_layer[j];
+ for (int k = 0; k < upper_layer.size(); k++) {
+ StringName adjacent_neighbour = upper_layer[k];
+ if (r_upper_neighbours[current_node].has(adjacent_neighbour)) {
+ up.push_back(Pair<int, StringName>(k, adjacent_neighbour));
+ }
+ }
+
+ int start = (up.size() - 1) / 2;
+ int end = (up.size() - 1) % 2 ? start + 1 : start;
+ for (int p = start; p <= end; p++) {
+ StringName Align = r_align[current_node];
+ if (Align == current_node && r < up[p].first) {
+ r_align[up[p].second] = lower_layer[j];
+ r_root[current_node] = r_root[up[p].second];
+ r_align[current_node] = r_root[up[p].second];
+ r = up[p].first;
+ }
+ }
+ }
+ }
+}
+
+void GraphEditArranger::_crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours) {
+ if (r_layers.size() == 1) {
+ return;
+ }
+
+ for (unsigned int i = 1; i < r_layers.size(); i++) {
+ Vector<StringName> upper_layer = r_layers[i - 1];
+ Vector<StringName> lower_layer = r_layers[i];
+ HashMap<StringName, Dictionary> c;
+
+ for (int j = 0; j < lower_layer.size(); j++) {
+ StringName p = lower_layer[j];
+ Dictionary d;
+
+ for (int k = 0; k < lower_layer.size(); k++) {
+ unsigned int crossings = 0;
+ StringName q = lower_layer[k];
+
+ if (j != k) {
+ for (int h = 1; h < upper_layer.size(); h++) {
+ if (r_upper_neighbours[p].has(upper_layer[h])) {
+ for (int g = 0; g < h; g++) {
+ if (r_upper_neighbours[q].has(upper_layer[g])) {
+ crossings++;
+ }
+ }
+ }
+ }
+ }
+ d[q] = crossings;
+ }
+ c.insert(p, d);
+ }
+
+ r_layers.insert(i, _split(lower_layer, c));
+ }
+}
+
+void GraphEditArranger::_calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const HashSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info) {
+ for (const StringName &E : r_block_heads) {
+ real_t left = 0;
+ StringName u = E;
+ StringName v = r_align[u];
+ while (u != v && (StringName)r_root[u] != v) {
+ String _connection = String(u) + " " + String(v);
+
+ GraphNode *gnode_from = Object::cast_to<GraphNode>(r_node_names[u]);
+ GraphNode *gnode_to = Object::cast_to<GraphNode>(r_node_names[v]);
+
+ Pair<int, int> ports = r_port_info[_connection];
+ int port_from = ports.first;
+ int port_to = ports.second;
+
+ Vector2 pos_from = gnode_from->get_connection_output_position(port_from) * graph_edit->get_zoom();
+ Vector2 pos_to = gnode_to->get_connection_input_position(port_to) * graph_edit->get_zoom();
+
+ real_t s = (real_t)r_inner_shifts[u] + (pos_from.y - pos_to.y) / graph_edit->get_zoom();
+ r_inner_shifts[v] = s;
+ left = MIN(left, s);
+
+ u = v;
+ v = (StringName)r_align[v];
+ }
+
+ u = E;
+ do {
+ r_inner_shifts[u] = (real_t)r_inner_shifts[u] - left;
+ u = (StringName)r_align[u];
+ } while (u != E);
+ }
+}
+
+float GraphEditArranger::_calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions) {
+#define MAX_ORDER 2147483647
+#define ORDER(node, layers) \
+ for (unsigned int i = 0; i < layers.size(); i++) { \
+ int index = layers[i].find(node); \
+ if (index > 0) { \
+ order = index; \
+ break; \
+ } \
+ order = MAX_ORDER; \
+ }
+
+ int order = MAX_ORDER;
+ float threshold = p_current_threshold;
+ if (p_v == p_w) {
+ int min_order = MAX_ORDER;
+ GraphEdit::Connection incoming;
+ List<GraphEdit::Connection> connection_list;
+ graph_edit->get_connection_list(&connection_list);
+ for (List<GraphEdit::Connection>::Element *E = connection_list.front(); E; E = E->next()) {
+ if (E->get().to_node == p_w) {
+ ORDER(E->get().from_node, r_layers);
+ if (min_order > order) {
+ min_order = order;
+ incoming = E->get();
+ }
+ }
+ }
+
+ if (incoming.from_node != StringName()) {
+ GraphNode *gnode_from = Object::cast_to<GraphNode>(r_node_names[incoming.from_node]);
+ GraphNode *gnode_to = Object::cast_to<GraphNode>(r_node_names[p_w]);
+ Vector2 pos_from = gnode_from->get_connection_output_position(incoming.from_port) * graph_edit->get_zoom();
+ Vector2 pos_to = gnode_to->get_connection_input_position(incoming.to_port) * graph_edit->get_zoom();
+
+ // If connected block node is selected, calculate thershold or add current block to list.
+ if (gnode_from->is_selected()) {
+ Vector2 connected_block_pos = r_node_positions[r_root[incoming.from_node]];
+ if (connected_block_pos.y != FLT_MAX) {
+ //Connected block is placed, calculate threshold.
+ threshold = connected_block_pos.y + (real_t)r_inner_shift[incoming.from_node] - (real_t)r_inner_shift[p_w] + pos_from.y - pos_to.y;
+ }
+ }
+ }
+ }
+ if (threshold == FLT_MIN && (StringName)r_align[p_w] == p_v) {
+ // This time, pick an outgoing edge and repeat as above!
+ int min_order = MAX_ORDER;
+ GraphEdit::Connection outgoing;
+ List<GraphEdit::Connection> connection_list;
+ graph_edit->get_connection_list(&connection_list);
+ for (List<GraphEdit::Connection>::Element *E = connection_list.front(); E; E = E->next()) {
+ if (E->get().from_node == p_w) {
+ ORDER(E->get().to_node, r_layers);
+ if (min_order > order) {
+ min_order = order;
+ outgoing = E->get();
+ }
+ }
+ }
+
+ if (outgoing.to_node != StringName()) {
+ GraphNode *gnode_from = Object::cast_to<GraphNode>(r_node_names[p_w]);
+ GraphNode *gnode_to = Object::cast_to<GraphNode>(r_node_names[outgoing.to_node]);
+ Vector2 pos_from = gnode_from->get_connection_output_position(outgoing.from_port) * graph_edit->get_zoom();
+ Vector2 pos_to = gnode_to->get_connection_input_position(outgoing.to_port) * graph_edit->get_zoom();
+
+ // If connected block node is selected, calculate thershold or add current block to list.
+ if (gnode_to->is_selected()) {
+ Vector2 connected_block_pos = r_node_positions[r_root[outgoing.to_node]];
+ if (connected_block_pos.y != FLT_MAX) {
+ //Connected block is placed. Calculate threshold
+ threshold = connected_block_pos.y + (real_t)r_inner_shift[outgoing.to_node] - (real_t)r_inner_shift[p_w] + pos_from.y - pos_to.y;
+ }
+ }
+ }
+ }
+#undef MAX_ORDER
+#undef ORDER
+ return threshold;
+}
+
+void GraphEditArranger::_place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions) {
+#define PRED(node, layers) \
+ for (unsigned int i = 0; i < layers.size(); i++) { \
+ int index = layers[i].find(node); \
+ if (index > 0) { \
+ predecessor = layers[i][index - 1]; \
+ break; \
+ } \
+ predecessor = StringName(); \
+ }
+
+ StringName predecessor;
+ StringName successor;
+ Vector2 pos = r_node_positions[p_v];
+
+ if (pos.y == FLT_MAX) {
+ pos.y = 0;
+ bool initial = false;
+ StringName w = p_v;
+ real_t threshold = FLT_MIN;
+ do {
+ PRED(w, r_layers);
+ if (predecessor != StringName()) {
+ StringName u = r_root[predecessor];
+ _place_block(u, p_delta, r_layers, r_root, r_align, r_node_name, r_inner_shift, r_sink, r_shift, r_node_positions);
+ threshold = _calculate_threshold(p_v, w, r_node_name, r_layers, r_root, r_align, r_inner_shift, threshold, r_node_positions);
+ if ((StringName)r_sink[p_v] == p_v) {
+ r_sink[p_v] = r_sink[u];
+ }
+
+ Vector2 predecessor_root_pos = r_node_positions[u];
+ Vector2 predecessor_node_size = Object::cast_to<GraphNode>(r_node_name[predecessor])->get_size();
+ if (r_sink[p_v] != r_sink[u]) {
+ real_t sc = pos.y + (real_t)r_inner_shift[w] - predecessor_root_pos.y - (real_t)r_inner_shift[predecessor] - predecessor_node_size.y - p_delta;
+ r_shift[r_sink[u]] = MIN(sc, (real_t)r_shift[r_sink[u]]);
+ } else {
+ real_t sb = predecessor_root_pos.y + (real_t)r_inner_shift[predecessor] + predecessor_node_size.y - (real_t)r_inner_shift[w] + p_delta;
+ sb = MAX(sb, threshold);
+ if (initial) {
+ pos.y = sb;
+ } else {
+ pos.y = MAX(pos.y, sb);
+ }
+ initial = false;
+ }
+ }
+ threshold = _calculate_threshold(p_v, w, r_node_name, r_layers, r_root, r_align, r_inner_shift, threshold, r_node_positions);
+ w = r_align[w];
+ } while (w != p_v);
+ r_node_positions.insert(p_v, pos);
+ }
+
+#undef PRED
+}
diff --git a/scene/gui/graph_edit_arranger.h b/scene/gui/graph_edit_arranger.h
new file mode 100644
index 0000000000..e79944e5dd
--- /dev/null
+++ b/scene/gui/graph_edit_arranger.h
@@ -0,0 +1,67 @@
+/**************************************************************************/
+/* graph_edit_arranger.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 GRAPH_EDIT_ARRANGER_H
+#define GRAPH_EDIT_ARRANGER_H
+
+#include "core/object/ref_counted.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/hash_set.h"
+
+class GraphEdit;
+
+class GraphEditArranger : public RefCounted {
+ enum SET_OPERATIONS {
+ IS_EQUAL,
+ IS_SUBSET,
+ DIFFERENCE,
+ UNION,
+ };
+
+ GraphEdit *graph_edit = nullptr;
+ bool arranging_graph = false;
+
+ int _set_operations(SET_OPERATIONS p_operation, HashSet<StringName> &r_u, const HashSet<StringName> &r_v);
+ HashMap<int, Vector<StringName>> _layering(const HashSet<StringName> &r_selected_nodes, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours);
+ Vector<StringName> _split(const Vector<StringName> &r_layer, const HashMap<StringName, Dictionary> &r_crossings);
+ void _horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours, const HashSet<StringName> &r_selected_nodes);
+ void _crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours);
+ void _calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const HashSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info);
+ float _calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions);
+ void _place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions);
+
+public:
+ void arrange_nodes();
+
+ GraphEditArranger(GraphEdit *p_graph_edit) :
+ graph_edit(p_graph_edit) {}
+};
+
+#endif // GRAPH_EDIT_ARRANGER_H
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index b0517caab0..2223beafda 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -286,37 +286,12 @@ void GraphNode::_resort() {
connpos_dirty = true;
}
-bool GraphNode::has_point(const Point2 &p_point) const {
- if (comment) {
- Ref<StyleBox> comment_sb = get_theme_stylebox(SNAME("comment"));
- Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
-
- if (Rect2(get_size() - resizer->get_size(), resizer->get_size()).has_point(p_point)) {
- return true;
- }
-
- if (Rect2(0, 0, get_size().width, comment_sb->get_margin(SIDE_TOP)).has_point(p_point)) {
- return true;
- }
-
- return false;
-
- } else {
- return Control::has_point(p_point);
- }
-}
-
void GraphNode::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
Ref<StyleBox> sb;
- if (comment) {
- sb = get_theme_stylebox(selected ? SNAME("comment_focus") : SNAME("comment"));
-
- } else {
- sb = get_theme_stylebox(selected ? SNAME("selected_frame") : SNAME("frame"));
- }
+ sb = get_theme_stylebox(selected ? SNAME("selected_frame") : SNAME("frame"));
Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
@@ -440,7 +415,7 @@ void GraphNode::_shape() {
void GraphNode::_edit_set_position(const Point2 &p_position) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
- Point2 offset = (p_position + graph->get_scroll_ofs()) * graph->get_zoom();
+ Point2 offset = (p_position + graph->get_scroll_offset()) * graph->get_zoom();
set_position_offset(offset);
}
set_position(p_position);
@@ -1003,19 +978,6 @@ GraphNode::Overlay GraphNode::get_overlay() const {
return overlay;
}
-void GraphNode::set_comment(bool p_enable) {
- if (comment == p_enable) {
- return;
- }
-
- comment = p_enable;
- queue_redraw();
-}
-
-bool GraphNode::is_comment() const {
- return comment;
-}
-
void GraphNode::set_resizable(bool p_enable) {
if (resizable == p_enable) {
return;
@@ -1115,9 +1077,6 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_position_offset", "offset"), &GraphNode::set_position_offset);
ClassDB::bind_method(D_METHOD("get_position_offset"), &GraphNode::get_position_offset);
- ClassDB::bind_method(D_METHOD("set_comment", "comment"), &GraphNode::set_comment);
- ClassDB::bind_method(D_METHOD("is_comment"), &GraphNode::is_comment);
-
ClassDB::bind_method(D_METHOD("set_resizable", "resizable"), &GraphNode::set_resizable);
ClassDB::bind_method(D_METHOD("is_resizable"), &GraphNode::is_resizable);
@@ -1157,7 +1116,6 @@ void GraphNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draggable"), "set_draggable", "is_draggable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selectable"), "set_selectable", "is_selectable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selected"), "set_selected", "is_selected");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "comment"), "set_comment", "is_comment");
ADD_PROPERTY(PropertyInfo(Variant::INT, "overlay", PROPERTY_HINT_ENUM, "Disabled,Breakpoint,Position"), "set_overlay", "get_overlay");
ADD_GROUP("BiDi", "");
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 7ba2e6db94..873683bc62 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -124,8 +124,6 @@ protected:
void _validate_property(PropertyInfo &p_property) const;
public:
- bool has_point(const Point2 &p_point) const override;
-
void set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left = Ref<Texture2D>(), const Ref<Texture2D> &p_custom_right = Ref<Texture2D>(), bool p_draw_stylebox = true);
void clear_slot(int p_idx);
void clear_all_slots();
@@ -189,9 +187,6 @@ public:
void set_overlay(Overlay p_overlay);
Overlay get_overlay() const;
- void set_comment(bool p_enable);
- bool is_comment() const;
-
void set_resizable(bool p_enable);
bool is_resizable() const;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index aa9ecd4142..b273f709f2 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -1265,9 +1265,6 @@ void ItemList::_notification(int p_what) {
if (rtl) {
text_ofs.x = size.width - width;
- }
-
- if (rtl) {
items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
} else {
items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_LEFT);
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 1b48b9165d..9242105b47 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -31,7 +31,6 @@
#include "label.h"
#include "core/config/project_settings.h"
-#include "core/core_string_names.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
@@ -304,6 +303,9 @@ void Label::_update_visible() {
break;
}
}
+ if (minsize.height > 0) {
+ minsize.height -= line_spacing;
+ }
}
inline void draw_glyph(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Vector2 &p_ofs) {
@@ -784,11 +786,11 @@ void Label::_invalidate() {
void Label::set_label_settings(const Ref<LabelSettings> &p_settings) {
if (settings != p_settings) {
if (settings.is_valid()) {
- settings->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Label::_invalidate));
+ settings->disconnect_changed(callable_mp(this, &Label::_invalidate));
}
settings = p_settings;
if (settings.is_valid()) {
- settings->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Label::_invalidate), CONNECT_REFERENCE_COUNTED);
+ settings->connect_changed(callable_mp(this, &Label::_invalidate), CONNECT_REFERENCE_COUNTED);
}
_invalidate();
}
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index d8ec581089..85068ac862 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -453,7 +453,7 @@ void MenuBar::_draw_menu_item(int p_index) {
}
Color color;
- Ref<StyleBox> style = theme_cache.normal;
+ Ref<StyleBox> style;
Rect2 item_rect = _get_menu_item_rect(p_index);
if (menu_cache[p_index].disabled) {
diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp
index 68e2db7cfd..e2ae824e60 100644
--- a/scene/gui/nine_patch_rect.cpp
+++ b/scene/gui/nine_patch_rect.cpp
@@ -30,7 +30,6 @@
#include "nine_patch_rect.h"
-#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
#include "servers/rendering_server.h"
@@ -101,13 +100,13 @@ void NinePatchRect::set_texture(const Ref<Texture2D> &p_tex) {
}
if (texture.is_valid()) {
- texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NinePatchRect::_texture_changed));
+ texture->disconnect_changed(callable_mp(this, &NinePatchRect::_texture_changed));
}
texture = p_tex;
if (texture.is_valid()) {
- texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NinePatchRect::_texture_changed));
+ texture->connect_changed(callable_mp(this, &NinePatchRect::_texture_changed));
}
queue_redraw();
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 451ac94109..8138a66f64 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -445,13 +445,11 @@ void OptionButton::_select_int(int p_which) {
void OptionButton::_refresh_size_cache() {
cache_refresh_pending = false;
- if (!fit_to_longest_item) {
- return;
- }
-
- _cached_size = Vector2();
- for (int i = 0; i < get_item_count(); i++) {
- _cached_size = _cached_size.max(get_minimum_size_for_text_and_icon(get_item_text(i), get_item_icon(i)));
+ if (fit_to_longest_item) {
+ _cached_size = Vector2();
+ for (int i = 0; i < get_item_count(); i++) {
+ _cached_size = _cached_size.max(get_minimum_size_for_text_and_icon(popup->get_item_xl_text(i), get_item_icon(i)));
+ }
}
update_minimum_size();
}
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index adeaf9a49f..40db8deaac 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -244,7 +244,12 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
Rect2 safe_area = this_rect;
safe_area.position.y += items[p_over]._ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2;
safe_area.size.y = items[p_over]._height_cache + theme_cache.v_separation;
- DisplayServer::get_singleton()->window_set_popup_safe_rect(submenu_popup->get_window_id(), safe_area);
+ Viewport *vp = submenu_popup->get_embedder();
+ if (vp) {
+ vp->subwindow_set_popup_safe_rect(submenu_popup, safe_area);
+ } else {
+ DisplayServer::get_singleton()->window_set_popup_safe_rect(submenu_popup->get_window_id(), safe_area);
+ }
// Make the position of the parent popup relative to submenu popup.
this_rect.position = this_rect.position - submenu_pum->get_position();
@@ -273,7 +278,7 @@ void PopupMenu::_parent_focused() {
window_parent = Object::cast_to<Window>(window_parent->get_parent()->get_viewport());
}
- Rect2 safe_area = DisplayServer::get_singleton()->window_get_popup_safe_rect(get_window_id());
+ Rect2 safe_area = get_embedder()->subwindow_get_popup_safe_rect(this);
Point2 pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted;
if (safe_area == Rect2i() || !safe_area.has_point(pos)) {
Popup::_parent_focused();
@@ -1471,6 +1476,11 @@ String PopupMenu::get_item_text(int p_idx) const {
return items[p_idx].text;
}
+String PopupMenu::get_item_xl_text(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, items.size(), "");
+ return items[p_idx].xl_text;
+}
+
Control::TextDirection PopupMenu::get_item_text_direction(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), Control::TEXT_DIRECTION_INHERITED);
return items[p_idx].text_direction;
@@ -1958,7 +1968,7 @@ void PopupMenu::clear() {
void PopupMenu::_ref_shortcut(Ref<Shortcut> p_sc) {
if (!shortcut_refcount.has(p_sc)) {
shortcut_refcount[p_sc] = 1;
- p_sc->connect("changed", callable_mp(this, &PopupMenu::_shortcut_changed));
+ p_sc->connect_changed(callable_mp(this, &PopupMenu::_shortcut_changed));
} else {
shortcut_refcount[p_sc] += 1;
}
@@ -1968,7 +1978,7 @@ void PopupMenu::_unref_shortcut(Ref<Shortcut> p_sc) {
ERR_FAIL_COND(!shortcut_refcount.has(p_sc));
shortcut_refcount[p_sc]--;
if (shortcut_refcount[p_sc] == 0) {
- p_sc->disconnect("changed", callable_mp(this, &PopupMenu::_shortcut_changed));
+ p_sc->disconnect_changed(callable_mp(this, &PopupMenu::_shortcut_changed));
shortcut_refcount.erase(p_sc);
}
}
@@ -2298,7 +2308,7 @@ void PopupMenu::_bind_methods() {
ADD_SIGNAL(MethodInfo("menu_changed"));
}
-void PopupMenu::popup(const Rect2 &p_bounds) {
+void PopupMenu::popup(const Rect2i &p_bounds) {
moved = Vector2();
popup_time_msec = OS::get_singleton()->get_ticks_msec();
Popup::popup(p_bounds);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index 572467bf94..5ad9cd4303 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -250,6 +250,7 @@ public:
void toggle_item_checked(int p_idx);
String get_item_text(int p_idx) const;
+ String get_item_xl_text(int p_idx) const;
Control::TextDirection get_item_text_direction(int p_idx) const;
String get_item_language(int p_idx) const;
int get_item_idx_from_text(const String &text) const;
@@ -311,7 +312,7 @@ public:
void set_allow_search(bool p_allow);
bool get_allow_search() const;
- virtual void popup(const Rect2 &p_bounds = Rect2());
+ virtual void popup(const Rect2i &p_bounds = Rect2i()) override;
void take_mouse_focus();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 9409ae2315..db7196fb07 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -35,7 +35,8 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/translation.h"
-#include "label.h"
+#include "scene/gui/label.h"
+#include "scene/resources/atlas_texture.h"
#include "scene/scene_string_names.h"
#include "servers/display_server.h"
@@ -1097,6 +1098,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + gloff.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a);
+ } else if (item_fx->type == ITEM_PULSE) {
+ ItemPulse *item_pulse = static_cast<ItemPulse *>(item_fx);
+
+ const float sined_time = (Math::ease(Math::pingpong(item_pulse->elapsed_time, 1.0 / item_pulse->frequency) * item_pulse->frequency, item_pulse->ease));
+ font_color = font_color.lerp(font_color * item_pulse->color, sined_time);
}
}
@@ -1315,6 +1321,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + off.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a);
+ } else if (item_fx->type == ITEM_PULSE) {
+ ItemPulse *item_pulse = static_cast<ItemPulse *>(item_fx);
+
+ const float sined_time = (Math::ease(Math::pingpong(item_pulse->elapsed_time, 1.0 / item_pulse->frequency) * item_pulse->frequency, item_pulse->ease));
+ font_color = font_color.lerp(font_color * item_pulse->color, sined_time);
}
}
@@ -1675,7 +1686,7 @@ void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, double p_delta
while (it) {
ItemFX *ifx = nullptr;
- if (it->type == ITEM_CUSTOMFX || it->type == ITEM_SHAKE || it->type == ITEM_WAVE || it->type == ITEM_TORNADO || it->type == ITEM_RAINBOW) {
+ if (it->type == ITEM_CUSTOMFX || it->type == ITEM_SHAKE || it->type == ITEM_WAVE || it->type == ITEM_TORNADO || it->type == ITEM_RAINBOW || it->type == ITEM_PULSE) {
ifx = static_cast<ItemFX *>(it);
}
@@ -2616,7 +2627,7 @@ bool RichTextLabel::_find_strikethrough(Item *p_item) {
void RichTextLabel::_fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack) {
Item *item = p_item;
while (item) {
- if (item->type == ITEM_CUSTOMFX || item->type == ITEM_SHAKE || item->type == ITEM_WAVE || item->type == ITEM_TORNADO || item->type == ITEM_RAINBOW) {
+ if (item->type == ITEM_CUSTOMFX || item->type == ITEM_SHAKE || item->type == ITEM_WAVE || item->type == ITEM_TORNADO || item->type == ITEM_RAINBOW || item->type == ITEM_PULSE) {
r_stack.push_back(static_cast<ItemFX *>(item));
}
@@ -2802,7 +2813,7 @@ _FORCE_INLINE_ float RichTextLabel::_update_scroll_exceeds(float p_total_height,
total_height = 0;
for (int j = 0; j <= p_idx; j++) {
- total_height = _resize_line(main, j, theme_cache.normal_font, theme_cache.normal_font_size, p_width, total_height);
+ total_height = _resize_line(main, j, theme_cache.normal_font, theme_cache.normal_font_size, p_width - scroll_w, total_height);
main->first_resized_line.store(j);
}
@@ -2852,7 +2863,7 @@ bool RichTextLabel::_validate_line_caches() {
float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
for (int i = fi; i < (int)main->lines.size(); i++) {
total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
- total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width - scroll_w, i, old_scroll, text_rect.size.height);
+ total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width, i, old_scroll, text_rect.size.height);
main->first_resized_line.store(i);
}
@@ -2898,27 +2909,40 @@ void RichTextLabel::_process_line_caches() {
float total_height = 0;
if (fi != 0) {
- // Update fonts.
+ int sr = MIN(main->first_invalid_font_line.load(), main->first_resized_line.load());
+ // Update fonts.
for (int i = main->first_invalid_font_line.load(); i < fi; i++) {
_update_line_font(main, i, theme_cache.normal_font, theme_cache.normal_font_size);
+
+ main->first_invalid_font_line.store(i);
+
+ if (stop_thread.load()) {
+ return;
+ }
}
// Resize lines without reshaping.
- int sr = MIN(main->first_invalid_font_line.load(), main->first_resized_line.load());
- main->first_invalid_font_line.store(fi);
+ if (sr != 0) {
+ total_height = _calculate_line_vertical_offset(main->lines[sr - 1]);
+ }
for (int i = sr; i < fi; i++) {
total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
- total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width - scroll_w, i, old_scroll, text_rect.size.height);
+ total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width, i, old_scroll, text_rect.size.height);
main->first_resized_line.store(i);
+
+ if (stop_thread.load()) {
+ return;
+ }
}
}
+ total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
for (int i = fi; i < (int)main->lines.size(); i++) {
total_height = _shape_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars);
- total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width - scroll_w, i, old_scroll, text_rect.size.height);
+ total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width, i, old_scroll, text_rect.size.height);
main->first_invalid_line.store(i);
main->first_resized_line.store(i);
@@ -3431,6 +3455,7 @@ void RichTextLabel::push_fade(int p_start_index, int p_length) {
_stop_thread();
MutexLock data_lock(data_mutex);
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemFade *item = memnew(ItemFade);
item->starting_index = p_start_index;
item->length = p_length;
@@ -3441,6 +3466,7 @@ void RichTextLabel::push_shake(int p_strength = 10, float p_rate = 24.0f, bool p
_stop_thread();
MutexLock data_lock(data_mutex);
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemShake *item = memnew(ItemShake);
item->strength = p_strength;
item->rate = p_rate;
@@ -3452,6 +3478,7 @@ void RichTextLabel::push_wave(float p_frequency = 1.0f, float p_amplitude = 10.0
_stop_thread();
MutexLock data_lock(data_mutex);
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemWave *item = memnew(ItemWave);
item->frequency = p_frequency;
item->amplitude = p_amplitude;
@@ -3463,6 +3490,7 @@ void RichTextLabel::push_tornado(float p_frequency = 1.0f, float p_radius = 10.0
_stop_thread();
MutexLock data_lock(data_mutex);
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemTornado *item = memnew(ItemTornado);
item->frequency = p_frequency;
item->radius = p_radius;
@@ -3474,6 +3502,7 @@ void RichTextLabel::push_rainbow(float p_saturation, float p_value, float p_freq
_stop_thread();
MutexLock data_lock(data_mutex);
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemRainbow *item = memnew(ItemRainbow);
item->frequency = p_frequency;
item->saturation = p_saturation;
@@ -3481,6 +3510,17 @@ void RichTextLabel::push_rainbow(float p_saturation, float p_value, float p_freq
_add_item(item, true);
}
+void RichTextLabel::push_pulse(const Color &p_color, float p_frequency, float p_ease) {
+ _stop_thread();
+ MutexLock data_lock(data_mutex);
+
+ ItemPulse *item = memnew(ItemPulse);
+ item->color = p_color;
+ item->frequency = p_frequency;
+ item->ease = p_ease;
+ _add_item(item, true);
+}
+
void RichTextLabel::push_bgcolor(const Color &p_color) {
_stop_thread();
MutexLock data_lock(data_mutex);
@@ -3507,6 +3547,7 @@ void RichTextLabel::push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionar
_stop_thread();
MutexLock data_lock(data_mutex);
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemCustomFX *item = memnew(ItemCustomFX);
item->custom_effect = p_custom_effect;
item->char_fx_transform->environment = p_environment;
@@ -3515,6 +3556,15 @@ void RichTextLabel::push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionar
set_process_internal(true);
}
+void RichTextLabel::push_context() {
+ _stop_thread();
+ MutexLock data_lock(data_mutex);
+
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemContext *item = memnew(ItemContext);
+ _add_item(item, true);
+}
+
void RichTextLabel::set_table_column_expand(int p_column, bool p_expand, int p_ratio) {
_stop_thread();
MutexLock data_lock(data_mutex);
@@ -3608,6 +3658,31 @@ void RichTextLabel::pop() {
current = current->parent;
}
+void RichTextLabel::pop_context() {
+ _stop_thread();
+ MutexLock data_lock(data_mutex);
+
+ ERR_FAIL_NULL(current->parent);
+
+ while (current->parent && current != main) {
+ if (current->type == ITEM_FRAME) {
+ current_frame = static_cast<ItemFrame *>(current)->parent_frame;
+ } else if (current->type == ITEM_CONTEXT) {
+ current = current->parent;
+ return;
+ }
+ current = current->parent;
+ }
+}
+
+void RichTextLabel::pop_all() {
+ _stop_thread();
+ MutexLock data_lock(data_mutex);
+
+ current = main;
+ current_frame = main;
+}
+
void RichTextLabel::clear() {
_stop_thread();
MutexLock data_lock(data_mutex);
@@ -4664,7 +4739,29 @@ void RichTextLabel::append_text(const String &p_bbcode) {
pos = brk_end + 1;
tag_stack.push_front("rainbow");
set_process_internal(true);
+ } else if (bbcode_name == "pulse") {
+ Color color = Color(1, 1, 1, 0.25);
+ OptionMap::Iterator color_option = bbcode_options.find("color");
+ if (color_option) {
+ color = Color::from_string(color_option->value, color);
+ }
+
+ float frequency = 1.0;
+ OptionMap::Iterator freq_option = bbcode_options.find("freq");
+ if (freq_option) {
+ frequency = freq_option->value.to_float();
+ }
+ float ease = -2.0;
+ OptionMap::Iterator ease_option = bbcode_options.find("ease");
+ if (ease_option) {
+ ease = ease_option->value.to_float();
+ }
+
+ push_pulse(color, frequency, ease);
+ pos = brk_end + 1;
+ tag_stack.push_front("pulse");
+ set_process_internal(true);
} else if (tag.begins_with("bgcolor=")) {
String color_str = tag.substr(8, tag.length()).unquote();
Color color = Color::from_string(color_str, theme_cache.default_color);
@@ -5467,7 +5564,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align", "region"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(Rect2(0, 0, 0, 0)));
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
ClassDB::bind_method(D_METHOD("remove_paragraph", "paragraph"), &RichTextLabel::remove_paragraph);
- ClassDB::bind_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font);
+ ClassDB::bind_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font, DEFVAL(0));
ClassDB::bind_method(D_METHOD("push_font_size", "font_size"), &RichTextLabel::push_font_size);
ClassDB::bind_method(D_METHOD("push_normal"), &RichTextLabel::push_normal);
ClassDB::bind_method(D_METHOD("push_bold"), &RichTextLabel::push_bold);
@@ -5486,7 +5583,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough);
ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align", "align_to_row"), &RichTextLabel::push_table, DEFVAL(INLINE_ALIGNMENT_TOP), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("push_dropcap", "string", "font", "size", "dropcap_margins", "color", "outline_size", "outline_color"), &RichTextLabel::push_dropcap, DEFVAL(Rect2()), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(0, 0, 0, 0)));
- ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand);
+ ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand, DEFVAL(1));
ClassDB::bind_method(D_METHOD("set_cell_row_background_color", "odd_row_bg", "even_row_bg"), &RichTextLabel::set_cell_row_background_color);
ClassDB::bind_method(D_METHOD("set_cell_border_color", "color"), &RichTextLabel::set_cell_border_color);
ClassDB::bind_method(D_METHOD("set_cell_size_override", "min_size", "max_size"), &RichTextLabel::set_cell_size_override);
@@ -5495,7 +5592,10 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("push_fgcolor", "fgcolor"), &RichTextLabel::push_fgcolor);
ClassDB::bind_method(D_METHOD("push_bgcolor", "bgcolor"), &RichTextLabel::push_bgcolor);
ClassDB::bind_method(D_METHOD("push_customfx", "effect", "env"), &RichTextLabel::push_customfx);
+ ClassDB::bind_method(D_METHOD("push_context"), &RichTextLabel::push_context);
+ ClassDB::bind_method(D_METHOD("pop_context"), &RichTextLabel::pop_context);
ClassDB::bind_method(D_METHOD("pop"), &RichTextLabel::pop);
+ ClassDB::bind_method(D_METHOD("pop_all"), &RichTextLabel::pop_all);
ClassDB::bind_method(D_METHOD("clear"), &RichTextLabel::clear);
@@ -5607,6 +5707,11 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("_thread_end"), &RichTextLabel::_thread_end);
+#ifndef DISABLE_DEPRECATED
+ ClassDB::bind_compatibility_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font);
+ ClassDB::bind_compatibility_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand);
+#endif // DISABLE_DEPRECATED
+
// Note: set "bbcode_enabled" first, to avoid unnecessary "text" resets.
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bbcode_enabled"), "set_use_bbcode", "is_using_bbcode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
@@ -5707,10 +5812,12 @@ int RichTextLabel::get_character_line(int p_char) {
int to_line = main->first_invalid_line.load();
for (int i = 0; i < to_line; i++) {
MutexLock lock(main->lines[i].text_buf->get_mutex());
- if (main->lines[i].char_offset < p_char && p_char <= main->lines[i].char_offset + main->lines[i].char_count) {
+ int char_offset = main->lines[i].char_offset;
+ int char_count = main->lines[i].char_count;
+ if (char_offset <= p_char && p_char < char_offset + char_count) {
for (int j = 0; j < main->lines[i].text_buf->get_line_count(); j++) {
Vector2i range = main->lines[i].text_buf->get_line_range(j);
- if (main->lines[i].char_offset + range.x < p_char && p_char <= main->lines[i].char_offset + range.y) {
+ if (char_offset + range.x <= p_char && p_char <= char_offset + range.y) {
return line_count;
}
line_count++;
@@ -5725,13 +5832,11 @@ int RichTextLabel::get_character_line(int p_char) {
int RichTextLabel::get_character_paragraph(int p_char) {
_validate_line_caches();
- int para_count = 0;
int to_line = main->first_invalid_line.load();
for (int i = 0; i < to_line; i++) {
- if (main->lines[i].char_offset < p_char && p_char <= main->lines[i].char_offset + main->lines[i].char_count) {
- return para_count;
- } else {
- para_count++;
+ int char_offset = main->lines[i].char_offset;
+ if (char_offset <= p_char && p_char < char_offset + main->lines[i].char_count) {
+ return i;
}
}
return -1;
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 66891ab567..30adf03f84 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -32,8 +32,8 @@
#define RICH_TEXT_LABEL_H
#include "core/object/worker_thread_pool.h"
-#include "rich_text_effect.h"
#include "scene/gui/popup_menu.h"
+#include "scene/gui/rich_text_effect.h"
#include "scene/gui/scroll_bar.h"
#include "scene/resources/text_paragraph.h"
@@ -70,12 +70,14 @@ public:
ITEM_WAVE,
ITEM_TORNADO,
ITEM_RAINBOW,
+ ITEM_PULSE,
ITEM_BGCOLOR,
ITEM_FGCOLOR,
ITEM_META,
ITEM_HINT,
ITEM_DROPCAP,
- ITEM_CUSTOMFX
+ ITEM_CUSTOMFX,
+ ITEM_CONTEXT
};
enum MenuItems {
@@ -343,6 +345,14 @@ private:
ItemRainbow() { type = ITEM_RAINBOW; }
};
+ struct ItemPulse : public ItemFX {
+ Color color = Color(1.0, 1.0, 1.0, 0.25);
+ float frequency = 1.0f;
+ float ease = -2.0f;
+
+ ItemPulse() { type = ITEM_PULSE; }
+ };
+
struct ItemBGColor : public Item {
Color color;
ItemBGColor() { type = ITEM_BGCOLOR; }
@@ -370,6 +380,10 @@ private:
}
};
+ struct ItemContext : public Item {
+ ItemContext() { type = ITEM_CONTEXT; }
+ };
+
ItemFrame *main = nullptr;
Item *current = nullptr;
ItemFrame *current_frame = nullptr;
@@ -611,9 +625,11 @@ public:
void push_wave(float p_frequency, float p_amplitude, bool p_connected);
void push_tornado(float p_frequency, float p_radius, bool p_connected);
void push_rainbow(float p_saturation, float p_value, float p_frequency);
+ void push_pulse(const Color &p_color, float p_frequency, float p_ease);
void push_bgcolor(const Color &p_color);
void push_fgcolor(const Color &p_color);
void push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment);
+ void push_context();
void set_table_column_expand(int p_column, bool p_expand, int p_ratio = 1);
void set_cell_row_background_color(const Color &p_odd_row_bg, const Color &p_even_row_bg);
void set_cell_border_color(const Color &p_color);
@@ -622,6 +638,8 @@ public:
int get_current_table_column() const;
void push_cell();
void pop();
+ void pop_context();
+ void pop_all();
void clear();
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index e2fb7efb19..398f637e85 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -256,7 +256,7 @@ void Slider::_notification(int p_what) {
Ref<StyleBox> style = theme_cache.slider_style;
Ref<Texture2D> tick = theme_cache.tick_icon;
- bool highlighted = mouse_inside || has_focus();
+ bool highlighted = editable && (mouse_inside || has_focus());
Ref<Texture2D> grabber;
if (editable) {
if (highlighted) {
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 9105837486..105c35383b 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -154,6 +154,18 @@ void SubViewportContainer::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
_notify_viewports(NOTIFICATION_VP_MOUSE_EXIT);
} break;
+
+ case NOTIFICATION_FOCUS_ENTER: {
+ // If focused, send InputEvent to the SubViewport before the Gui-Input stage.
+ set_process_input(true);
+ set_process_unhandled_input(false);
+ } break;
+
+ case NOTIFICATION_FOCUS_EXIT: {
+ // A different Control has focus and should receive Gui-Input before the InputEvent is sent to the SubViewport.
+ set_process_input(false);
+ set_process_unhandled_input(true);
+ } break;
}
}
@@ -168,6 +180,14 @@ void SubViewportContainer::_notify_viewports(int p_notification) {
}
void SubViewportContainer::input(const Ref<InputEvent> &p_event) {
+ _propagate_nonpositional_event(p_event);
+}
+
+void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) {
+ _propagate_nonpositional_event(p_event);
+}
+
+void SubViewportContainer::_propagate_nonpositional_event(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (Engine::get_singleton()->is_editor_hint()) {
@@ -247,6 +267,10 @@ PackedStringArray SubViewportContainer::get_configuration_warnings() const {
warnings.push_back(RTR("This node doesn't have a SubViewport as child, so it can't display its intended content.\nConsider adding a SubViewport as a child to provide something displayable."));
}
+ if (get_default_cursor_shape() != Control::CURSOR_ARROW) {
+ warnings.push_back(RTR("The default mouse cursor shape of SubViewportContainer has no effect.\nConsider leaving it at its initial value `CURSOR_ARROW`."));
+ }
+
return warnings;
}
@@ -262,5 +286,6 @@ void SubViewportContainer::_bind_methods() {
}
SubViewportContainer::SubViewportContainer() {
- set_process_input(true);
+ set_process_unhandled_input(true);
+ set_focus_mode(FOCUS_CLICK);
}
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index 8e5f5d157d..3c6cd09d66 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -41,6 +41,7 @@ class SubViewportContainer : public Container {
void _notify_viewports(int p_notification);
bool _is_propagated_in_gui_input(const Ref<InputEvent> &p_event);
void _send_event_to_viewports(const Ref<InputEvent> &p_event);
+ void _propagate_nonpositional_event(const Ref<InputEvent> &p_event);
protected:
void _notification(int p_what);
@@ -54,6 +55,7 @@ public:
bool is_stretch_enabled() const;
virtual void input(const Ref<InputEvent> &p_event) override;
+ virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
void set_stretch_shrink(int p_shrink);
int get_stretch_shrink() const;
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index 35564eb458..959a51eff9 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -881,6 +881,8 @@ void TabBar::_update_hover() {
if (hover != -1) {
emit_signal(SNAME("tab_hovered"), hover);
}
+
+ _update_cache();
queue_redraw();
}
@@ -988,6 +990,7 @@ void TabBar::_on_mouse_exited() {
highlight_arrow = -1;
dragging_valid_tab = false;
+ _update_cache();
queue_redraw();
}
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index b07a3d7669..dcbb25c41d 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -30,7 +30,6 @@
#include "texture_button.h"
-#include "core/core_string_names.h"
#include "core/typedefs.h"
#include <stdlib.h>
@@ -353,12 +352,12 @@ void TextureButton::_set_texture(Ref<Texture2D> *p_destination, const Ref<Textur
return;
}
if (destination.is_valid()) {
- destination->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureButton::_texture_changed));
+ destination->disconnect_changed(callable_mp(this, &TextureButton::_texture_changed));
}
destination = p_texture;
if (destination.is_valid()) {
// Pass `CONNECT_REFERENCE_COUNTED` to avoid early disconnect in case the same texture is assigned to different "slots".
- destination->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureButton::_texture_changed), CONNECT_REFERENCE_COUNTED);
+ destination->connect_changed(callable_mp(this, &TextureButton::_texture_changed), CONNECT_REFERENCE_COUNTED);
}
_texture_changed();
}
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index 2464e005ee..70c2cc9d65 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -31,7 +31,7 @@
#include "texture_progress_bar.h"
#include "core/config/engine.h"
-#include "core/core_string_names.h"
+#include "scene/resources/atlas_texture.h"
void TextureProgressBar::set_under_texture(const Ref<Texture2D> &p_texture) {
_set_texture(&under, p_texture);
@@ -161,12 +161,12 @@ void TextureProgressBar::_set_texture(Ref<Texture2D> *p_destination, const Ref<T
return;
}
if (destination.is_valid()) {
- destination->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureProgressBar::_texture_changed));
+ destination->disconnect_changed(callable_mp(this, &TextureProgressBar::_texture_changed));
}
destination = p_texture;
if (destination.is_valid()) {
// Pass `CONNECT_REFERENCE_COUNTED` to avoid early disconnect in case the same texture is assigned to different "slots".
- destination->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureProgressBar::_texture_changed), CONNECT_REFERENCE_COUNTED);
+ destination->connect_changed(callable_mp(this, &TextureProgressBar::_texture_changed), CONNECT_REFERENCE_COUNTED);
}
_texture_changed();
}
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index 20472ab46e..d94b11789f 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -30,7 +30,7 @@
#include "texture_rect.h"
-#include "core/core_string_names.h"
+#include "scene/resources/atlas_texture.h"
#include "servers/rendering_server.h"
void TextureRect::_notification(int p_what) {
@@ -201,13 +201,13 @@ void TextureRect::set_texture(const Ref<Texture2D> &p_tex) {
}
if (texture.is_valid()) {
- texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureRect::_texture_changed));
+ texture->disconnect_changed(callable_mp(this, &TextureRect::_texture_changed));
}
texture = p_tex;
if (texture.is_valid()) {
- texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureRect::_texture_changed));
+ texture->connect_changed(callable_mp(this, &TextureRect::_texture_changed));
}
queue_redraw();
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index a5d12aecad..ee9c6573f4 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1176,6 +1176,12 @@ int TreeItem::get_button_by_id(int p_column, int p_id) const {
return -1;
}
+void TreeItem::set_button_tooltip_text(int p_column, int p_index, const String &p_tooltip) {
+ ERR_FAIL_INDEX(p_column, cells.size());
+ ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size());
+ cells.write[p_column].buttons.write[p_index].tooltip = p_tooltip;
+}
+
void TreeItem::set_button(int p_column, int p_index, const Ref<Texture2D> &p_button) {
ERR_FAIL_COND(p_button.is_null());
ERR_FAIL_INDEX(p_column, cells.size());
@@ -1586,6 +1592,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_index"), &TreeItem::get_button_id);
ClassDB::bind_method(D_METHOD("get_button_by_id", "column", "id"), &TreeItem::get_button_by_id);
ClassDB::bind_method(D_METHOD("get_button", "column", "button_index"), &TreeItem::get_button);
+ ClassDB::bind_method(D_METHOD("set_button_tooltip_text", "column", "button_index", "tooltip"), &TreeItem::set_button_tooltip_text);
ClassDB::bind_method(D_METHOD("set_button", "column", "button_index", "button"), &TreeItem::set_button);
ClassDB::bind_method(D_METHOD("erase_button", "column", "button_index"), &TreeItem::erase_button);
ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_index", "disabled"), &TreeItem::set_button_disabled);
@@ -1704,6 +1711,10 @@ void Tree::_update_theme_item_cache() {
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"));
@@ -1841,13 +1852,14 @@ int Tree::get_item_height(TreeItem *p_item) const {
void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color) {
ERR_FAIL_COND(theme_cache.font.is_null());
- Rect2i rect = p_rect;
+ Rect2i rect = p_rect.grow_individual(-theme_cache.inner_item_margin_left, -theme_cache.inner_item_margin_top, -theme_cache.inner_item_margin_right, -theme_cache.inner_item_margin_bottom);
Size2 ts = p_cell.text_buf->get_size();
bool rtl = is_layout_rtl();
int w = 0;
+ Size2i bmsize;
if (!p_cell.icon.is_null()) {
- Size2i bmsize = _get_cell_icon_size(p_cell);
+ bmsize = _get_cell_icon_size(p_cell);
w += bmsize.width + theme_cache.h_separation;
if (rect.size.width > 0 && (w + ts.width) > rect.size.width) {
ts.width = rect.size.width - w;
@@ -1886,8 +1898,6 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
}
if (!p_cell.icon.is_null()) {
- Size2i bmsize = _get_cell_icon_size(p_cell);
-
p_cell.draw_icon(ci, rect.position + Size2i(0, Math::floor((real_t)(rect.size.y - bmsize.y) / 2)), bmsize, p_icon_color);
rect.position.x += bmsize.x + theme_cache.h_separation;
rect.size.x -= bmsize.x + theme_cache.h_separation;
@@ -2868,21 +2878,17 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
return -1;
}
- if (select_mode == SELECT_MULTI && p_mod->is_command_or_control_pressed() && c.selectable) {
- if (!c.selected || p_button == MouseButton::RIGHT) {
- p_item->select(col);
- emit_signal(SNAME("multi_selected"), p_item, col, true);
- emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button);
-
- //p_item->selected_signal.call(col);
+ if (c.selectable) {
+ if (select_mode == SELECT_MULTI && p_mod->is_command_or_control_pressed()) {
+ if (c.selected && p_button == MouseButton::LEFT) {
+ p_item->deselect(col);
+ emit_signal(SNAME("multi_selected"), p_item, col, false);
+ } else {
+ p_item->select(col);
+ emit_signal(SNAME("multi_selected"), p_item, col, true);
+ emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button);
+ }
} else {
- p_item->deselect(col);
- emit_signal(SNAME("multi_selected"), p_item, col, false);
- //p_item->deselected_signal.call(col);
- }
-
- } else {
- if (c.selectable) {
if (select_mode == SELECT_MULTI && p_mod->is_shift_pressed() && selected_item && selected_item != p_item) {
bool inrange = false;
@@ -2902,12 +2908,6 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button);
}
}
-
- /*
- if (!c.selected && select_mode==SELECT_MULTI) {
- emit_signal(SNAME("multi_selected"),p_item,col,true);
- }
- */
queue_redraw();
}
}
@@ -4400,9 +4400,7 @@ void Tree::item_selected(int p_column, TreeItem *p_item) {
//emit_signal(SNAME("multi_selected"),p_item,p_column,true); - NO this is for TreeItem::select
selected_col = p_column;
- if (!selected_item) {
- selected_item = p_item;
- }
+ selected_item = p_item;
} else {
select_single_item(p_item, root, p_column);
}
@@ -4410,11 +4408,18 @@ void Tree::item_selected(int p_column, TreeItem *p_item) {
}
void Tree::item_deselected(int p_column, TreeItem *p_item) {
- if (selected_item == p_item) {
+ if (select_mode == SELECT_SINGLE && selected_item == p_item && selected_col == p_column) {
selected_item = nullptr;
-
- if (selected_col == p_column) {
+ selected_col = -1;
+ } else {
+ if (select_mode == SELECT_ROW && selected_item == p_item) {
+ selected_item = nullptr;
selected_col = -1;
+ } else {
+ if (select_mode == SELECT_MULTI) {
+ selected_item = p_item;
+ selected_col = p_column;
+ }
}
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index c0814c651d..ce4379d7fe 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -262,6 +262,7 @@ public:
int get_button_id(int p_column, int p_index) const;
void erase_button(int p_column, int p_index);
int get_button_by_id(int p_column, int p_id) const;
+ void set_button_tooltip_text(int p_column, int p_index, const String &p_tooltip);
void set_button(int p_column, int p_index, const Ref<Texture2D> &p_button);
void set_button_color(int p_column, int p_index, const Color &p_color);
void set_button_disabled(int p_column, int p_index, bool p_disabled);
@@ -550,6 +551,10 @@ private:
int h_separation = 0;
int v_separation = 0;
+ int inner_item_margin_bottom = 0;
+ int inner_item_margin_left = 0;
+ int inner_item_margin_right = 0;
+ int inner_item_margin_top = 0;
int item_margin = 0;
int button_margin = 0;
int icon_max_width = 0;
diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp
index 19a54e01c4..f6e558fe57 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -31,6 +31,7 @@
#include "video_stream_player.h"
#include "core/os/os.h"
+#include "scene/resources/image_texture.h"
#include "scene/scene_string_names.h"
#include "servers/audio_server.h"
@@ -159,6 +160,10 @@ void VideoStreamPlayer::_notification(int p_notification) {
playback->update(delta); // playback->is_playing() returns false in the last video frame
if (!playback->is_playing()) {
+ if (loop) {
+ play();
+ return;
+ }
emit_signal(SceneStringNames::get_singleton()->finished);
}
} break;
@@ -221,6 +226,14 @@ bool VideoStreamPlayer::has_expand() const {
return expand;
}
+void VideoStreamPlayer::set_loop(bool p_loop) {
+ loop = p_loop;
+}
+
+bool VideoStreamPlayer::has_loop() const {
+ return loop;
+}
+
void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) {
stop();
@@ -389,6 +402,13 @@ String VideoStreamPlayer::get_stream_name() const {
return stream->get_name();
}
+double VideoStreamPlayer::get_stream_length() const {
+ if (playback.is_null()) {
+ return 0;
+ }
+ return playback->get_length();
+}
+
double VideoStreamPlayer::get_stream_position() const {
if (playback.is_null()) {
return 0;
@@ -461,6 +481,9 @@ void VideoStreamPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_paused", "paused"), &VideoStreamPlayer::set_paused);
ClassDB::bind_method(D_METHOD("is_paused"), &VideoStreamPlayer::is_paused);
+ ClassDB::bind_method(D_METHOD("set_loop", "loop"), &VideoStreamPlayer::set_loop);
+ ClassDB::bind_method(D_METHOD("has_loop"), &VideoStreamPlayer::has_loop);
+
ClassDB::bind_method(D_METHOD("set_volume", "volume"), &VideoStreamPlayer::set_volume);
ClassDB::bind_method(D_METHOD("get_volume"), &VideoStreamPlayer::get_volume);
@@ -471,6 +494,7 @@ void VideoStreamPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_audio_track"), &VideoStreamPlayer::get_audio_track);
ClassDB::bind_method(D_METHOD("get_stream_name"), &VideoStreamPlayer::get_stream_name);
+ ClassDB::bind_method(D_METHOD("get_stream_length"), &VideoStreamPlayer::get_stream_length);
ClassDB::bind_method(D_METHOD("set_stream_position", "position"), &VideoStreamPlayer::set_stream_position);
ClassDB::bind_method(D_METHOD("get_stream_position"), &VideoStreamPlayer::get_stream_position);
@@ -498,6 +522,7 @@ void VideoStreamPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "has_autoplay");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_paused", "is_paused");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
ADD_PROPERTY(PropertyInfo(Variant::INT, "buffering_msec", PROPERTY_HINT_RANGE, "10,1000,suffix:ms"), "set_buffering_msec", "get_buffering_msec");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stream_position", PROPERTY_HINT_RANGE, "0,1280000,0.1", PROPERTY_USAGE_NONE), "set_stream_position", "get_stream_position");
diff --git a/scene/gui/video_stream_player.h b/scene/gui/video_stream_player.h
index 1fd599a9e1..0b83608f0b 100644
--- a/scene/gui/video_stream_player.h
+++ b/scene/gui/video_stream_player.h
@@ -36,6 +36,8 @@
#include "servers/audio/audio_rb_resampler.h"
#include "servers/audio_server.h"
+class ImageTexture;
+
class VideoStreamPlayer : public Control {
GDCLASS(VideoStreamPlayer, Control);
@@ -65,6 +67,7 @@ class VideoStreamPlayer : public Control {
float volume = 1.0;
double last_audio_time = 0.0;
bool expand = false;
+ bool loop = false;
int buffering_ms = 500;
int audio_track = 0;
int bus_index = 0;
@@ -94,6 +97,9 @@ public:
void stop();
bool is_playing() const;
+ void set_loop(bool p_loop);
+ bool has_loop() const;
+
void set_paused(bool p_paused);
bool is_paused() const;
@@ -104,6 +110,7 @@ public:
float get_volume_db() const;
String get_stream_name() const;
+ double get_stream_length() const;
double get_stream_position() const;
void set_stream_position(double p_position);
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index fcb951a89d..7f6bbb17c3 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -170,6 +170,7 @@ protected:
_FORCE_INLINE_ void set_hide_clip_children(bool p_value) { hide_clip_children = p_value; }
GDVIRTUAL0(_draw)
+
public:
enum {
NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique
@@ -179,7 +180,6 @@ public:
NOTIFICATION_EXIT_CANVAS = 33,
NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 35,
NOTIFICATION_WORLD_2D_CHANGED = 36,
-
};
/* EDITOR */
@@ -189,7 +189,7 @@ public:
// Save and restore a CanvasItem state
virtual void _edit_set_state(const Dictionary &p_state) {}
- virtual Dictionary _edit_get_state() const { return Dictionary(); };
+ virtual Dictionary _edit_get_state() const { return Dictionary(); }
// Used to move the node
virtual void _edit_set_position(const Point2 &p_position) = 0;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 9ebd8f00a8..cb72e4ec08 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1139,7 +1139,6 @@ void Node::_set_name_nocheck(const StringName &p_name) {
void Node::set_name(const String &p_name) {
ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Changing the name to nodes inside the SceneTree is only allowed from the main thread. Use `set_name.call_deferred(new_name)`.");
- ERR_FAIL_COND_MSG(data.parent && data.parent->data.blocked > 0, "Parent node is busy setting up children, `set_name(new_name)` failed. Consider using `set_name.call_deferred(new_name)` instead.");
String name = p_name.validate_node_name();
ERR_FAIL_COND(name.is_empty());
@@ -1151,9 +1150,9 @@ void Node::set_name(const String &p_name) {
data.name = name;
if (data.parent) {
- data.parent->data.children.erase(old_name);
data.parent->_validate_child_name(this, true);
- data.parent->data.children.insert(data.name, this);
+ bool success = data.parent->data.children.replace_key(old_name, data.name);
+ ERR_FAIL_COND_MSG(!success, "Renaming child in hashtable failed, this is a bug.");
}
if (data.unique_name_in_owner && data.owner) {
@@ -1403,9 +1402,9 @@ void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_i
void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Adding a sibling to a node inside the SceneTree is only allowed from the main thread. Use call_deferred(\"add_sibling\",node).");
ERR_FAIL_NULL(p_sibling);
- ERR_FAIL_NULL(data.parent);
ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself!
- ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_sibling()` failed. Consider using `add_sibling.call_deferred(sibling)` instead.");
+ ERR_FAIL_NULL(data.parent);
+ ERR_FAIL_COND_MSG(data.parent->data.blocked > 0, "Parent node is busy setting up children, `add_sibling()` failed. Consider using `add_sibling.call_deferred(sibling)` instead.");
data.parent->add_child(p_sibling, p_force_readable_name, data.internal_mode);
data.parent->_update_children_cache();
@@ -1906,7 +1905,7 @@ void Node::set_owner(Node *p_owner) {
check = check->data.parent;
}
- ERR_FAIL_COND(!owner_valid);
+ ERR_FAIL_COND_MSG(!owner_valid, "Invalid owner. Owner must be an ancestor in the tree.");
_set_owner_nocheck(p_owner);
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 9a7f34d277..db9c1efa68 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -50,6 +50,7 @@
#include "scene/main/viewport.h"
#include "scene/resources/environment.h"
#include "scene/resources/font.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
#include "scene/resources/packed_scene.h"
@@ -444,9 +445,8 @@ void SceneTree::set_group(const StringName &p_group, const String &p_name, const
void SceneTree::initialize() {
ERR_FAIL_NULL(root);
- initialized = true;
- root->_set_tree(this);
MainLoop::initialize();
+ root->_set_tree(this);
}
bool SceneTree::physics_process(double p_time) {
@@ -550,6 +550,10 @@ bool SceneTree::process(double p_time) {
#endif // _3D_DISABLED
#endif // TOOLS_ENABLED
+ if (unlikely(pending_new_scene)) {
+ _flush_scene_change();
+ }
+
return _quit;
}
@@ -618,20 +622,18 @@ void SceneTree::finalize() {
_flush_ugc();
- initialized = false;
-
- MainLoop::finalize();
-
if (root) {
root->_set_tree(nullptr);
root->_propagate_after_exit_tree();
memdelete(root); //delete root
root = nullptr;
+
+ // In case deletion of some objects was queued when destructing the `root`.
+ // E.g. if `queue_free()` was called for some node outside the tree when handling NOTIFICATION_PREDELETE for some node in the tree.
+ _flush_delete_queue();
}
- // In case deletion of some objects was queued when destructing the `root`.
- // E.g. if `queue_free()` was called for some node outside the tree when handling NOTIFICATION_PREDELETE for some node in the tree.
- _flush_delete_queue();
+ MainLoop::finalize();
// Cleanup timers.
for (Ref<SceneTreeTimer> &timer : timers) {
@@ -1378,27 +1380,16 @@ Node *SceneTree::get_current_scene() const {
return current_scene;
}
-void SceneTree::_change_scene(Node *p_to) {
- ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Changing scene can only be done from the main thread.");
- if (current_scene) {
- memdelete(current_scene);
- current_scene = nullptr;
- }
-
- // If we're quitting, abort.
- if (unlikely(_quit)) {
- if (p_to) { // Prevent memory leak.
- memdelete(p_to);
- }
- return;
- }
-
- if (p_to) {
- current_scene = p_to;
- root->add_child(p_to);
- // Update display for cursor instantly.
- root->update_mouse_cursor_state();
+void SceneTree::_flush_scene_change() {
+ if (prev_scene) {
+ memdelete(prev_scene);
+ prev_scene = nullptr;
}
+ current_scene = pending_new_scene;
+ root->add_child(pending_new_scene);
+ pending_new_scene = nullptr;
+ // Update display for cursor instantly.
+ root->update_mouse_cursor_state();
}
Error SceneTree::change_scene_to_file(const String &p_path) {
@@ -1417,7 +1408,22 @@ Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) {
Node *new_scene = p_scene->instantiate();
ERR_FAIL_NULL_V(new_scene, ERR_CANT_CREATE);
- call_deferred(SNAME("_change_scene"), new_scene);
+ // If called again while a change is pending.
+ if (pending_new_scene) {
+ queue_delete(pending_new_scene);
+ pending_new_scene = nullptr;
+ }
+
+ prev_scene = current_scene;
+
+ if (current_scene) {
+ // Let as many side effects as possible happen or be queued now,
+ // so they are run before the scene is actually deleted.
+ root->remove_child(current_scene);
+ }
+ DEV_ASSERT(!current_scene);
+
+ pending_new_scene = new_scene;
return OK;
}
@@ -1595,8 +1601,6 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("reload_current_scene"), &SceneTree::reload_current_scene);
ClassDB::bind_method(D_METHOD("unload_current_scene"), &SceneTree::unload_current_scene);
- ClassDB::bind_method(D_METHOD("_change_scene"), &SceneTree::_change_scene);
-
ClassDB::bind_method(D_METHOD("set_multiplayer", "multiplayer", "root_path"), &SceneTree::set_multiplayer, DEFVAL(NodePath()));
ClassDB::bind_method(D_METHOD("get_multiplayer", "for_path"), &SceneTree::get_multiplayer, DEFVAL(NodePath()));
ClassDB::bind_method(D_METHOD("set_multiplayer_poll_enabled", "enabled"), &SceneTree::set_multiplayer_poll_enabled);
@@ -1835,6 +1839,14 @@ SceneTree::SceneTree() {
}
SceneTree::~SceneTree() {
+ if (prev_scene) {
+ memdelete(prev_scene);
+ prev_scene = nullptr;
+ }
+ if (pending_new_scene) {
+ memdelete(pending_new_scene);
+ pending_new_scene = nullptr;
+ }
if (root) {
root->_set_tree(nullptr);
root->_propagate_after_exit_tree();
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 452fac7423..e1597d3890 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -138,7 +138,6 @@ private:
HashMap<StringName, Group> group_map;
bool _quit = false;
- bool initialized = false;
StringName tree_changed_name = "tree_changed";
StringName node_added_name = "node_added";
@@ -179,6 +178,8 @@ private:
TypedArray<Node> _get_nodes_in_group(const StringName &p_group);
Node *current_scene = nullptr;
+ Node *prev_scene = nullptr;
+ Node *pending_new_scene = nullptr;
Color debug_collisions_color;
Color debug_collision_contact_color;
@@ -189,7 +190,7 @@ private:
Ref<Material> collision_material;
int collision_debug_contacts;
- void _change_scene(Node *p_to);
+ void _flush_scene_change();
List<Ref<SceneTreeTimer>> timers;
List<Ref<Tween>> tweens;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index faa609d847..d9a1cfe965 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -31,7 +31,6 @@
#include "viewport.h"
#include "core/config/project_settings.h"
-#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/object/message_queue.h"
#include "core/string/translation.h"
@@ -315,7 +314,7 @@ 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(SNAME("embedded_border"));
+ Ref<StyleBox> panel = p_window->get_theme_stylebox(gui.subwindow_focused == p_window ? SNAME("embedded_border") : SNAME("embedded_unfocused_border"));
panel->draw(sw.canvas_item, r);
// Draw the title bar text.
@@ -464,7 +463,7 @@ void Viewport::_sub_window_remove(Window *p_window) {
RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID());
}
-int Viewport::_sub_window_find(Window *p_window) {
+int Viewport::_sub_window_find(Window *p_window) const {
for (int i = 0; i < gui.sub_windows.size(); i++) {
if (gui.sub_windows[i].window == p_window) {
return i;
@@ -689,17 +688,26 @@ void Viewport::_process_picking() {
PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
- bool has_mouse_event = false;
- for (const Ref<InputEvent> &e : physics_picking_events) {
- Ref<InputEventMouse> m = e;
- if (m.is_valid()) {
- has_mouse_event = true;
- break;
+ SubViewportContainer *parent_svc = Object::cast_to<SubViewportContainer>(get_parent());
+ bool parent_ignore_mouse = (parent_svc && parent_svc->get_mouse_filter() == Control::MOUSE_FILTER_IGNORE);
+ bool create_passive_hover_event = true;
+ if (gui.mouse_over || parent_ignore_mouse) {
+ // When the mouse is over a Control node, passive hovering would cause input events for Colliders, that are behind Control nodes.
+ // When parent SubViewportContainer ignores mouse, that setting should be respected.
+ create_passive_hover_event = false;
+ } else {
+ for (const Ref<InputEvent> &e : physics_picking_events) {
+ Ref<InputEventMouse> m = e;
+ if (m.is_valid()) {
+ // A mouse event exists, so passive hovering isn't necessary.
+ create_passive_hover_event = false;
+ break;
+ }
}
}
- if (!has_mouse_event) {
- // If no mouse event exists, create a motion one. This is necessary because objects or camera may have moved.
+ if (create_passive_hover_event) {
+ // Create a mouse motion event. This is necessary because objects or camera may have moved.
// While this extra event is sent, it is checked if both camera and last object and last ID did not move.
// If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame.
Ref<InputEventMouseMotion> mm;
@@ -717,6 +725,7 @@ void Viewport::_process_picking() {
}
while (physics_picking_events.size()) {
+ local_input_handled = false;
Ref<InputEvent> ev = physics_picking_events.front()->get();
physics_picking_events.pop_front();
@@ -841,6 +850,9 @@ void Viewport::_process_picking() {
capture_object = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture));
if (!capture_object || !camera_3d || (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed())) {
physics_object_capture = ObjectID();
+ } else {
+ last_id = physics_object_capture;
+ last_object = capture_object;
}
}
@@ -1344,7 +1356,12 @@ Vector2 Viewport::get_mouse_position() const {
// In this case get_screen_transform is not applicable, because it is ambiguous.
return gui.last_mouse_pos;
} else if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_MOUSE)) {
- return get_screen_transform_internal(true).affine_inverse().xform(DisplayServer::get_singleton()->mouse_get_position());
+ Transform2D xform = get_screen_transform_internal(true);
+ if (xform.determinant() == 0) {
+ // Screen transform can be non-invertible when the Window is minimized.
+ return Vector2();
+ }
+ return xform.affine_inverse().xform(DisplayServer::get_singleton()->mouse_get_position());
} else {
// Fallback to Input for getting mouse position in case of emulated mouse.
return get_screen_transform_internal().affine_inverse().xform(Input::get_singleton()->get_mouse_position());
@@ -1720,11 +1737,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.last_mouse_focus = gui.mouse_focus;
if (!gui.mouse_focus) {
- gui.mouse_focus_mask.clear();
return;
}
- gui.mouse_focus_mask.clear();
gui.mouse_focus_mask.set_flag(mouse_button_to_mask(mb->get_button_index()));
if (mb->get_button_index() == MouseButton::LEFT) {
@@ -1875,13 +1890,13 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (over != gui.mouse_over) {
+ if (!gui.mouse_over) {
+ _drop_physics_mouseover();
+ }
_drop_mouse_over();
_gui_cancel_tooltip();
if (over) {
- if (!gui.mouse_over) {
- _drop_physics_mouseover();
- }
_gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER);
gui.mouse_over = over;
}
@@ -2074,7 +2089,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) {
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE) && !Object::cast_to<SubViewportContainer>(over)) {
DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape);
}
}
@@ -3025,18 +3040,18 @@ void Viewport::_push_unhandled_input_internal(const Ref<InputEvent> &p_event) {
get_tree()->_call_input_pause(shortcut_input_group, SceneTree::CALL_INPUT_TYPE_SHORTCUT_INPUT, p_event, this);
}
- // Unhandled Input.
- if (!is_input_handled()) {
- ERR_FAIL_COND(!is_inside_tree());
- get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, p_event, this);
- }
-
// Unhandled key Input - Used for performance reasons - This is called a lot less than _unhandled_input since it ignores MouseMotion, and to handle Unicode input with Alt / Ctrl modifiers after handling shortcuts.
if (!is_input_handled() && (Object::cast_to<InputEventKey>(*p_event) != nullptr)) {
ERR_FAIL_COND(!is_inside_tree());
get_tree()->_call_input_pause(unhandled_key_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT, p_event, this);
}
+ // Unhandled Input.
+ if (!is_input_handled()) {
+ ERR_FAIL_COND(!is_inside_tree());
+ get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, p_event, this);
+ }
+
if (physics_object_picking && !is_input_handled()) {
if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED &&
(Object::cast_to<InputEventMouse>(*p_event) ||
@@ -3485,6 +3500,26 @@ bool Viewport::is_embedding_subwindows() const {
return gui.embed_subwindows_hint;
}
+void Viewport::subwindow_set_popup_safe_rect(Window *p_window, const Rect2i &p_rect) {
+ int index = _sub_window_find(p_window);
+ ERR_FAIL_COND(index == -1);
+
+ SubWindow sw = gui.sub_windows[index];
+ sw.parent_safe_rect = p_rect;
+}
+
+Rect2i Viewport::subwindow_get_popup_safe_rect(Window *p_window) const {
+ int index = _sub_window_find(p_window);
+ // FIXME: Re-enable ERR_FAIL_COND after rewriting embedded window popup closing.
+ // Currently it is expected, that index == -1 can happen.
+ if (index == -1) {
+ return Rect2i();
+ }
+ // ERR_FAIL_COND_V(index == -1, Rect2i());
+
+ return gui.sub_windows[index].parent_safe_rect;
+}
+
void Viewport::pass_mouse_focus_to(Viewport *p_viewport, Control *p_control) {
ERR_MAIN_THREAD_GUARD;
ERR_FAIL_NULL(p_viewport);
@@ -3848,7 +3883,7 @@ void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) {
}
if (own_world_3d.is_valid() && world_3d.is_valid()) {
- world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ world_3d->disconnect_changed(callable_mp(this, &Viewport::_own_world_3d_changed));
}
world_3d = p_world_3d;
@@ -3856,7 +3891,7 @@ void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) {
if (own_world_3d.is_valid()) {
if (world_3d.is_valid()) {
own_world_3d = world_3d->duplicate();
- world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ world_3d->connect_changed(callable_mp(this, &Viewport::_own_world_3d_changed));
} else {
own_world_3d = Ref<World3D>(memnew(World3D));
}
@@ -3907,14 +3942,14 @@ void Viewport::set_use_own_world_3d(bool p_use_own_world_3d) {
if (p_use_own_world_3d) {
if (world_3d.is_valid()) {
own_world_3d = world_3d->duplicate();
- world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ world_3d->connect_changed(callable_mp(this, &Viewport::_own_world_3d_changed));
} else {
own_world_3d = Ref<World3D>(memnew(World3D));
}
} else {
own_world_3d = Ref<World3D>();
if (world_3d.is_valid()) {
- world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ world_3d->disconnect_changed(callable_mp(this, &Viewport::_own_world_3d_changed));
}
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index af2907ca6f..e56d69a868 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -338,6 +338,7 @@ private:
struct SubWindow {
Window *window = nullptr;
RID canvas_item;
+ Rect2i parent_safe_rect;
};
// VRS
@@ -461,7 +462,7 @@ private:
void _sub_window_update(Window *p_window);
void _sub_window_grab_focus(Window *p_window);
void _sub_window_remove(Window *p_window);
- int _sub_window_find(Window *p_window);
+ int _sub_window_find(Window *p_window) const;
bool _sub_windows_forward_input(const Ref<InputEvent> &p_event);
SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point);
@@ -644,6 +645,8 @@ public:
void set_embedding_subwindows(bool p_embed);
bool is_embedding_subwindows() const;
+ void subwindow_set_popup_safe_rect(Window *p_window, const Rect2i &p_rect);
+ Rect2i subwindow_get_popup_safe_rect(Window *p_window) const;
Viewport *get_parent_viewport() const;
Window *get_base_window() const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 0aa6b69d6c..3ea53da141 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -54,21 +54,21 @@ bool Window::_set(const StringName &p_name, const Variant &p_value) {
if (name.begins_with("theme_override_icons/")) {
String dname = name.get_slicec('/', 1);
if (theme_icon_override.has(dname)) {
- theme_icon_override[dname]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ theme_icon_override[dname]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
theme_icon_override.erase(dname);
_notify_theme_override_changed();
} else if (name.begins_with("theme_override_styles/")) {
String dname = name.get_slicec('/', 1);
if (theme_style_override.has(dname)) {
- theme_style_override[dname]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ theme_style_override[dname]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
theme_style_override.erase(dname);
_notify_theme_override_changed();
} else if (name.begins_with("theme_override_fonts/")) {
String dname = name.get_slicec('/', 1);
if (theme_font_override.has(dname)) {
- theme_font_override[dname]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ theme_font_override[dname]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
theme_font_override.erase(dname);
_notify_theme_override_changed();
@@ -1823,13 +1823,13 @@ void Window::set_theme(const Ref<Theme> &p_theme) {
}
if (theme.is_valid()) {
- theme->disconnect("changed", callable_mp(this, &Window::_theme_changed));
+ theme->disconnect_changed(callable_mp(this, &Window::_theme_changed));
}
theme = p_theme;
if (theme.is_valid()) {
theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true);
- theme->connect("changed", callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED);
+ theme->connect_changed(callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED);
return;
}
@@ -2165,11 +2165,11 @@ void Window::add_theme_icon_override(const StringName &p_name, const Ref<Texture
ERR_FAIL_COND(!p_icon.is_valid());
if (theme_icon_override.has(p_name)) {
- theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ theme_icon_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
theme_icon_override[p_name] = p_icon;
- theme_icon_override[p_name]->connect("changed", callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ theme_icon_override[p_name]->connect_changed(callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
_notify_theme_override_changed();
}
@@ -2178,11 +2178,11 @@ void Window::add_theme_style_override(const StringName &p_name, const Ref<StyleB
ERR_FAIL_COND(!p_style.is_valid());
if (theme_style_override.has(p_name)) {
- theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ theme_style_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
theme_style_override[p_name] = p_style;
- theme_style_override[p_name]->connect("changed", callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ theme_style_override[p_name]->connect_changed(callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
_notify_theme_override_changed();
}
@@ -2191,11 +2191,11 @@ void Window::add_theme_font_override(const StringName &p_name, const Ref<Font> &
ERR_FAIL_COND(!p_font.is_valid());
if (theme_font_override.has(p_name)) {
- theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ theme_font_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
theme_font_override[p_name] = p_font;
- theme_font_override[p_name]->connect("changed", callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ theme_font_override[p_name]->connect_changed(callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
_notify_theme_override_changed();
}
@@ -2220,7 +2220,7 @@ void Window::add_theme_constant_override(const StringName &p_name, int p_constan
void Window::remove_theme_icon_override(const StringName &p_name) {
ERR_MAIN_THREAD_GUARD;
if (theme_icon_override.has(p_name)) {
- theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ theme_icon_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
theme_icon_override.erase(p_name);
@@ -2230,7 +2230,7 @@ void Window::remove_theme_icon_override(const StringName &p_name) {
void Window::remove_theme_style_override(const StringName &p_name) {
ERR_MAIN_THREAD_GUARD;
if (theme_style_override.has(p_name)) {
- theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ theme_style_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
theme_style_override.erase(p_name);
@@ -2240,7 +2240,7 @@ void Window::remove_theme_style_override(const StringName &p_name) {
void Window::remove_theme_font_override(const StringName &p_name) {
ERR_MAIN_THREAD_GUARD;
if (theme_font_override.has(p_name)) {
- theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ theme_font_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
theme_font_override.erase(p_name);
@@ -2653,7 +2653,7 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("popup_exclusive_centered_clamped", "from_node", "minsize", "fallback_ratio"), &Window::popup_exclusive_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75));
// Keep the enum values in sync with the `Mode` enum.
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
@@ -2768,13 +2768,13 @@ Window::~Window() {
// Resources need to be disconnected.
for (KeyValue<StringName, Ref<Texture2D>> &E : theme_icon_override) {
- E.value->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ E.value->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
for (KeyValue<StringName, Ref<StyleBox>> &E : theme_style_override) {
- E.value->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ E.value->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
for (KeyValue<StringName, Ref<Font>> &E : theme_font_override) {
- E.value->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
+ E.value->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed));
}
// Then override maps can be simply cleared.
diff --git a/scene/main/window.h b/scene/main/window.h
index b98b888380..7a10499d9b 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -315,7 +315,7 @@ public:
Window *get_parent_visible_window() const;
Viewport *get_parent_viewport() const;
- void popup(const Rect2i &p_screen_rect = Rect2i());
+ virtual void popup(const Rect2i &p_screen_rect = Rect2i());
void popup_on_parent(const Rect2i &p_parent_rect);
void popup_centered(const Size2i &p_minsize = Size2i());
void popup_centered_ratio(float p_ratio = 0.8);
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 9706fb1a5d..4d5d287fbe 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -139,30 +139,38 @@
#include "scene/main/timer.h"
#include "scene/main/viewport.h"
#include "scene/main/window.h"
+#include "scene/resources/animated_texture.h"
#include "scene/resources/animation_library.h"
+#include "scene/resources/atlas_texture.h"
#include "scene/resources/audio_stream_polyphonic.h"
#include "scene/resources/audio_stream_wav.h"
#include "scene/resources/bit_map.h"
#include "scene/resources/bone_map.h"
#include "scene/resources/box_shape_3d.h"
#include "scene/resources/camera_attributes.h"
+#include "scene/resources/camera_texture.h"
#include "scene/resources/capsule_shape_2d.h"
#include "scene/resources/capsule_shape_3d.h"
#include "scene/resources/circle_shape_2d.h"
+#include "scene/resources/compressed_texture.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
+#include "scene/resources/curve_texture.h"
#include "scene/resources/cylinder_shape_3d.h"
#include "scene/resources/default_theme/default_theme.h"
#include "scene/resources/environment.h"
#include "scene/resources/font.h"
#include "scene/resources/gradient.h"
+#include "scene/resources/gradient_texture.h"
#include "scene/resources/height_map_shape_3d.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/immediate_mesh.h"
#include "scene/resources/label_settings.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh_data_tool.h"
+#include "scene/resources/mesh_texture.h"
#include "scene/resources/multimesh.h"
#include "scene/resources/navigation_mesh.h"
#include "scene/resources/navigation_mesh_source_geometry_data_3d.h"
@@ -170,7 +178,9 @@
#include "scene/resources/packed_scene.h"
#include "scene/resources/particle_process_material.h"
#include "scene/resources/physics_material.h"
+#include "scene/resources/placeholder_textures.h"
#include "scene/resources/polygon_path_finder.h"
+#include "scene/resources/portable_compressed_texture.h"
#include "scene/resources/primitive_meshes.h"
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/resource_format_text.h"
@@ -192,12 +202,16 @@
#include "scene/resources/sky_material.h"
#include "scene/resources/sphere_shape_3d.h"
#include "scene/resources/style_box.h"
+#include "scene/resources/style_box_flat.h"
+#include "scene/resources/style_box_line.h"
+#include "scene/resources/style_box_texture.h"
#include "scene/resources/surface_tool.h"
#include "scene/resources/syntax_highlighter.h"
#include "scene/resources/text_file.h"
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
#include "scene/resources/texture.h"
+#include "scene/resources/texture_rd.h"
#include "scene/resources/theme.h"
#include "scene/resources/tile_set.h"
#include "scene/resources/video_stream.h"
@@ -662,6 +676,8 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeTexture3DParameter);
GDREGISTER_CLASS(VisualShaderNodeCubemapParameter);
GDREGISTER_CLASS(VisualShaderNodeLinearSceneDepth);
+ GDREGISTER_CLASS(VisualShaderNodeWorldPositionFromDepth);
+ GDREGISTER_CLASS(VisualShaderNodeScreenNormalWorldSpace);
GDREGISTER_CLASS(VisualShaderNodeIf);
GDREGISTER_CLASS(VisualShaderNodeSwitch);
GDREGISTER_CLASS(VisualShaderNodeFresnel);
@@ -675,6 +691,7 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeProximityFade);
GDREGISTER_CLASS(VisualShaderNodeRandomRange);
GDREGISTER_CLASS(VisualShaderNodeRemap);
+ GDREGISTER_CLASS(VisualShaderNodeRotationByAxis);
GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeVarying);
GDREGISTER_CLASS(VisualShaderNodeVaryingSetter);
GDREGISTER_CLASS(VisualShaderNodeVaryingGetter);
@@ -874,6 +891,14 @@ void register_scene_types() {
GDREGISTER_CLASS(PlaceholderCubemap);
GDREGISTER_CLASS(PlaceholderCubemapArray);
+ // These classes are part of renderer_rd
+ GDREGISTER_CLASS(Texture2DRD);
+ GDREGISTER_ABSTRACT_CLASS(TextureLayeredRD);
+ GDREGISTER_CLASS(Texture2DArrayRD);
+ GDREGISTER_CLASS(TextureCubemapRD);
+ GDREGISTER_CLASS(TextureCubemapArrayRD);
+ GDREGISTER_CLASS(Texture3DRD);
+
GDREGISTER_CLASS(Animation);
GDREGISTER_CLASS(AnimationLibrary);
diff --git a/scene/resources/animated_texture.cpp b/scene/resources/animated_texture.cpp
new file mode 100644
index 0000000000..842a398327
--- /dev/null
+++ b/scene/resources/animated_texture.cpp
@@ -0,0 +1,286 @@
+/**************************************************************************/
+/* animated_texture.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 "animated_texture.h"
+
+void AnimatedTexture::_update_proxy() {
+ RWLockRead r(rw_lock);
+
+ float delta;
+ if (prev_ticks == 0) {
+ delta = 0;
+ prev_ticks = OS::get_singleton()->get_ticks_usec();
+ } else {
+ uint64_t ticks = OS::get_singleton()->get_ticks_usec();
+ delta = float(double(ticks - prev_ticks) / 1000000.0);
+ prev_ticks = ticks;
+ }
+
+ time += delta;
+
+ float speed = speed_scale == 0 ? 0 : abs(1.0 / speed_scale);
+
+ int iter_max = frame_count;
+ while (iter_max && !pause) {
+ float frame_limit = frames[current_frame].duration * speed;
+
+ if (time > frame_limit) {
+ if (speed_scale > 0.0) {
+ current_frame++;
+ } else {
+ current_frame--;
+ }
+ if (current_frame >= frame_count) {
+ if (one_shot) {
+ current_frame = frame_count - 1;
+ } else {
+ current_frame = 0;
+ }
+ } else if (current_frame < 0) {
+ if (one_shot) {
+ current_frame = 0;
+ } else {
+ current_frame = frame_count - 1;
+ }
+ }
+ time -= frame_limit;
+
+ } else {
+ break;
+ }
+ iter_max--;
+ }
+
+ if (frames[current_frame].texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_proxy_update(proxy, frames[current_frame].texture->get_rid());
+ }
+}
+
+void AnimatedTexture::set_frames(int p_frames) {
+ ERR_FAIL_COND(p_frames < 1 || p_frames > MAX_FRAMES);
+
+ RWLockWrite r(rw_lock);
+
+ frame_count = p_frames;
+}
+
+int AnimatedTexture::get_frames() const {
+ return frame_count;
+}
+
+void AnimatedTexture::set_current_frame(int p_frame) {
+ ERR_FAIL_COND(p_frame < 0 || p_frame >= frame_count);
+
+ RWLockWrite r(rw_lock);
+
+ current_frame = p_frame;
+ time = 0;
+}
+
+int AnimatedTexture::get_current_frame() const {
+ return current_frame;
+}
+
+void AnimatedTexture::set_pause(bool p_pause) {
+ RWLockWrite r(rw_lock);
+ pause = p_pause;
+}
+
+bool AnimatedTexture::get_pause() const {
+ return pause;
+}
+
+void AnimatedTexture::set_one_shot(bool p_one_shot) {
+ RWLockWrite r(rw_lock);
+ one_shot = p_one_shot;
+}
+
+bool AnimatedTexture::get_one_shot() const {
+ return one_shot;
+}
+
+void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture) {
+ ERR_FAIL_COND(p_texture == this);
+ ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
+
+ RWLockWrite w(rw_lock);
+
+ frames[p_frame].texture = p_texture;
+}
+
+Ref<Texture2D> AnimatedTexture::get_frame_texture(int p_frame) const {
+ ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, Ref<Texture2D>());
+
+ RWLockRead r(rw_lock);
+
+ return frames[p_frame].texture;
+}
+
+void AnimatedTexture::set_frame_duration(int p_frame, float p_duration) {
+ ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
+
+ RWLockWrite r(rw_lock);
+
+ frames[p_frame].duration = p_duration;
+}
+
+float AnimatedTexture::get_frame_duration(int p_frame) const {
+ ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0);
+
+ RWLockRead r(rw_lock);
+
+ return frames[p_frame].duration;
+}
+
+void AnimatedTexture::set_speed_scale(float p_scale) {
+ ERR_FAIL_COND(p_scale < -1000 || p_scale >= 1000);
+
+ RWLockWrite r(rw_lock);
+
+ speed_scale = p_scale;
+}
+
+float AnimatedTexture::get_speed_scale() const {
+ return speed_scale;
+}
+
+int AnimatedTexture::get_width() const {
+ RWLockRead r(rw_lock);
+
+ if (!frames[current_frame].texture.is_valid()) {
+ return 1;
+ }
+
+ return frames[current_frame].texture->get_width();
+}
+
+int AnimatedTexture::get_height() const {
+ RWLockRead r(rw_lock);
+
+ if (!frames[current_frame].texture.is_valid()) {
+ return 1;
+ }
+
+ return frames[current_frame].texture->get_height();
+}
+
+RID AnimatedTexture::get_rid() const {
+ return proxy;
+}
+
+bool AnimatedTexture::has_alpha() const {
+ RWLockRead r(rw_lock);
+
+ if (!frames[current_frame].texture.is_valid()) {
+ return false;
+ }
+
+ return frames[current_frame].texture->has_alpha();
+}
+
+Ref<Image> AnimatedTexture::get_image() const {
+ RWLockRead r(rw_lock);
+
+ if (!frames[current_frame].texture.is_valid()) {
+ return Ref<Image>();
+ }
+
+ return frames[current_frame].texture->get_image();
+}
+
+bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
+ RWLockRead r(rw_lock);
+
+ if (frames[current_frame].texture.is_valid()) {
+ return frames[current_frame].texture->is_pixel_opaque(p_x, p_y);
+ }
+ return true;
+}
+
+void AnimatedTexture::_validate_property(PropertyInfo &p_property) const {
+ String prop = p_property.name;
+ if (prop.begins_with("frame_")) {
+ int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int();
+ if (frame >= frame_count) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+ }
+}
+
+void AnimatedTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_frames", "frames"), &AnimatedTexture::set_frames);
+ ClassDB::bind_method(D_METHOD("get_frames"), &AnimatedTexture::get_frames);
+
+ ClassDB::bind_method(D_METHOD("set_current_frame", "frame"), &AnimatedTexture::set_current_frame);
+ ClassDB::bind_method(D_METHOD("get_current_frame"), &AnimatedTexture::get_current_frame);
+
+ ClassDB::bind_method(D_METHOD("set_pause", "pause"), &AnimatedTexture::set_pause);
+ ClassDB::bind_method(D_METHOD("get_pause"), &AnimatedTexture::get_pause);
+
+ ClassDB::bind_method(D_METHOD("set_one_shot", "one_shot"), &AnimatedTexture::set_one_shot);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &AnimatedTexture::get_one_shot);
+
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &AnimatedTexture::set_speed_scale);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedTexture::get_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("set_frame_texture", "frame", "texture"), &AnimatedTexture::set_frame_texture);
+ ClassDB::bind_method(D_METHOD("get_frame_texture", "frame"), &AnimatedTexture::get_frame_texture);
+
+ ClassDB::bind_method(D_METHOD("set_frame_duration", "frame", "duration"), &AnimatedTexture::set_frame_duration);
+ ClassDB::bind_method(D_METHOD("get_frame_duration", "frame"), &AnimatedTexture::get_frame_duration);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_frame", "get_current_frame");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-60,60,0.1,or_less,or_greater"), "set_speed_scale", "get_speed_scale");
+
+ for (int i = 0; i < MAX_FRAMES; i++) {
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/duration", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_duration", "get_frame_duration", i);
+ }
+
+ BIND_CONSTANT(MAX_FRAMES);
+}
+
+AnimatedTexture::AnimatedTexture() {
+ //proxy = RS::get_singleton()->texture_create();
+ proxy_ph = RS::get_singleton()->texture_2d_placeholder_create();
+ proxy = RS::get_singleton()->texture_proxy_create(proxy_ph);
+
+ RenderingServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true);
+ RenderingServer::get_singleton()->connect("frame_pre_draw", callable_mp(this, &AnimatedTexture::_update_proxy));
+}
+
+AnimatedTexture::~AnimatedTexture() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(proxy);
+ RS::get_singleton()->free(proxy_ph);
+}
diff --git a/scene/resources/animated_texture.h b/scene/resources/animated_texture.h
new file mode 100644
index 0000000000..844959c810
--- /dev/null
+++ b/scene/resources/animated_texture.h
@@ -0,0 +1,109 @@
+/**************************************************************************/
+/* animated_texture.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 ANIMATED_TEXTURE_H
+#define ANIMATED_TEXTURE_H
+
+#include "scene/resources/texture.h"
+
+class AnimatedTexture : public Texture2D {
+ GDCLASS(AnimatedTexture, Texture2D);
+
+ // Use readers writers lock for this, since its far more times read than written to.
+ RWLock rw_lock;
+
+public:
+ enum {
+ MAX_FRAMES = 256
+ };
+
+private:
+ RID proxy_ph;
+ RID proxy;
+
+ struct Frame {
+ Ref<Texture2D> texture;
+ float duration = 1.0;
+ };
+
+ Frame frames[MAX_FRAMES];
+ int frame_count = 1.0;
+ int current_frame = 0;
+ bool pause = false;
+ bool one_shot = false;
+ float speed_scale = 1.0;
+
+ float time = 0.0;
+
+ uint64_t prev_ticks = 0;
+
+ void _update_proxy();
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+public:
+ void set_frames(int p_frames);
+ int get_frames() const;
+
+ void set_current_frame(int p_frame);
+ int get_current_frame() const;
+
+ void set_pause(bool p_pause);
+ bool get_pause() const;
+
+ void set_one_shot(bool p_one_shot);
+ bool get_one_shot() const;
+
+ void set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture);
+ Ref<Texture2D> get_frame_texture(int p_frame) const;
+
+ void set_frame_duration(int p_frame, float p_duration);
+ float get_frame_duration(int p_frame) const;
+
+ void set_speed_scale(float p_scale);
+ float get_speed_scale() const;
+
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual RID get_rid() const override;
+
+ virtual bool has_alpha() const override;
+
+ virtual Ref<Image> get_image() const override;
+
+ bool is_pixel_opaque(int p_x, int p_y) const override;
+
+ AnimatedTexture();
+ ~AnimatedTexture();
+};
+
+#endif // ANIMATED_TEXTURE_H
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 7078d60de5..860e48a361 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -427,6 +427,11 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
} else {
return false;
}
+#ifndef DISABLE_DEPRECATED
+ } else if (prop_name == "loop" && p_value.operator bool()) { // Compatibility with Godot 3.x.
+ loop_mode = Animation::LoopMode::LOOP_LINEAR;
+ return true;
+#endif // DISABLE_DEPRECATED
} else {
return false;
}
@@ -5503,6 +5508,9 @@ Variant Animation::add_variant(const Variant &a, const Variant &b) {
const ::AABB ab = b.operator ::AABB();
return ::AABB(aa.position + ab.position, aa.size + ab.size);
}
+ case Variant::BASIS: {
+ return (a.operator Basis()) * (b.operator Basis());
+ }
case Variant::QUATERNION: {
return (a.operator Quaternion()) * (b.operator Quaternion());
}
@@ -5550,14 +5558,17 @@ Variant Animation::subtract_variant(const Variant &a, const Variant &b) {
const ::AABB ab = b.operator ::AABB();
return ::AABB(aa.position - ab.position, aa.size - ab.size);
}
+ case Variant::BASIS: {
+ return (b.operator Basis()).inverse() * (a.operator Basis());
+ }
case Variant::QUATERNION: {
return (b.operator Quaternion()).inverse() * (a.operator Quaternion());
}
case Variant::TRANSFORM2D: {
- return (b.operator Transform2D()).inverse() * (a.operator Transform2D());
+ return (b.operator Transform2D()).affine_inverse() * (a.operator Transform2D());
}
case Variant::TRANSFORM3D: {
- return (b.operator Transform3D()).inverse() * (a.operator Transform3D());
+ return (b.operator Transform3D()).affine_inverse() * (a.operator Transform3D());
}
default: {
return Variant::evaluate(Variant::OP_SUBTRACT, a, b);
diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp
index 206e9df71a..a69b1818d2 100644
--- a/scene/resources/animation_library.cpp
+++ b/scene/resources/animation_library.cpp
@@ -52,13 +52,13 @@ Error AnimationLibrary::add_animation(const StringName &p_name, const Ref<Animat
ERR_FAIL_COND_V(p_animation.is_null(), ERR_INVALID_PARAMETER);
if (animations.has(p_name)) {
- animations.get(p_name)->disconnect(SNAME("changed"), callable_mp(this, &AnimationLibrary::_animation_changed));
+ animations.get(p_name)->disconnect_changed(callable_mp(this, &AnimationLibrary::_animation_changed));
animations.erase(p_name);
emit_signal(SNAME("animation_removed"), p_name);
}
animations.insert(p_name, p_animation);
- animations.get(p_name)->connect(SNAME("changed"), callable_mp(this, &AnimationLibrary::_animation_changed).bind(p_name));
+ animations.get(p_name)->connect_changed(callable_mp(this, &AnimationLibrary::_animation_changed).bind(p_name));
emit_signal(SNAME("animation_added"), p_name);
notify_property_list_changed();
return OK;
@@ -67,7 +67,7 @@ Error AnimationLibrary::add_animation(const StringName &p_name, const Ref<Animat
void AnimationLibrary::remove_animation(const StringName &p_name) {
ERR_FAIL_COND_MSG(!animations.has(p_name), vformat("Animation not found: %s.", p_name));
- animations.get(p_name)->disconnect(SNAME("changed"), callable_mp(this, &AnimationLibrary::_animation_changed));
+ animations.get(p_name)->disconnect_changed(callable_mp(this, &AnimationLibrary::_animation_changed));
animations.erase(p_name);
emit_signal(SNAME("animation_removed"), p_name);
notify_property_list_changed();
@@ -78,8 +78,8 @@ void AnimationLibrary::rename_animation(const StringName &p_name, const StringNa
ERR_FAIL_COND_MSG(!is_valid_animation_name(p_new_name), "Invalid animation name: '" + String(p_new_name) + "'.");
ERR_FAIL_COND_MSG(animations.has(p_new_name), vformat("Animation name \"%s\" already exists in library.", p_new_name));
- animations.get(p_name)->disconnect(SNAME("changed"), callable_mp(this, &AnimationLibrary::_animation_changed));
- animations.get(p_name)->connect(SNAME("changed"), callable_mp(this, &AnimationLibrary::_animation_changed).bind(p_new_name));
+ animations.get(p_name)->disconnect_changed(callable_mp(this, &AnimationLibrary::_animation_changed));
+ animations.get(p_name)->connect_changed(callable_mp(this, &AnimationLibrary::_animation_changed).bind(p_new_name));
animations.insert(p_new_name, animations[p_name]);
animations.erase(p_name);
emit_signal(SNAME("animation_renamed"), p_name, p_new_name);
@@ -125,7 +125,7 @@ void AnimationLibrary::get_animation_list(List<StringName> *p_animations) const
void AnimationLibrary::_set_data(const Dictionary &p_data) {
for (KeyValue<StringName, Ref<Animation>> &K : animations) {
- K.value->disconnect(SNAME("changed"), callable_mp(this, &AnimationLibrary::_animation_changed));
+ K.value->disconnect_changed(callable_mp(this, &AnimationLibrary::_animation_changed));
}
animations.clear();
List<Variant> keys;
diff --git a/scene/resources/atlas_texture.cpp b/scene/resources/atlas_texture.cpp
new file mode 100644
index 0000000000..24bf25f2db
--- /dev/null
+++ b/scene/resources/atlas_texture.cpp
@@ -0,0 +1,255 @@
+/**************************************************************************/
+/* atlas_texture.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 "atlas_texture.h"
+
+#include "core/core_string_names.h"
+
+int AtlasTexture::get_width() const {
+ if (region.size.width == 0) {
+ if (atlas.is_valid()) {
+ return atlas->get_width();
+ }
+ return 1;
+ } else {
+ return region.size.width + margin.size.width;
+ }
+}
+
+int AtlasTexture::get_height() const {
+ if (region.size.height == 0) {
+ if (atlas.is_valid()) {
+ return atlas->get_height();
+ }
+ return 1;
+ } else {
+ return region.size.height + margin.size.height;
+ }
+}
+
+RID AtlasTexture::get_rid() const {
+ if (atlas.is_valid()) {
+ return atlas->get_rid();
+ }
+
+ return RID();
+}
+
+bool AtlasTexture::has_alpha() const {
+ if (atlas.is_valid()) {
+ return atlas->has_alpha();
+ }
+
+ return false;
+}
+
+void AtlasTexture::set_atlas(const Ref<Texture2D> &p_atlas) {
+ ERR_FAIL_COND(p_atlas == this);
+ if (atlas == p_atlas) {
+ return;
+ }
+ // Support recursive AtlasTextures.
+ if (Ref<AtlasTexture>(atlas).is_valid()) {
+ atlas->disconnect_changed(callable_mp((Resource *)this, &AtlasTexture::emit_changed));
+ }
+ atlas = p_atlas;
+ if (Ref<AtlasTexture>(atlas).is_valid()) {
+ atlas->connect_changed(callable_mp((Resource *)this, &AtlasTexture::emit_changed));
+ }
+
+ emit_changed();
+}
+
+Ref<Texture2D> AtlasTexture::get_atlas() const {
+ return atlas;
+}
+
+void AtlasTexture::set_region(const Rect2 &p_region) {
+ if (region == p_region) {
+ return;
+ }
+ region = p_region;
+ emit_changed();
+}
+
+Rect2 AtlasTexture::get_region() const {
+ return region;
+}
+
+void AtlasTexture::set_margin(const Rect2 &p_margin) {
+ if (margin == p_margin) {
+ return;
+ }
+ margin = p_margin;
+ emit_changed();
+}
+
+Rect2 AtlasTexture::get_margin() const {
+ return margin;
+}
+
+void AtlasTexture::set_filter_clip(const bool p_enable) {
+ filter_clip = p_enable;
+ emit_changed();
+}
+
+bool AtlasTexture::has_filter_clip() const {
+ return filter_clip;
+}
+
+void AtlasTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_atlas", "atlas"), &AtlasTexture::set_atlas);
+ ClassDB::bind_method(D_METHOD("get_atlas"), &AtlasTexture::get_atlas);
+
+ ClassDB::bind_method(D_METHOD("set_region", "region"), &AtlasTexture::set_region);
+ ClassDB::bind_method(D_METHOD("get_region"), &AtlasTexture::get_region);
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &AtlasTexture::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &AtlasTexture::get_margin);
+
+ ClassDB::bind_method(D_METHOD("set_filter_clip", "enable"), &AtlasTexture::set_filter_clip);
+ ClassDB::bind_method(D_METHOD("has_filter_clip"), &AtlasTexture::has_filter_clip);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_atlas", "get_atlas");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region", PROPERTY_HINT_NONE, "suffix:px"), "set_region", "get_region");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin", PROPERTY_HINT_NONE, "suffix:px"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_clip"), "set_filter_clip", "has_filter_clip");
+}
+
+void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
+ if (!atlas.is_valid()) {
+ return;
+ }
+
+ Rect2 rc = region;
+
+ if (rc.size.width == 0) {
+ rc.size.width = atlas->get_width();
+ }
+
+ if (rc.size.height == 0) {
+ rc.size.height = atlas->get_height();
+ }
+
+ atlas->draw_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), rc, p_modulate, p_transpose, filter_clip);
+}
+
+void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
+ if (!atlas.is_valid()) {
+ return;
+ }
+
+ Rect2 rc = region;
+
+ if (rc.size.width == 0) {
+ rc.size.width = atlas->get_width();
+ }
+
+ if (rc.size.height == 0) {
+ rc.size.height = atlas->get_height();
+ }
+
+ Vector2 scale = p_rect.size / (region.size + margin.size);
+ Rect2 dr(p_rect.position + margin.position * scale, rc.size * scale);
+
+ atlas->draw_rect_region(p_canvas_item, dr, rc, p_modulate, p_transpose, filter_clip);
+}
+
+void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
+ //this might not necessarily work well if using a rect, needs to be fixed properly
+ if (!atlas.is_valid()) {
+ return;
+ }
+
+ Rect2 dr;
+ Rect2 src_c;
+ get_rect_region(p_rect, p_src_rect, dr, src_c);
+
+ atlas->draw_rect_region(p_canvas_item, dr, src_c, p_modulate, p_transpose, filter_clip);
+}
+
+bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
+ if (!atlas.is_valid()) {
+ return false;
+ }
+
+ Rect2 src = p_src_rect;
+ if (src.size == Size2()) {
+ src.size = region.size;
+ }
+ Vector2 scale = p_rect.size / src.size;
+
+ src.position += (region.position - margin.position);
+ Rect2 src_clipped = region.intersection(src);
+ if (src_clipped.size == Size2()) {
+ return false;
+ }
+
+ Vector2 ofs = (src_clipped.position - src.position);
+ if (scale.x < 0) {
+ ofs.x += (src_clipped.size.x - src.size.x);
+ }
+ if (scale.y < 0) {
+ ofs.y += (src_clipped.size.y - src.size.y);
+ }
+
+ r_rect = Rect2(p_rect.position + ofs * scale, src_clipped.size * scale);
+ r_src_rect = src_clipped;
+ return true;
+}
+
+bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const {
+ if (!atlas.is_valid()) {
+ return true;
+ }
+
+ int x = p_x + region.position.x - margin.position.x;
+ int y = p_y + region.position.y - margin.position.y;
+
+ // margin edge may outside of atlas
+ if (x < 0 || x >= atlas->get_width()) {
+ return false;
+ }
+ if (y < 0 || y >= atlas->get_height()) {
+ return false;
+ }
+
+ return atlas->is_pixel_opaque(x, y);
+}
+
+Ref<Image> AtlasTexture::get_image() const {
+ if (!atlas.is_valid() || !atlas->get_image().is_valid()) {
+ return Ref<Image>();
+ }
+
+ return atlas->get_image()->get_region(region);
+}
+
+AtlasTexture::AtlasTexture() {}
diff --git a/scene/resources/atlas_texture.h b/scene/resources/atlas_texture.h
new file mode 100644
index 0000000000..5aba098d09
--- /dev/null
+++ b/scene/resources/atlas_texture.h
@@ -0,0 +1,79 @@
+/**************************************************************************/
+/* atlas_texture.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 ATLAS_TEXTURE_H
+#define ATLAS_TEXTURE_H
+
+#include "scene/resources/texture.h"
+
+class AtlasTexture : public Texture2D {
+ GDCLASS(AtlasTexture, Texture2D);
+ RES_BASE_EXTENSION("atlastex");
+
+protected:
+ Ref<Texture2D> atlas;
+ Rect2 region;
+ Rect2 margin;
+ bool filter_clip = false;
+
+ static void _bind_methods();
+
+public:
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual RID get_rid() const override;
+
+ virtual bool has_alpha() const override;
+
+ void set_atlas(const Ref<Texture2D> &p_atlas);
+ Ref<Texture2D> get_atlas() const;
+
+ void set_region(const Rect2 &p_region);
+ Rect2 get_region() const;
+
+ void set_margin(const Rect2 &p_margin);
+ Rect2 get_margin() const;
+
+ void set_filter_clip(const bool p_enable);
+ bool has_filter_clip() const;
+
+ virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
+ virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const override;
+
+ bool is_pixel_opaque(int p_x, int p_y) const override;
+
+ virtual Ref<Image> get_image() const override;
+
+ AtlasTexture();
+};
+
+#endif // ATLAS_TEXTURE_H
diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp
index 6a1f7dc6ea..313aeb1bca 100644
--- a/scene/resources/box_shape_3d.cpp
+++ b/scene/resources/box_shape_3d.cpp
@@ -80,7 +80,7 @@ void BoxShape3D::set_size(const Vector3 &p_size) {
ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0 || p_size.z < 0, "BoxShape3D size cannot be negative.");
size = p_size;
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
Vector3 BoxShape3D::get_size() const {
diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp
index 8f4f804397..7c46729af3 100644
--- a/scene/resources/camera_attributes.cpp
+++ b/scene/resources/camera_attributes.cpp
@@ -122,7 +122,7 @@ void CameraAttributes::_bind_methods() {
ADD_GROUP("Exposure", "exposure_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_sensitivity", PROPERTY_HINT_RANGE, "0.1,32000.0,0.1,suffix:ISO"), "set_exposure_sensitivity", "get_exposure_sensitivity");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_multiplier", PROPERTY_HINT_RANGE, "0.0,2048.0,0.001"), "set_exposure_multiplier", "get_exposure_multiplier");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_multiplier", PROPERTY_HINT_RANGE, "0.0,8.0,0.001,or_greater"), "set_exposure_multiplier", "get_exposure_multiplier");
ADD_GROUP("Auto Exposure", "auto_exposure_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_auto_exposure_enabled", "is_auto_exposure_enabled");
diff --git a/scene/resources/camera_texture.cpp b/scene/resources/camera_texture.cpp
new file mode 100644
index 0000000000..b575a099ed
--- /dev/null
+++ b/scene/resources/camera_texture.cpp
@@ -0,0 +1,131 @@
+/**************************************************************************/
+/* camera_texture.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 "camera_texture.h"
+
+#include "servers/camera/camera_feed.h"
+
+void CameraTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_camera_feed_id", "feed_id"), &CameraTexture::set_camera_feed_id);
+ ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &CameraTexture::get_camera_feed_id);
+
+ ClassDB::bind_method(D_METHOD("set_which_feed", "which_feed"), &CameraTexture::set_which_feed);
+ ClassDB::bind_method(D_METHOD("get_which_feed"), &CameraTexture::get_which_feed);
+
+ ClassDB::bind_method(D_METHOD("set_camera_active", "active"), &CameraTexture::set_camera_active);
+ ClassDB::bind_method(D_METHOD("get_camera_active"), &CameraTexture::get_camera_active);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "camera_feed_id"), "set_camera_feed_id", "get_camera_feed_id");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "which_feed"), "set_which_feed", "get_which_feed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "camera_is_active"), "set_camera_active", "get_camera_active");
+}
+
+int CameraTexture::get_width() const {
+ Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
+ if (feed.is_valid()) {
+ return feed->get_base_width();
+ } else {
+ return 0;
+ }
+}
+
+int CameraTexture::get_height() const {
+ Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
+ if (feed.is_valid()) {
+ return feed->get_base_height();
+ } else {
+ return 0;
+ }
+}
+
+bool CameraTexture::has_alpha() const {
+ return false;
+}
+
+RID CameraTexture::get_rid() const {
+ Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
+ if (feed.is_valid()) {
+ return feed->get_texture(which_feed);
+ } else {
+ if (_texture.is_null()) {
+ _texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
+ }
+ return _texture;
+ }
+}
+
+Ref<Image> CameraTexture::get_image() const {
+ // not (yet) supported
+ return Ref<Image>();
+}
+
+void CameraTexture::set_camera_feed_id(int p_new_id) {
+ camera_feed_id = p_new_id;
+ notify_property_list_changed();
+}
+
+int CameraTexture::get_camera_feed_id() const {
+ return camera_feed_id;
+}
+
+void CameraTexture::set_which_feed(CameraServer::FeedImage p_which) {
+ which_feed = p_which;
+ notify_property_list_changed();
+}
+
+CameraServer::FeedImage CameraTexture::get_which_feed() const {
+ return which_feed;
+}
+
+void CameraTexture::set_camera_active(bool p_active) {
+ Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
+ if (feed.is_valid()) {
+ feed->set_active(p_active);
+ notify_property_list_changed();
+ }
+}
+
+bool CameraTexture::get_camera_active() const {
+ Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
+ if (feed.is_valid()) {
+ return feed->is_active();
+ } else {
+ return false;
+ }
+}
+
+CameraTexture::CameraTexture() {}
+
+CameraTexture::~CameraTexture() {
+ if (_texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RenderingServer::get_singleton()->free(_texture);
+ }
+}
diff --git a/scene/resources/camera_texture.h b/scene/resources/camera_texture.h
new file mode 100644
index 0000000000..521121f9ea
--- /dev/null
+++ b/scene/resources/camera_texture.h
@@ -0,0 +1,68 @@
+/**************************************************************************/
+/* camera_texture.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 CAMERA_TEXTURE_H
+#define CAMERA_TEXTURE_H
+
+#include "scene/resources/texture.h"
+
+class CameraTexture : public Texture2D {
+ GDCLASS(CameraTexture, Texture2D);
+
+private:
+ mutable RID _texture;
+ int camera_feed_id = 0;
+ CameraServer::FeedImage which_feed = CameraServer::FEED_RGBA_IMAGE;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual RID get_rid() const override;
+ virtual bool has_alpha() const override;
+
+ virtual Ref<Image> get_image() const override;
+
+ void set_camera_feed_id(int p_new_id);
+ int get_camera_feed_id() const;
+
+ void set_which_feed(CameraServer::FeedImage p_which);
+ CameraServer::FeedImage get_which_feed() const;
+
+ void set_camera_active(bool p_active);
+ bool get_camera_active() const;
+
+ CameraTexture();
+ ~CameraTexture();
+};
+
+#endif // CAMERA_TEXTURE_H
diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp
index 3edff0cc68..9e16801060 100644
--- a/scene/resources/capsule_shape_3d.cpp
+++ b/scene/resources/capsule_shape_3d.cpp
@@ -86,7 +86,7 @@ void CapsuleShape3D::set_radius(float p_radius) {
height = radius * 2.0;
}
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
float CapsuleShape3D::get_radius() const {
@@ -100,7 +100,7 @@ void CapsuleShape3D::set_height(float p_height) {
radius = height * 0.5;
}
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
float CapsuleShape3D::get_height() const {
diff --git a/scene/resources/compressed_texture.cpp b/scene/resources/compressed_texture.cpp
new file mode 100644
index 0000000000..f4395d5c7d
--- /dev/null
+++ b/scene/resources/compressed_texture.cpp
@@ -0,0 +1,907 @@
+/**************************************************************************/
+/* compressed_texture.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 "compressed_texture.h"
+
+#include "scene/resources/bit_map.h"
+
+Error CompressedTexture2D::_load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) {
+ alpha_cache.unref();
+
+ ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER);
+
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));
+
+ uint8_t header[4];
+ f->get_buffer(header, 4);
+ if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != '2') {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is corrupt (Bad header).");
+ }
+
+ uint32_t version = f->get_32();
+
+ if (version > FORMAT_VERSION) {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new.");
+ }
+ r_width = f->get_32();
+ r_height = f->get_32();
+ uint32_t df = f->get_32(); //data format
+
+ //skip reserved
+ mipmap_limit = int(f->get_32());
+ //reserved
+ f->get_32();
+ f->get_32();
+ f->get_32();
+
+#ifdef TOOLS_ENABLED
+
+ r_request_3d = request_3d_callback && df & FORMAT_BIT_DETECT_3D;
+ r_request_roughness = request_roughness_callback && df & FORMAT_BIT_DETECT_ROUGNESS;
+ r_request_normal = request_normal_callback && df & FORMAT_BIT_DETECT_NORMAL;
+
+#else
+
+ r_request_3d = false;
+ r_request_roughness = false;
+ r_request_normal = false;
+
+#endif
+ if (!(df & FORMAT_BIT_STREAM)) {
+ p_size_limit = 0;
+ }
+
+ image = load_image_from_file(f, p_size_limit);
+
+ if (image.is_null() || image->is_empty()) {
+ return ERR_CANT_OPEN;
+ }
+
+ return OK;
+}
+
+void CompressedTexture2D::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+void CompressedTexture2D::_requested_3d(void *p_ud) {
+ CompressedTexture2D *ct = (CompressedTexture2D *)p_ud;
+ Ref<CompressedTexture2D> ctex(ct);
+ ERR_FAIL_NULL(request_3d_callback);
+ request_3d_callback(ctex);
+}
+
+void CompressedTexture2D::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) {
+ CompressedTexture2D *ct = (CompressedTexture2D *)p_ud;
+ Ref<CompressedTexture2D> ctex(ct);
+ ERR_FAIL_NULL(request_roughness_callback);
+ request_roughness_callback(ctex, p_normal_path, p_roughness_channel);
+}
+
+void CompressedTexture2D::_requested_normal(void *p_ud) {
+ CompressedTexture2D *ct = (CompressedTexture2D *)p_ud;
+ Ref<CompressedTexture2D> ctex(ct);
+ ERR_FAIL_NULL(request_normal_callback);
+ request_normal_callback(ctex);
+}
+
+CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_3d_callback = nullptr;
+CompressedTexture2D::TextureFormatRoughnessRequestCallback CompressedTexture2D::request_roughness_callback = nullptr;
+CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_normal_callback = nullptr;
+
+Image::Format CompressedTexture2D::get_format() const {
+ return format;
+}
+
+Error CompressedTexture2D::load(const String &p_path) {
+ int lw, lh;
+ Ref<Image> image;
+ image.instantiate();
+
+ bool request_3d;
+ bool request_normal;
+ bool request_roughness;
+ int mipmap_limit;
+
+ Error err = _load_data(p_path, lw, lh, image, request_3d, request_normal, request_roughness, mipmap_limit);
+ if (err) {
+ return err;
+ }
+
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_2d_create(image);
+ }
+ if (lw || lh) {
+ RS::get_singleton()->texture_set_size_override(texture, lw, lh);
+ }
+
+ w = lw;
+ h = lh;
+ path_to_file = p_path;
+ format = image->get_format();
+
+ if (get_path().is_empty()) {
+ //temporarily set path if no path set for resource, helps find errors
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+#ifdef TOOLS_ENABLED
+
+ if (request_3d) {
+ //print_line("request detect 3D at " + p_path);
+ RS::get_singleton()->texture_set_detect_3d_callback(texture, _requested_3d, this);
+ } else {
+ //print_line("not requesting detect 3D at " + p_path);
+ RS::get_singleton()->texture_set_detect_3d_callback(texture, nullptr, nullptr);
+ }
+
+ if (request_roughness) {
+ //print_line("request detect srgb at " + p_path);
+ RS::get_singleton()->texture_set_detect_roughness_callback(texture, _requested_roughness, this);
+ } else {
+ //print_line("not requesting detect srgb at " + p_path);
+ RS::get_singleton()->texture_set_detect_roughness_callback(texture, nullptr, nullptr);
+ }
+
+ if (request_normal) {
+ //print_line("request detect srgb at " + p_path);
+ RS::get_singleton()->texture_set_detect_normal_callback(texture, _requested_normal, this);
+ } else {
+ //print_line("not requesting detect normal at " + p_path);
+ RS::get_singleton()->texture_set_detect_normal_callback(texture, nullptr, nullptr);
+ }
+
+#endif
+ notify_property_list_changed();
+ emit_changed();
+ return OK;
+}
+
+String CompressedTexture2D::get_load_path() const {
+ return path_to_file;
+}
+
+int CompressedTexture2D::get_width() const {
+ return w;
+}
+
+int CompressedTexture2D::get_height() const {
+ return h;
+}
+
+RID CompressedTexture2D::get_rid() const {
+ if (!texture.is_valid()) {
+ texture = RS::get_singleton()->texture_2d_placeholder_create();
+ }
+ return texture;
+}
+
+void CompressedTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
+ if ((w | h) == 0) {
+ return;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose);
+}
+
+void CompressedTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
+ if ((w | h) == 0) {
+ return;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);
+}
+
+void CompressedTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
+ if ((w | h) == 0) {
+ return;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv);
+}
+
+bool CompressedTexture2D::has_alpha() const {
+ return false;
+}
+
+Ref<Image> CompressedTexture2D::get_image() const {
+ if (texture.is_valid()) {
+ return RS::get_singleton()->texture_2d_get(texture);
+ } else {
+ return Ref<Image>();
+ }
+}
+
+bool CompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {
+ if (!alpha_cache.is_valid()) {
+ Ref<Image> img = get_image();
+ if (img.is_valid()) {
+ if (img->is_compressed()) { //must decompress, if compressed
+ Ref<Image> decom = img->duplicate();
+ decom->decompress();
+ img = decom;
+ }
+
+ alpha_cache.instantiate();
+ alpha_cache->create_from_image_alpha(img);
+ }
+ }
+
+ if (alpha_cache.is_valid()) {
+ int aw = int(alpha_cache->get_size().width);
+ int ah = int(alpha_cache->get_size().height);
+ if (aw == 0 || ah == 0) {
+ return true;
+ }
+
+ int x = p_x * aw / w;
+ int y = p_y * ah / h;
+
+ x = CLAMP(x, 0, aw);
+ y = CLAMP(y, 0, ah);
+
+ return alpha_cache->get_bit(x, y);
+ }
+
+ return true;
+}
+
+void CompressedTexture2D::reload_from_file() {
+ String path = get_path();
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ path = ResourceLoader::path_remap(path); //remap for translation
+ path = ResourceLoader::import_remap(path); //remap for import
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ load(path);
+}
+
+void CompressedTexture2D::_validate_property(PropertyInfo &p_property) const {
+}
+
+Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_size_limit) {
+ uint32_t data_format = f->get_32();
+ uint32_t w = f->get_16();
+ uint32_t h = f->get_16();
+ uint32_t mipmaps = f->get_32();
+ Image::Format format = Image::Format(f->get_32());
+
+ if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP) {
+ //look for a PNG or WebP file inside
+
+ int sw = w;
+ int sh = h;
+
+ //mipmaps need to be read independently, they will be later combined
+ Vector<Ref<Image>> mipmap_images;
+ uint64_t total_size = 0;
+
+ bool first = true;
+
+ for (uint32_t i = 0; i < mipmaps + 1; i++) {
+ uint32_t size = f->get_32();
+
+ if (p_size_limit > 0 && i < (mipmaps - 1) && (sw > p_size_limit || sh > p_size_limit)) {
+ //can't load this due to size limit
+ sw = MAX(sw >> 1, 1);
+ sh = MAX(sh >> 1, 1);
+ f->seek(f->get_position() + size);
+ continue;
+ }
+
+ Vector<uint8_t> pv;
+ pv.resize(size);
+ {
+ uint8_t *wr = pv.ptrw();
+ f->get_buffer(wr, size);
+ }
+
+ Ref<Image> img;
+ if (data_format == DATA_FORMAT_PNG && Image::png_unpacker) {
+ img = Image::png_unpacker(pv);
+ } else if (data_format == DATA_FORMAT_WEBP && Image::webp_unpacker) {
+ img = Image::webp_unpacker(pv);
+ }
+
+ if (img.is_null() || img->is_empty()) {
+ ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref<Image>());
+ }
+
+ if (first) {
+ //format will actually be the format of the first image,
+ //as it may have changed on compression
+ format = img->get_format();
+ first = false;
+ } else if (img->get_format() != format) {
+ img->convert(format); //all needs to be the same format
+ }
+
+ total_size += img->get_data().size();
+
+ mipmap_images.push_back(img);
+
+ sw = MAX(sw >> 1, 1);
+ sh = MAX(sh >> 1, 1);
+ }
+
+ //print_line("mipmap read total: " + itos(mipmap_images.size()));
+
+ Ref<Image> image;
+ image.instantiate();
+
+ if (mipmap_images.size() == 1) {
+ //only one image (which will most likely be the case anyway for this format)
+ image = mipmap_images[0];
+ return image;
+
+ } else {
+ //rarer use case, but needs to be supported
+ Vector<uint8_t> img_data;
+ img_data.resize(total_size);
+
+ {
+ uint8_t *wr = img_data.ptrw();
+
+ int ofs = 0;
+ for (int i = 0; i < mipmap_images.size(); i++) {
+ Vector<uint8_t> id = mipmap_images[i]->get_data();
+ int len = id.size();
+ const uint8_t *r = id.ptr();
+ memcpy(&wr[ofs], r, len);
+ ofs += len;
+ }
+ }
+
+ image->set_data(w, h, true, mipmap_images[0]->get_format(), img_data);
+ return image;
+ }
+
+ } else if (data_format == DATA_FORMAT_BASIS_UNIVERSAL) {
+ int sw = w;
+ int sh = h;
+ uint32_t size = f->get_32();
+ if (p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) {
+ //can't load this due to size limit
+ sw = MAX(sw >> 1, 1);
+ sh = MAX(sh >> 1, 1);
+ f->seek(f->get_position() + size);
+ return Ref<Image>();
+ }
+ Vector<uint8_t> pv;
+ pv.resize(size);
+ {
+ uint8_t *wr = pv.ptrw();
+ f->get_buffer(wr, size);
+ }
+ Ref<Image> img;
+ img = Image::basis_universal_unpacker(pv);
+ if (img.is_null() || img->is_empty()) {
+ ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref<Image>());
+ }
+ format = img->get_format();
+ sw = MAX(sw >> 1, 1);
+ sh = MAX(sh >> 1, 1);
+ return img;
+ } else if (data_format == DATA_FORMAT_IMAGE) {
+ int size = Image::get_image_data_size(w, h, format, mipmaps ? true : false);
+
+ for (uint32_t i = 0; i < mipmaps + 1; i++) {
+ int tw, th;
+ int ofs = Image::get_image_mipmap_offset_and_dimensions(w, h, format, i, tw, th);
+
+ if (p_size_limit > 0 && i < mipmaps && (p_size_limit > tw || p_size_limit > th)) {
+ if (ofs) {
+ f->seek(f->get_position() + ofs);
+ }
+ continue; //oops, size limit enforced, go to next
+ }
+
+ Vector<uint8_t> data;
+ data.resize(size - ofs);
+
+ {
+ uint8_t *wr = data.ptrw();
+ f->get_buffer(wr, data.size());
+ }
+
+ Ref<Image> image = Image::create_from_data(tw, th, mipmaps - i ? true : false, format, data);
+
+ return image;
+ }
+ }
+
+ return Ref<Image>();
+}
+
+void CompressedTexture2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture2D::load);
+ ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture2D::get_load_path);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");
+}
+
+CompressedTexture2D::CompressedTexture2D() {}
+
+CompressedTexture2D::~CompressedTexture2D() {
+ if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(texture);
+ }
+}
+
+Ref<Resource> ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<CompressedTexture2D> st;
+ st.instantiate();
+ Error err = st->load(p_path);
+ if (r_error) {
+ *r_error = err;
+ }
+ if (err != OK) {
+ return Ref<Resource>();
+ }
+
+ return st;
+}
+
+void ResourceFormatLoaderCompressedTexture2D::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("ctex");
+}
+
+bool ResourceFormatLoaderCompressedTexture2D::handles_type(const String &p_type) const {
+ return p_type == "CompressedTexture2D";
+}
+
+String ResourceFormatLoaderCompressedTexture2D::get_resource_type(const String &p_path) const {
+ if (p_path.get_extension().to_lower() == "ctex") {
+ return "CompressedTexture2D";
+ }
+ return "";
+}
+
+void CompressedTexture3D::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+Image::Format CompressedTexture3D::get_format() const {
+ return format;
+}
+
+Error CompressedTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));
+
+ uint8_t header[4];
+ f->get_buffer(header, 4);
+ ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L', ERR_FILE_UNRECOGNIZED);
+
+ //stored as compressed textures (used for lossless and lossy compression)
+ uint32_t version = f->get_32();
+
+ if (version > FORMAT_VERSION) {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new.");
+ }
+
+ r_depth = f->get_32(); //depth
+ f->get_32(); //ignored (mode)
+ f->get_32(); // ignored (data format)
+
+ f->get_32(); //ignored
+ int mipmap_count = f->get_32();
+ f->get_32(); //ignored
+ f->get_32(); //ignored
+
+ r_mipmaps = mipmap_count != 0;
+
+ r_data.clear();
+
+ for (int i = 0; i < (r_depth + mipmap_count); i++) {
+ Ref<Image> image = CompressedTexture2D::load_image_from_file(f, 0);
+ ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);
+ if (i == 0) {
+ r_format = image->get_format();
+ r_width = image->get_width();
+ r_height = image->get_height();
+ }
+ r_data.push_back(image);
+ }
+
+ return OK;
+}
+
+Error CompressedTexture3D::load(const String &p_path) {
+ Vector<Ref<Image>> data;
+
+ int tw, th, td;
+ Image::Format tfmt;
+ bool tmm;
+
+ Error err = _load_data(p_path, data, tfmt, tw, th, td, tmm);
+ if (err) {
+ return err;
+ }
+
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data);
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data);
+ }
+
+ w = tw;
+ h = th;
+ d = td;
+ mipmaps = tmm;
+ format = tfmt;
+
+ path_to_file = p_path;
+
+ if (get_path().is_empty()) {
+ //temporarily set path if no path set for resource, helps find errors
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ notify_property_list_changed();
+ emit_changed();
+ return OK;
+}
+
+String CompressedTexture3D::get_load_path() const {
+ return path_to_file;
+}
+
+int CompressedTexture3D::get_width() const {
+ return w;
+}
+
+int CompressedTexture3D::get_height() const {
+ return h;
+}
+
+int CompressedTexture3D::get_depth() const {
+ return d;
+}
+
+bool CompressedTexture3D::has_mipmaps() const {
+ return mipmaps;
+}
+
+RID CompressedTexture3D::get_rid() const {
+ if (!texture.is_valid()) {
+ texture = RS::get_singleton()->texture_3d_placeholder_create();
+ }
+ return texture;
+}
+
+Vector<Ref<Image>> CompressedTexture3D::get_data() const {
+ if (texture.is_valid()) {
+ return RS::get_singleton()->texture_3d_get(texture);
+ } else {
+ return Vector<Ref<Image>>();
+ }
+}
+
+void CompressedTexture3D::reload_from_file() {
+ String path = get_path();
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ path = ResourceLoader::path_remap(path); //remap for translation
+ path = ResourceLoader::import_remap(path); //remap for import
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ load(path);
+}
+
+void CompressedTexture3D::_validate_property(PropertyInfo &p_property) const {
+}
+
+void CompressedTexture3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture3D::load);
+ ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture3D::get_load_path);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");
+}
+
+CompressedTexture3D::CompressedTexture3D() {}
+
+CompressedTexture3D::~CompressedTexture3D() {
+ if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(texture);
+ }
+}
+
+Ref<Resource> ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<CompressedTexture3D> st;
+ st.instantiate();
+ Error err = st->load(p_path);
+ if (r_error) {
+ *r_error = err;
+ }
+ if (err != OK) {
+ return Ref<Resource>();
+ }
+
+ return st;
+}
+
+void ResourceFormatLoaderCompressedTexture3D::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("ctex3d");
+}
+
+bool ResourceFormatLoaderCompressedTexture3D::handles_type(const String &p_type) const {
+ return p_type == "CompressedTexture3D";
+}
+
+String ResourceFormatLoaderCompressedTexture3D::get_resource_type(const String &p_path) const {
+ if (p_path.get_extension().to_lower() == "ctex3d") {
+ return "CompressedTexture3D";
+ }
+ return "";
+}
+
+void CompressedTextureLayered::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+Image::Format CompressedTextureLayered::get_format() const {
+ return format;
+}
+
+Error CompressedTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit) {
+ ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER);
+
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));
+
+ uint8_t header[4];
+ f->get_buffer(header, 4);
+ if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L') {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture layered file is corrupt (Bad header).");
+ }
+
+ uint32_t version = f->get_32();
+
+ if (version > FORMAT_VERSION) {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new.");
+ }
+
+ uint32_t layer_count = f->get_32(); //layer count
+ uint32_t type = f->get_32(); //layer count
+ ERR_FAIL_COND_V((int)type != layered_type, ERR_INVALID_DATA);
+
+ uint32_t df = f->get_32(); //data format
+ mipmap_limit = int(f->get_32());
+ //reserved
+ f->get_32();
+ f->get_32();
+ f->get_32();
+
+ if (!(df & FORMAT_BIT_STREAM)) {
+ p_size_limit = 0;
+ }
+
+ images.resize(layer_count);
+
+ for (uint32_t i = 0; i < layer_count; i++) {
+ Ref<Image> image = CompressedTexture2D::load_image_from_file(f, p_size_limit);
+ ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);
+ images.write[i] = image;
+ }
+
+ return OK;
+}
+
+Error CompressedTextureLayered::load(const String &p_path) {
+ Vector<Ref<Image>> images;
+
+ int mipmap_limit;
+
+ Error err = _load_data(p_path, images, mipmap_limit);
+ if (err) {
+ return err;
+ }
+
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TextureLayeredType(layered_type));
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TextureLayeredType(layered_type));
+ }
+
+ w = images[0]->get_width();
+ h = images[0]->get_height();
+ mipmaps = images[0]->has_mipmaps();
+ format = images[0]->get_format();
+ layers = images.size();
+
+ path_to_file = p_path;
+
+ if (get_path().is_empty()) {
+ //temporarily set path if no path set for resource, helps find errors
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ notify_property_list_changed();
+ emit_changed();
+ return OK;
+}
+
+String CompressedTextureLayered::get_load_path() const {
+ return path_to_file;
+}
+
+int CompressedTextureLayered::get_width() const {
+ return w;
+}
+
+int CompressedTextureLayered::get_height() const {
+ return h;
+}
+
+int CompressedTextureLayered::get_layers() const {
+ return layers;
+}
+
+bool CompressedTextureLayered::has_mipmaps() const {
+ return mipmaps;
+}
+
+TextureLayered::LayeredType CompressedTextureLayered::get_layered_type() const {
+ return layered_type;
+}
+
+RID CompressedTextureLayered::get_rid() const {
+ if (!texture.is_valid()) {
+ texture = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));
+ }
+ return texture;
+}
+
+Ref<Image> CompressedTextureLayered::get_layer_data(int p_layer) const {
+ if (texture.is_valid()) {
+ return RS::get_singleton()->texture_2d_layer_get(texture, p_layer);
+ } else {
+ return Ref<Image>();
+ }
+}
+
+void CompressedTextureLayered::reload_from_file() {
+ String path = get_path();
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ path = ResourceLoader::path_remap(path); //remap for translation
+ path = ResourceLoader::import_remap(path); //remap for import
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ load(path);
+}
+
+void CompressedTextureLayered::_validate_property(PropertyInfo &p_property) const {
+}
+
+void CompressedTextureLayered::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTextureLayered::load);
+ ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTextureLayered::get_load_path);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");
+}
+
+CompressedTextureLayered::CompressedTextureLayered(LayeredType p_type) {
+ layered_type = p_type;
+}
+
+CompressedTextureLayered::~CompressedTextureLayered() {
+ if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(texture);
+ }
+}
+
+/////////////////////////////////////////////////
+
+Ref<Resource> ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<CompressedTextureLayered> ct;
+ if (p_path.get_extension().to_lower() == "ctexarray") {
+ Ref<CompressedTexture2DArray> c;
+ c.instantiate();
+ ct = c;
+ } else if (p_path.get_extension().to_lower() == "ccube") {
+ Ref<CompressedCubemap> c;
+ c.instantiate();
+ ct = c;
+ } else if (p_path.get_extension().to_lower() == "ccubearray") {
+ Ref<CompressedCubemapArray> c;
+ c.instantiate();
+ ct = c;
+ } else {
+ if (r_error) {
+ *r_error = ERR_FILE_UNRECOGNIZED;
+ }
+ return Ref<Resource>();
+ }
+ Error err = ct->load(p_path);
+ if (r_error) {
+ *r_error = err;
+ }
+ if (err != OK) {
+ return Ref<Resource>();
+ }
+
+ return ct;
+}
+
+void ResourceFormatLoaderCompressedTextureLayered::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("ctexarray");
+ p_extensions->push_back("ccube");
+ p_extensions->push_back("ccubearray");
+}
+
+bool ResourceFormatLoaderCompressedTextureLayered::handles_type(const String &p_type) const {
+ return p_type == "CompressedTexture2DArray" || p_type == "CompressedCubemap" || p_type == "CompressedCubemapArray";
+}
+
+String ResourceFormatLoaderCompressedTextureLayered::get_resource_type(const String &p_path) const {
+ if (p_path.get_extension().to_lower() == "ctexarray") {
+ return "CompressedTexture2DArray";
+ }
+ if (p_path.get_extension().to_lower() == "ccube") {
+ return "CompressedCubemap";
+ }
+ if (p_path.get_extension().to_lower() == "ccubearray") {
+ return "CompressedCubemapArray";
+ }
+ return "";
+}
diff --git a/scene/resources/compressed_texture.h b/scene/resources/compressed_texture.h
new file mode 100644
index 0000000000..5297d79cfe
--- /dev/null
+++ b/scene/resources/compressed_texture.h
@@ -0,0 +1,273 @@
+/**************************************************************************/
+/* compressed_texture.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 COMPRESSED_TEXTURE_H
+#define COMPRESSED_TEXTURE_H
+
+#include "scene/resources/texture.h"
+
+class BitMap;
+
+class CompressedTexture2D : public Texture2D {
+ GDCLASS(CompressedTexture2D, Texture2D);
+
+public:
+ enum DataFormat {
+ DATA_FORMAT_IMAGE,
+ DATA_FORMAT_PNG,
+ DATA_FORMAT_WEBP,
+ DATA_FORMAT_BASIS_UNIVERSAL,
+ };
+
+ enum {
+ FORMAT_VERSION = 1
+ };
+
+ enum FormatBits {
+ FORMAT_BIT_STREAM = 1 << 22,
+ FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
+ FORMAT_BIT_DETECT_3D = 1 << 24,
+ //FORMAT_BIT_DETECT_SRGB = 1 << 25,
+ FORMAT_BIT_DETECT_NORMAL = 1 << 26,
+ FORMAT_BIT_DETECT_ROUGNESS = 1 << 27,
+ };
+
+private:
+ String path_to_file;
+ mutable RID texture;
+ Image::Format format = Image::FORMAT_L8;
+ int w = 0;
+ int h = 0;
+ mutable Ref<BitMap> alpha_cache;
+
+ Error _load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0);
+ virtual void reload_from_file() override;
+
+ static void _requested_3d(void *p_ud);
+ static void _requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel);
+ static void _requested_normal(void *p_ud);
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+public:
+ static Ref<Image> load_image_from_file(Ref<FileAccess> p_file, int p_size_limit);
+
+ typedef void (*TextureFormatRequestCallback)(const Ref<CompressedTexture2D> &);
+ typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<CompressedTexture2D> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel);
+
+ static TextureFormatRequestCallback request_3d_callback;
+ static TextureFormatRoughnessRequestCallback request_roughness_callback;
+ static TextureFormatRequestCallback request_normal_callback;
+
+ Image::Format get_format() const;
+ Error load(const String &p_path);
+ String get_load_path() const;
+
+ int get_width() const override;
+ int get_height() const override;
+ virtual RID get_rid() const override;
+
+ virtual void set_path(const String &p_path, bool p_take_over) override;
+
+ virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
+
+ virtual bool has_alpha() const override;
+ bool is_pixel_opaque(int p_x, int p_y) const override;
+
+ virtual Ref<Image> get_image() const override;
+
+ CompressedTexture2D();
+ ~CompressedTexture2D();
+};
+
+class ResourceFormatLoaderCompressedTexture2D : public ResourceFormatLoader {
+public:
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+class CompressedTextureLayered : public TextureLayered {
+ GDCLASS(CompressedTextureLayered, TextureLayered);
+
+public:
+ enum DataFormat {
+ DATA_FORMAT_IMAGE,
+ DATA_FORMAT_PNG,
+ DATA_FORMAT_WEBP,
+ DATA_FORMAT_BASIS_UNIVERSAL,
+ };
+
+ enum {
+ FORMAT_VERSION = 1
+ };
+
+ enum FormatBits {
+ FORMAT_BIT_STREAM = 1 << 22,
+ FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
+ };
+
+private:
+ Error _load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit = 0);
+ String path_to_file;
+ mutable RID texture;
+ Image::Format format = Image::FORMAT_L8;
+ int w = 0;
+ int h = 0;
+ int layers = 0;
+ bool mipmaps = false;
+ LayeredType layered_type = LayeredType::LAYERED_TYPE_2D_ARRAY;
+
+ virtual void reload_from_file() override;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+public:
+ Image::Format get_format() const override;
+ Error load(const String &p_path);
+ String get_load_path() const;
+ virtual LayeredType get_layered_type() const override;
+
+ int get_width() const override;
+ int get_height() const override;
+ int get_layers() const override;
+ virtual bool has_mipmaps() const override;
+ virtual RID get_rid() const override;
+
+ virtual void set_path(const String &p_path, bool p_take_over) override;
+
+ virtual Ref<Image> get_layer_data(int p_layer) const override;
+
+ CompressedTextureLayered(LayeredType p_layered_type);
+ ~CompressedTextureLayered();
+};
+
+class ResourceFormatLoaderCompressedTextureLayered : public ResourceFormatLoader {
+public:
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+class CompressedTexture2DArray : public CompressedTextureLayered {
+ GDCLASS(CompressedTexture2DArray, CompressedTextureLayered)
+public:
+ CompressedTexture2DArray() :
+ CompressedTextureLayered(LAYERED_TYPE_2D_ARRAY) {}
+};
+
+class CompressedCubemap : public CompressedTextureLayered {
+ GDCLASS(CompressedCubemap, CompressedTextureLayered);
+
+public:
+ CompressedCubemap() :
+ CompressedTextureLayered(LAYERED_TYPE_CUBEMAP) {}
+};
+
+class CompressedCubemapArray : public CompressedTextureLayered {
+ GDCLASS(CompressedCubemapArray, CompressedTextureLayered);
+
+public:
+ CompressedCubemapArray() :
+ CompressedTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
+};
+
+class CompressedTexture3D : public Texture3D {
+ GDCLASS(CompressedTexture3D, Texture3D);
+
+public:
+ enum DataFormat {
+ DATA_FORMAT_IMAGE,
+ DATA_FORMAT_PNG,
+ DATA_FORMAT_WEBP,
+ DATA_FORMAT_BASIS_UNIVERSAL,
+ };
+
+ enum {
+ FORMAT_VERSION = 1
+ };
+
+ enum FormatBits {
+ FORMAT_BIT_STREAM = 1 << 22,
+ FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
+ };
+
+private:
+ Error _load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps);
+ String path_to_file;
+ mutable RID texture;
+ Image::Format format = Image::FORMAT_L8;
+ int w = 0;
+ int h = 0;
+ int d = 0;
+ bool mipmaps = false;
+
+ virtual void reload_from_file() override;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+public:
+ Image::Format get_format() const override;
+ Error load(const String &p_path);
+ String get_load_path() const;
+
+ int get_width() const override;
+ int get_height() const override;
+ int get_depth() const override;
+ virtual bool has_mipmaps() const override;
+ virtual RID get_rid() const override;
+
+ virtual void set_path(const String &p_path, bool p_take_over) override;
+
+ virtual Vector<Ref<Image>> get_data() const override;
+
+ CompressedTexture3D();
+ ~CompressedTexture3D();
+};
+
+class ResourceFormatLoaderCompressedTexture3D : public ResourceFormatLoader {
+public:
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+#endif // COMPRESSED_TEXTURE_H
diff --git a/scene/resources/concave_polygon_shape_3d.cpp b/scene/resources/concave_polygon_shape_3d.cpp
index cb5e0fc600..82b125905f 100644
--- a/scene/resources/concave_polygon_shape_3d.cpp
+++ b/scene/resources/concave_polygon_shape_3d.cpp
@@ -81,7 +81,7 @@ void ConcavePolygonShape3D::_update_shape() {
void ConcavePolygonShape3D::set_faces(const Vector<Vector3> &p_faces) {
faces = p_faces;
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
Vector<Vector3> ConcavePolygonShape3D::get_faces() const {
@@ -93,7 +93,7 @@ void ConcavePolygonShape3D::set_backface_collision_enabled(bool p_enabled) {
if (!faces.is_empty()) {
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
}
diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp
index cc0ef8f583..3bfeeca461 100644
--- a/scene/resources/convex_polygon_shape_3d.cpp
+++ b/scene/resources/convex_polygon_shape_3d.cpp
@@ -71,7 +71,7 @@ void ConvexPolygonShape3D::_update_shape() {
void ConvexPolygonShape3D::set_points(const Vector<Vector3> &p_points) {
points = p_points;
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
Vector<Vector3> ConvexPolygonShape3D::get_points() const {
diff --git a/scene/resources/curve_texture.cpp b/scene/resources/curve_texture.cpp
new file mode 100644
index 0000000000..3578b46308
--- /dev/null
+++ b/scene/resources/curve_texture.cpp
@@ -0,0 +1,376 @@
+/**************************************************************************/
+/* curve_texture.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 "curve_texture.h"
+
+#include "core/core_string_names.h"
+
+void CurveTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
+
+ ClassDB::bind_method(D_METHOD("set_curve", "curve"), &CurveTexture::set_curve);
+ ClassDB::bind_method(D_METHOD("get_curve"), &CurveTexture::get_curve);
+
+ ClassDB::bind_method(D_METHOD("set_texture_mode", "texture_mode"), &CurveTexture::set_texture_mode);
+ ClassDB::bind_method(D_METHOD("get_texture_mode"), &CurveTexture::get_texture_mode);
+
+ ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
+
+ BIND_ENUM_CONSTANT(TEXTURE_MODE_RGB);
+ BIND_ENUM_CONSTANT(TEXTURE_MODE_RED);
+}
+
+void CurveTexture::set_width(int p_width) {
+ ERR_FAIL_COND(p_width < 32 || p_width > 4096);
+
+ if (_width == p_width) {
+ return;
+ }
+
+ _width = p_width;
+ _update();
+}
+
+int CurveTexture::get_width() const {
+ return _width;
+}
+
+void CurveTexture::ensure_default_setup(float p_min, float p_max) {
+ if (_curve.is_null()) {
+ Ref<Curve> curve = Ref<Curve>(memnew(Curve));
+ curve->add_point(Vector2(0, 1));
+ curve->add_point(Vector2(1, 1));
+ curve->set_min_value(p_min);
+ curve->set_max_value(p_max);
+ set_curve(curve);
+ // Min and max is 0..1 by default
+ }
+}
+
+void CurveTexture::set_curve(Ref<Curve> p_curve) {
+ if (_curve != p_curve) {
+ if (_curve.is_valid()) {
+ _curve->disconnect_changed(callable_mp(this, &CurveTexture::_update));
+ }
+ _curve = p_curve;
+ if (_curve.is_valid()) {
+ _curve->connect_changed(callable_mp(this, &CurveTexture::_update));
+ }
+ _update();
+ }
+}
+
+void CurveTexture::_update() {
+ Vector<uint8_t> data;
+ data.resize(_width * sizeof(float) * (texture_mode == TEXTURE_MODE_RGB ? 3 : 1));
+
+ // The array is locked in that scope
+ {
+ uint8_t *wd8 = data.ptrw();
+ float *wd = (float *)wd8;
+
+ if (_curve.is_valid()) {
+ Curve &curve = **_curve;
+ for (int i = 0; i < _width; ++i) {
+ float t = i / static_cast<float>(_width);
+ if (texture_mode == TEXTURE_MODE_RGB) {
+ wd[i * 3 + 0] = curve.sample_baked(t);
+ wd[i * 3 + 1] = wd[i * 3 + 0];
+ wd[i * 3 + 2] = wd[i * 3 + 0];
+ } else {
+ wd[i] = curve.sample_baked(t);
+ }
+ }
+
+ } else {
+ for (int i = 0; i < _width; ++i) {
+ if (texture_mode == TEXTURE_MODE_RGB) {
+ wd[i * 3 + 0] = 0;
+ wd[i * 3 + 1] = 0;
+ wd[i * 3 + 2] = 0;
+ } else {
+ wd[i] = 0;
+ }
+ }
+ }
+ }
+
+ Ref<Image> image = memnew(Image(_width, 1, false, texture_mode == TEXTURE_MODE_RGB ? Image::FORMAT_RGBF : Image::FORMAT_RF, data));
+
+ if (_texture.is_valid()) {
+ if (_current_texture_mode != texture_mode || _current_width != _width) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(_texture, new_texture);
+ } else {
+ RS::get_singleton()->texture_2d_update(_texture, image);
+ }
+ } else {
+ _texture = RS::get_singleton()->texture_2d_create(image);
+ }
+ _current_texture_mode = texture_mode;
+ _current_width = _width;
+
+ emit_changed();
+}
+
+Ref<Curve> CurveTexture::get_curve() const {
+ return _curve;
+}
+
+void CurveTexture::set_texture_mode(TextureMode p_mode) {
+ ERR_FAIL_COND(p_mode < TEXTURE_MODE_RGB || p_mode > TEXTURE_MODE_RED);
+ if (texture_mode == p_mode) {
+ return;
+ }
+ texture_mode = p_mode;
+ _update();
+}
+CurveTexture::TextureMode CurveTexture::get_texture_mode() const {
+ return texture_mode;
+}
+
+RID CurveTexture::get_rid() const {
+ if (!_texture.is_valid()) {
+ _texture = RS::get_singleton()->texture_2d_placeholder_create();
+ }
+ return _texture;
+}
+
+CurveTexture::CurveTexture() {}
+
+CurveTexture::~CurveTexture() {
+ if (_texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(_texture);
+ }
+}
+
+//////////////////
+
+void CurveXYZTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveXYZTexture::set_width);
+
+ ClassDB::bind_method(D_METHOD("set_curve_x", "curve"), &CurveXYZTexture::set_curve_x);
+ ClassDB::bind_method(D_METHOD("get_curve_x"), &CurveXYZTexture::get_curve_x);
+
+ ClassDB::bind_method(D_METHOD("set_curve_y", "curve"), &CurveXYZTexture::set_curve_y);
+ ClassDB::bind_method(D_METHOD("get_curve_y"), &CurveXYZTexture::get_curve_y);
+
+ ClassDB::bind_method(D_METHOD("set_curve_z", "curve"), &CurveXYZTexture::set_curve_z);
+ ClassDB::bind_method(D_METHOD("get_curve_z"), &CurveXYZTexture::get_curve_z);
+
+ ClassDB::bind_method(D_METHOD("_update"), &CurveXYZTexture::_update);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_z", "get_curve_z");
+}
+
+void CurveXYZTexture::set_width(int p_width) {
+ ERR_FAIL_COND(p_width < 32 || p_width > 4096);
+
+ if (_width == p_width) {
+ return;
+ }
+
+ _width = p_width;
+ _update();
+}
+
+int CurveXYZTexture::get_width() const {
+ return _width;
+}
+
+void CurveXYZTexture::ensure_default_setup(float p_min, float p_max) {
+ if (_curve_x.is_null()) {
+ Ref<Curve> curve = Ref<Curve>(memnew(Curve));
+ curve->add_point(Vector2(0, 1));
+ curve->add_point(Vector2(1, 1));
+ curve->set_min_value(p_min);
+ curve->set_max_value(p_max);
+ set_curve_x(curve);
+ }
+
+ if (_curve_y.is_null()) {
+ Ref<Curve> curve = Ref<Curve>(memnew(Curve));
+ curve->add_point(Vector2(0, 1));
+ curve->add_point(Vector2(1, 1));
+ curve->set_min_value(p_min);
+ curve->set_max_value(p_max);
+ set_curve_y(curve);
+ }
+
+ if (_curve_z.is_null()) {
+ Ref<Curve> curve = Ref<Curve>(memnew(Curve));
+ curve->add_point(Vector2(0, 1));
+ curve->add_point(Vector2(1, 1));
+ curve->set_min_value(p_min);
+ curve->set_max_value(p_max);
+ set_curve_z(curve);
+ }
+}
+
+void CurveXYZTexture::set_curve_x(Ref<Curve> p_curve) {
+ if (_curve_x != p_curve) {
+ if (_curve_x.is_valid()) {
+ _curve_x->disconnect_changed(callable_mp(this, &CurveXYZTexture::_update));
+ }
+ _curve_x = p_curve;
+ if (_curve_x.is_valid()) {
+ _curve_x->connect_changed(callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
+ }
+ _update();
+ }
+}
+
+void CurveXYZTexture::set_curve_y(Ref<Curve> p_curve) {
+ if (_curve_y != p_curve) {
+ if (_curve_y.is_valid()) {
+ _curve_y->disconnect_changed(callable_mp(this, &CurveXYZTexture::_update));
+ }
+ _curve_y = p_curve;
+ if (_curve_y.is_valid()) {
+ _curve_y->connect_changed(callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
+ }
+ _update();
+ }
+}
+
+void CurveXYZTexture::set_curve_z(Ref<Curve> p_curve) {
+ if (_curve_z != p_curve) {
+ if (_curve_z.is_valid()) {
+ _curve_z->disconnect_changed(callable_mp(this, &CurveXYZTexture::_update));
+ }
+ _curve_z = p_curve;
+ if (_curve_z.is_valid()) {
+ _curve_z->connect_changed(callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
+ }
+ _update();
+ }
+}
+
+void CurveXYZTexture::_update() {
+ Vector<uint8_t> data;
+ data.resize(_width * sizeof(float) * 3);
+
+ // The array is locked in that scope
+ {
+ uint8_t *wd8 = data.ptrw();
+ float *wd = (float *)wd8;
+
+ if (_curve_x.is_valid()) {
+ Curve &curve_x = **_curve_x;
+ for (int i = 0; i < _width; ++i) {
+ float t = i / static_cast<float>(_width);
+ wd[i * 3 + 0] = curve_x.sample_baked(t);
+ }
+
+ } else {
+ for (int i = 0; i < _width; ++i) {
+ wd[i * 3 + 0] = 0;
+ }
+ }
+
+ if (_curve_y.is_valid()) {
+ Curve &curve_y = **_curve_y;
+ for (int i = 0; i < _width; ++i) {
+ float t = i / static_cast<float>(_width);
+ wd[i * 3 + 1] = curve_y.sample_baked(t);
+ }
+
+ } else {
+ for (int i = 0; i < _width; ++i) {
+ wd[i * 3 + 1] = 0;
+ }
+ }
+
+ if (_curve_z.is_valid()) {
+ Curve &curve_z = **_curve_z;
+ for (int i = 0; i < _width; ++i) {
+ float t = i / static_cast<float>(_width);
+ wd[i * 3 + 2] = curve_z.sample_baked(t);
+ }
+
+ } else {
+ for (int i = 0; i < _width; ++i) {
+ wd[i * 3 + 2] = 0;
+ }
+ }
+ }
+
+ Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RGBF, data));
+
+ if (_texture.is_valid()) {
+ if (_current_width != _width) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(_texture, new_texture);
+ } else {
+ RS::get_singleton()->texture_2d_update(_texture, image);
+ }
+ } else {
+ _texture = RS::get_singleton()->texture_2d_create(image);
+ }
+ _current_width = _width;
+
+ emit_changed();
+}
+
+Ref<Curve> CurveXYZTexture::get_curve_x() const {
+ return _curve_x;
+}
+
+Ref<Curve> CurveXYZTexture::get_curve_y() const {
+ return _curve_y;
+}
+
+Ref<Curve> CurveXYZTexture::get_curve_z() const {
+ return _curve_z;
+}
+
+RID CurveXYZTexture::get_rid() const {
+ if (!_texture.is_valid()) {
+ _texture = RS::get_singleton()->texture_2d_placeholder_create();
+ }
+ return _texture;
+}
+
+CurveXYZTexture::CurveXYZTexture() {}
+
+CurveXYZTexture::~CurveXYZTexture() {
+ if (_texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(_texture);
+ }
+}
diff --git a/scene/resources/curve_texture.h b/scene/resources/curve_texture.h
new file mode 100644
index 0000000000..fd590aefa9
--- /dev/null
+++ b/scene/resources/curve_texture.h
@@ -0,0 +1,122 @@
+/**************************************************************************/
+/* curve_texture.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 CURVE_TEXTURE_H
+#define CURVE_TEXTURE_H
+
+#include "scene/resources/texture.h"
+
+class CurveTexture : public Texture2D {
+ GDCLASS(CurveTexture, Texture2D);
+ RES_BASE_EXTENSION("curvetex")
+public:
+ enum TextureMode {
+ TEXTURE_MODE_RGB,
+ TEXTURE_MODE_RED,
+ };
+
+private:
+ mutable RID _texture;
+ Ref<Curve> _curve;
+ int _width = 256;
+ int _current_width = 0;
+ TextureMode texture_mode = TEXTURE_MODE_RGB;
+ TextureMode _current_texture_mode = TEXTURE_MODE_RGB;
+
+ void _update();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_width(int p_width);
+ int get_width() const override;
+
+ void set_texture_mode(TextureMode p_mode);
+ TextureMode get_texture_mode() const;
+
+ void ensure_default_setup(float p_min = 0, float p_max = 1);
+
+ void set_curve(Ref<Curve> p_curve);
+ Ref<Curve> get_curve() const;
+
+ virtual RID get_rid() const override;
+
+ virtual int get_height() const override { return 1; }
+ virtual bool has_alpha() const override { return false; }
+
+ CurveTexture();
+ ~CurveTexture();
+};
+
+VARIANT_ENUM_CAST(CurveTexture::TextureMode)
+
+class CurveXYZTexture : public Texture2D {
+ GDCLASS(CurveXYZTexture, Texture2D);
+ RES_BASE_EXTENSION("curvetex")
+
+private:
+ mutable RID _texture;
+ Ref<Curve> _curve_x;
+ Ref<Curve> _curve_y;
+ Ref<Curve> _curve_z;
+ int _width = 256;
+ int _current_width = 0;
+
+ void _update();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_width(int p_width);
+ int get_width() const override;
+
+ void ensure_default_setup(float p_min = 0, float p_max = 1);
+
+ void set_curve_x(Ref<Curve> p_curve);
+ Ref<Curve> get_curve_x() const;
+
+ void set_curve_y(Ref<Curve> p_curve);
+ Ref<Curve> get_curve_y() const;
+
+ void set_curve_z(Ref<Curve> p_curve);
+ Ref<Curve> get_curve_z() const;
+
+ virtual RID get_rid() const override;
+
+ virtual int get_height() const override { return 1; }
+ virtual bool has_alpha() const override { return false; }
+
+ CurveXYZTexture();
+ ~CurveXYZTexture();
+};
+
+#endif // CURVE_TEXTURE_H
diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp
index aee2963b2e..a91282fd33 100644
--- a/scene/resources/cylinder_shape_3d.cpp
+++ b/scene/resources/cylinder_shape_3d.cpp
@@ -76,7 +76,7 @@ void CylinderShape3D::set_radius(float p_radius) {
ERR_FAIL_COND_MSG(p_radius < 0, "CylinderShape3D radius cannot be negative.");
radius = p_radius;
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
float CylinderShape3D::get_radius() const {
@@ -87,7 +87,7 @@ void CylinderShape3D::set_height(float p_height) {
ERR_FAIL_COND_MSG(p_height < 0, "CylinderShape3D height cannot be negative.");
height = p_height;
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
float CylinderShape3D::get_height() const {
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 1bfcf8d3ac..b6a1737acb 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -34,6 +34,10 @@
#include "default_font.gen.h"
#include "default_theme_icons.gen.h"
#include "scene/resources/font.h"
+#include "scene/resources/gradient_texture.h"
+#include "scene/resources/image_texture.h"
+#include "scene/resources/style_box_flat.h"
+#include "scene/resources/style_box_line.h"
#include "scene/resources/theme.h"
#include "scene/theme/theme_db.h"
#include "servers/text_server.h"
@@ -53,24 +57,24 @@ static const int default_corner_radius = 3;
static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = default_margin, float p_margin_top = default_margin, float p_margin_right = default_margin, float p_margin_bottom = default_margin, int p_corner_radius = default_corner_radius, bool p_draw_center = true, int p_border_width = 0) {
Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
style->set_bg_color(p_color);
- style->set_content_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
+ style->set_content_margin_individual(Math::round(p_margin_left * scale), Math::round(p_margin_top * scale), Math::round(p_margin_right * scale), Math::round(p_margin_bottom * scale));
- style->set_corner_radius_all(p_corner_radius);
+ style->set_corner_radius_all(Math::round(p_corner_radius * scale));
style->set_anti_aliased(true);
// Adjust level of detail based on the corners' effective sizes.
style->set_corner_detail(MIN(Math::ceil(1.5 * p_corner_radius), 6) * scale);
style->set_draw_center(p_draw_center);
- style->set_border_width_all(p_border_width);
+ style->set_border_width_all(Math::round(p_border_width * scale));
return style;
}
static Ref<StyleBoxFlat> sb_expand(Ref<StyleBoxFlat> p_sbox, float p_left, float p_top, float p_right, float p_bottom) {
- p_sbox->set_expand_margin(SIDE_LEFT, p_left * scale);
- p_sbox->set_expand_margin(SIDE_TOP, p_top * scale);
- p_sbox->set_expand_margin(SIDE_RIGHT, p_right * scale);
- p_sbox->set_expand_margin(SIDE_BOTTOM, p_bottom * scale);
+ p_sbox->set_expand_margin(SIDE_LEFT, Math::round(p_left * scale));
+ p_sbox->set_expand_margin(SIDE_TOP, Math::round(p_top * scale));
+ p_sbox->set_expand_margin(SIDE_RIGHT, Math::round(p_right * scale));
+ p_sbox->set_expand_margin(SIDE_BOTTOM, Math::round(p_bottom * scale));
return p_sbox;
}
@@ -83,13 +87,13 @@ static Ref<ImageTexture> generate_icon(int p_index) {
// Generating upsampled icons is slower, and the benefit is hardly visible
// with integer scales.
const bool upsample = !Math::is_equal_approx(Math::round(scale), scale);
- ImageLoaderSVG img_loader;
- Error err = img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>());
+
+ Error err = ImageLoaderSVG::create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>());
ERR_FAIL_COND_V_MSG(err != OK, Ref<ImageTexture>(), "Failed generating icon, unsupported or invalid SVG data in default theme.");
#else
// If the SVG module is disabled, we can't really display the UI well, but at least we won't crash.
// 16 pixels is used as it's the most common base size for Godot icons.
- img = Image::create_empty(16 * scale, 16 * scale, false, Image::FORMAT_RGBA8);
+ img = Image::create_empty(Math::round(16 * scale), Math::round(16 * scale), false, Image::FORMAT_RGBA8);
#endif
return ImageTexture::create_from_image(img);
@@ -97,7 +101,7 @@ static Ref<ImageTexture> generate_icon(int p_index) {
static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
Ref<StyleBox> style(memnew(StyleBoxEmpty));
- style->set_content_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
+ style->set_content_margin_individual(Math::round(p_margin_left * scale), Math::round(p_margin_top * scale), Math::round(p_margin_right * scale), Math::round(p_margin_bottom * scale));
return style;
}
@@ -106,7 +110,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Default theme properties.
theme->set_default_font(default_font);
- theme->set_default_font_size(default_font_size * scale);
+ theme->set_default_font_size(Math::round(default_font_size * scale));
theme->set_default_base_scale(scale);
// Font colors
@@ -152,7 +156,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
const Ref<StyleBoxFlat> button_disabled = make_flat_stylebox(style_disabled_color);
Ref<StyleBoxFlat> focus = make_flat_stylebox(style_focus_color, default_margin, default_margin, default_margin, default_margin, default_corner_radius, false, 2);
// Make the focus outline appear to be flush with the buttons it's focusing.
- focus->set_expand_margin_all(2 * scale);
+ focus->set_expand_margin_all(Math::round(2 * scale));
theme->set_stylebox("normal", "Button", button_normal);
theme->set_stylebox("hover", "Button", button_hover);
@@ -179,7 +183,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("icon_focus_color", "Button", Color(1, 1, 1, 1));
theme->set_color("icon_disabled_color", "Button", Color(1, 1, 1, 0.4));
- theme->set_constant("h_separation", "Button", 2 * scale);
+ theme->set_constant("h_separation", "Button", Math::round(2 * scale));
theme->set_constant("icon_max_width", "Button", 0);
// MenuBar
@@ -201,7 +205,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "MenuBar", control_font_disabled_color);
theme->set_color("font_outline_color", "MenuBar", Color(1, 1, 1));
- theme->set_constant("h_separation", "MenuBar", 4 * scale);
+ theme->set_constant("h_separation", "MenuBar", Math::round(4 * scale));
// LinkButton
@@ -217,7 +221,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "LinkButton", Color(1, 1, 1));
theme->set_constant("outline_size", "LinkButton", 0);
- theme->set_constant("underline_spacing", "LinkButton", 2 * scale);
+ theme->set_constant("underline_spacing", "LinkButton", Math::round(2 * scale));
// OptionButton
theme->set_stylebox("focus", "OptionButton", focus);
@@ -255,8 +259,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "OptionButton", control_font_disabled_color);
theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1));
- theme->set_constant("h_separation", "OptionButton", 2 * scale);
- theme->set_constant("arrow_margin", "OptionButton", 4 * scale);
+ theme->set_constant("h_separation", "OptionButton", Math::round(2 * scale));
+ theme->set_constant("arrow_margin", "OptionButton", Math::round(4 * scale));
theme->set_constant("outline_size", "OptionButton", 0);
theme->set_constant("modulate_arrow", "OptionButton", false);
@@ -278,15 +282,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "MenuButton", Color(1, 1, 1, 0.3));
theme->set_color("font_outline_color", "MenuButton", Color(1, 1, 1));
- theme->set_constant("h_separation", "MenuButton", 3 * scale);
+ theme->set_constant("h_separation", "MenuButton", Math::round(3 * scale));
theme->set_constant("outline_size", "MenuButton", 0);
// CheckBox
Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty);
- cbx_empty->set_content_margin_all(4 * scale);
+ cbx_empty->set_content_margin_all(Math::round(4 * scale));
Ref<StyleBox> cbx_focus = focus;
- cbx_focus->set_content_margin_all(4 * scale);
+ cbx_focus->set_content_margin_all(Math::round(4 * scale));
theme->set_stylebox("normal", "CheckBox", cbx_empty);
theme->set_stylebox("pressed", "CheckBox", cbx_empty);
@@ -315,14 +319,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "CheckBox", control_font_disabled_color);
theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1));
- theme->set_constant("h_separation", "CheckBox", 4 * scale);
+ theme->set_constant("h_separation", "CheckBox", Math::round(4 * scale));
theme->set_constant("check_v_offset", "CheckBox", 0);
theme->set_constant("outline_size", "CheckBox", 0);
// CheckButton
Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty);
- cb_empty->set_content_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale);
+ cb_empty->set_content_margin_individual(Math::round(6 * scale), Math::round(4 * scale), Math::round(6 * scale), Math::round(4 * scale));
theme->set_stylebox("normal", "CheckButton", cb_empty);
theme->set_stylebox("pressed", "CheckButton", cb_empty);
@@ -352,7 +356,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "CheckButton", control_font_disabled_color);
theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1));
- theme->set_constant("h_separation", "CheckButton", 4 * scale);
+ theme->set_constant("h_separation", "CheckButton", Math::round(4 * scale));
theme->set_constant("check_v_offset", "CheckButton", 0);
theme->set_constant("outline_size", "CheckButton", 0);
@@ -366,11 +370,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_shadow_color", "Label", Color(0, 0, 0, 0));
theme->set_color("font_outline_color", "Label", Color(1, 1, 1));
- theme->set_constant("shadow_offset_x", "Label", 1 * scale);
- theme->set_constant("shadow_offset_y", "Label", 1 * scale);
+ theme->set_constant("shadow_offset_x", "Label", Math::round(1 * scale));
+ theme->set_constant("shadow_offset_y", "Label", Math::round(1 * scale));
theme->set_constant("outline_size", "Label", 0);
- theme->set_constant("shadow_outline_size", "Label", 1 * scale);
- theme->set_constant("line_spacing", "Label", 3 * scale);
+ theme->set_constant("shadow_outline_size", "Label", Math::round(1 * scale));
+ theme->set_constant("line_spacing", "Label", Math::round(3 * scale));
theme->set_type_variation("HeaderSmall", "Label");
theme->set_font_size("font_size", "HeaderSmall", default_font_size + 4);
@@ -456,7 +460,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("search_result_color", "TextEdit", Color(0.3, 0.3, 0.3));
theme->set_color("search_result_border_color", "TextEdit", Color(0.3, 0.3, 0.3, 0.4));
- theme->set_constant("line_spacing", "TextEdit", 4 * scale);
+ theme->set_constant("line_spacing", "TextEdit", Math::round(4 * scale));
theme->set_constant("outline_size", "TextEdit", 0);
theme->set_constant("caret_width", "TextEdit", 1);
@@ -509,7 +513,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("completion_lines", "CodeEdit", 7);
theme->set_constant("completion_max_width", "CodeEdit", 50);
theme->set_constant("completion_scroll_width", "CodeEdit", 6);
- theme->set_constant("line_spacing", "CodeEdit", 4 * scale);
+ theme->set_constant("line_spacing", "CodeEdit", Math::round(4 * scale));
theme->set_constant("outline_size", "CodeEdit", 0);
Ref<Texture2D> empty_icon = memnew(ImageTexture);
@@ -595,6 +599,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Window
theme->set_stylebox("embedded_border", "Window", sb_expand(make_flat_stylebox(style_popup_color, 10, 28, 10, 8), 8, 32, 8, 6));
+ theme->set_stylebox("embedded_unfocused_border", "Window", sb_expand(make_flat_stylebox(style_popup_hover_color, 10, 28, 10, 8), 8, 32, 8, 6));
theme->set_font("title_font", "Window", Ref<Font>());
theme->set_font_size("title_font_size", "Window", -1);
@@ -602,7 +607,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("title_outline_modulate", "Window", Color(1, 1, 1));
theme->set_constant("title_outline_size", "Window", 0);
theme->set_constant("title_height", "Window", 36 * scale);
- theme->set_constant("resize_margin", "Window", 4 * scale);
+ theme->set_constant("resize_margin", "Window", Math::round(4 * scale));
theme->set_icon("close", "Window", icons["close"]);
theme->set_icon("close_pressed", "Window", icons["close_hl"]);
@@ -612,8 +617,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Dialogs
// AcceptDialog is currently the base dialog, so this defines styles for all extending nodes.
- theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 8 * scale, 8 * scale, 8 * scale, 8 * scale));
- theme->set_constant("buttons_separation", "AcceptDialog", 10 * scale);
+ theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale), Math::round(8 * scale)));
+ theme->set_constant("buttons_separation", "AcceptDialog", Math::round(10 * scale));
// File Dialog
@@ -684,13 +689,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1));
theme->set_color("font_separator_outline_color", "PopupMenu", Color(1, 1, 1));
- theme->set_constant("indent", "PopupMenu", 10 * scale);
- theme->set_constant("h_separation", "PopupMenu", 4 * scale);
- theme->set_constant("v_separation", "PopupMenu", 4 * scale);
+ theme->set_constant("indent", "PopupMenu", Math::round(10 * scale));
+ theme->set_constant("h_separation", "PopupMenu", Math::round(4 * scale));
+ theme->set_constant("v_separation", "PopupMenu", Math::round(4 * scale));
theme->set_constant("outline_size", "PopupMenu", 0);
theme->set_constant("separator_outline_size", "PopupMenu", 0);
- theme->set_constant("item_start_padding", "PopupMenu", 2 * scale);
- theme->set_constant("item_end_padding", "PopupMenu", 2 * scale);
+ theme->set_constant("item_start_padding", "PopupMenu", Math::round(2 * scale));
+ theme->set_constant("item_end_padding", "PopupMenu", Math::round(2 * scale));
theme->set_constant("icon_max_width", "PopupMenu", 0);
// GraphNode
@@ -711,8 +716,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("frame", "GraphNode", graphnode_normal);
theme->set_stylebox("selected_frame", "GraphNode", graphnode_selected);
- theme->set_stylebox("comment", "GraphNode", graphnode_comment_normal);
- theme->set_stylebox("comment_focus", "GraphNode", graphnode_comment_selected);
theme->set_stylebox("breakpoint", "GraphNode", graphnode_breakpoint);
theme->set_stylebox("position", "GraphNode", graphnode_position);
theme->set_stylebox("slot", "GraphNode", graphnode_slot);
@@ -724,11 +727,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("title_color", "GraphNode", control_font_color);
theme->set_color("close_color", "GraphNode", control_font_color);
theme->set_color("resizer_color", "GraphNode", control_font_color);
- theme->set_constant("separation", "GraphNode", 2 * scale);
- theme->set_constant("title_offset", "GraphNode", 26 * scale);
+ theme->set_constant("separation", "GraphNode", Math::round(2 * scale));
+ theme->set_constant("title_offset", "GraphNode", Math::round(26 * scale));
theme->set_constant("title_h_offset", "GraphNode", 0);
- theme->set_constant("close_offset", "GraphNode", 22 * scale);
- theme->set_constant("close_h_offset", "GraphNode", 12 * scale);
+ theme->set_constant("close_offset", "GraphNode", Math::round(22 * scale));
+ theme->set_constant("close_h_offset", "GraphNode", Math::round(12 * scale));
theme->set_constant("port_offset", "GraphNode", 0);
// Tree
@@ -771,10 +774,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("children_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("custom_button_font_highlight", "Tree", control_font_hover_color);
- theme->set_constant("h_separation", "Tree", 4 * scale);
- theme->set_constant("v_separation", "Tree", 4 * scale);
- theme->set_constant("item_margin", "Tree", 16 * scale);
- theme->set_constant("button_margin", "Tree", 4 * scale);
+ theme->set_constant("h_separation", "Tree", Math::round(4 * scale));
+ theme->set_constant("v_separation", "Tree", Math::round(4 * scale));
+ theme->set_constant("item_margin", "Tree", Math::round(16 * scale));
+ theme->set_constant("inner_item_margin_bottom", "Tree", 0);
+ theme->set_constant("inner_item_margin_left", "Tree", 0);
+ theme->set_constant("inner_item_margin_right", "Tree", 0);
+ theme->set_constant("inner_item_margin_top", "Tree", 0);
+ theme->set_constant("button_margin", "Tree", Math::round(4 * scale));
theme->set_constant("draw_relationship_lines", "Tree", 0);
theme->set_constant("relationship_line_width", "Tree", 1);
theme->set_constant("parent_hl_line_width", "Tree", 1);
@@ -789,8 +796,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("scrollbar_margin_top", "Tree", -1);
theme->set_constant("scrollbar_margin_right", "Tree", -1);
theme->set_constant("scrollbar_margin_bottom", "Tree", -1);
- theme->set_constant("scrollbar_h_separation", "Tree", 4 * scale);
- theme->set_constant("scrollbar_v_separation", "Tree", 4 * scale);
+ theme->set_constant("scrollbar_h_separation", "Tree", Math::round(4 * scale));
+ theme->set_constant("scrollbar_v_separation", "Tree", Math::round(4 * scale));
// ItemList
@@ -799,7 +806,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("h_separation", "ItemList", 4);
theme->set_constant("v_separation", "ItemList", 2);
theme->set_constant("icon_margin", "ItemList", 4);
- theme->set_constant("line_separation", "ItemList", 2 * scale);
+ theme->set_constant("line_separation", "ItemList", Math::round(2 * scale));
theme->set_font("font", "ItemList", Ref<Font>());
theme->set_font_size("font_size", "ItemList", -1);
@@ -857,8 +864,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "TabContainer", Color(1, 1, 1));
theme->set_color("drop_mark_color", "TabContainer", Color(1, 1, 1));
- theme->set_constant("side_margin", "TabContainer", 8 * scale);
- theme->set_constant("icon_separation", "TabContainer", 4 * scale);
+ theme->set_constant("side_margin", "TabContainer", Math::round(8 * scale));
+ theme->set_constant("icon_separation", "TabContainer", Math::round(4 * scale));
theme->set_constant("icon_max_width", "TabContainer", 0);
theme->set_constant("outline_size", "TabContainer", 0);
@@ -888,7 +895,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "TabBar", Color(1, 1, 1));
theme->set_color("drop_mark_color", "TabBar", Color(1, 1, 1));
- theme->set_constant("h_separation", "TabBar", 4 * scale);
+ theme->set_constant("h_separation", "TabBar", Math::round(4 * scale));
theme->set_constant("icon_max_width", "TabBar", 0);
theme->set_constant("outline_size", "TabBar", 0);
@@ -901,16 +908,16 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font("normal", "Fonts", Ref<Font>());
theme->set_font("large", "Fonts", Ref<Font>());
- theme->set_constant("separation", "HSeparator", 4 * scale);
- theme->set_constant("separation", "VSeparator", 4 * scale);
+ theme->set_constant("separation", "HSeparator", Math::round(4 * scale));
+ theme->set_constant("separation", "VSeparator", Math::round(4 * scale));
// ColorPicker
- theme->set_constant("margin", "ColorPicker", 4 * scale);
- theme->set_constant("sv_width", "ColorPicker", 256 * scale);
- theme->set_constant("sv_height", "ColorPicker", 256 * scale);
- theme->set_constant("h_width", "ColorPicker", 30 * scale);
- theme->set_constant("label_width", "ColorPicker", 10 * scale);
+ theme->set_constant("margin", "ColorPicker", Math::round(4 * scale));
+ theme->set_constant("sv_width", "ColorPicker", Math::round(256 * scale));
+ theme->set_constant("sv_height", "ColorPicker", Math::round(256 * scale));
+ theme->set_constant("h_width", "ColorPicker", Math::round(30 * scale));
+ theme->set_constant("label_width", "ColorPicker", Math::round(10 * scale));
theme->set_constant("center_slider_grabbers", "ColorPicker", 1);
theme->set_icon("folded_arrow", "ColorPicker", icons["arrow_right"]);
@@ -998,14 +1005,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3));
theme->set_color("font_outline_color", "ColorPickerButton", Color(1, 1, 1));
- theme->set_constant("h_separation", "ColorPickerButton", 2 * scale);
+ theme->set_constant("h_separation", "ColorPickerButton", Math::round(2 * scale));
theme->set_constant("outline_size", "ColorPickerButton", 0);
// ColorPresetButton
Ref<StyleBoxFlat> preset_sb = make_flat_stylebox(Color(1, 1, 1), 2, 2, 2, 2);
- preset_sb->set_corner_radius_all(2);
- preset_sb->set_corner_detail(2);
+ preset_sb->set_corner_radius_all(Math::round(2 * scale));
+ preset_sb->set_corner_detail(Math::round(2 * scale));
preset_sb->set_anti_aliased(false);
theme->set_stylebox("preset_fg", "ColorPresetButton", preset_sb);
@@ -1052,13 +1059,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "RichTextLabel", Color(1, 1, 1));
- theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * scale);
- theme->set_constant("shadow_offset_y", "RichTextLabel", 1 * scale);
- theme->set_constant("shadow_outline_size", "RichTextLabel", 1 * scale);
+ theme->set_constant("shadow_offset_x", "RichTextLabel", Math::round(1 * scale));
+ theme->set_constant("shadow_offset_y", "RichTextLabel", Math::round(1 * scale));
+ theme->set_constant("shadow_outline_size", "RichTextLabel", Math::round(1 * scale));
theme->set_constant("line_separation", "RichTextLabel", 0);
- theme->set_constant("table_h_separation", "RichTextLabel", 3 * scale);
- theme->set_constant("table_v_separation", "RichTextLabel", 3 * scale);
+ theme->set_constant("table_h_separation", "RichTextLabel", Math::round(3 * scale));
+ theme->set_constant("table_v_separation", "RichTextLabel", Math::round(3 * scale));
theme->set_constant("outline_size", "RichTextLabel", 0);
@@ -1066,8 +1073,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0));
- theme->set_constant("text_highlight_h_padding", "RichTextLabel", 3 * scale);
- theme->set_constant("text_highlight_v_padding", "RichTextLabel", 3 * scale);
+ theme->set_constant("text_highlight_h_padding", "RichTextLabel", Math::round(3 * scale));
+ theme->set_constant("text_highlight_v_padding", "RichTextLabel", Math::round(3 * scale));
// Containers
@@ -1076,40 +1083,43 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("grabber", "VSplitContainer", icons["vsplitter"]);
theme->set_icon("grabber", "HSplitContainer", icons["hsplitter"]);
- theme->set_constant("separation", "BoxContainer", 4 * scale);
- theme->set_constant("separation", "HBoxContainer", 4 * scale);
- theme->set_constant("separation", "VBoxContainer", 4 * scale);
+ theme->set_constant("separation", "BoxContainer", Math::round(4 * scale));
+ theme->set_constant("separation", "HBoxContainer", Math::round(4 * scale));
+ theme->set_constant("separation", "VBoxContainer", Math::round(4 * scale));
theme->set_constant("margin_left", "MarginContainer", 0);
theme->set_constant("margin_top", "MarginContainer", 0);
theme->set_constant("margin_right", "MarginContainer", 0);
theme->set_constant("margin_bottom", "MarginContainer", 0);
- theme->set_constant("h_separation", "GridContainer", 4 * scale);
- theme->set_constant("v_separation", "GridContainer", 4 * scale);
- theme->set_constant("separation", "SplitContainer", 12 * scale);
- theme->set_constant("separation", "HSplitContainer", 12 * scale);
- theme->set_constant("separation", "VSplitContainer", 12 * scale);
- theme->set_constant("minimum_grab_thickness", "SplitContainer", 6 * scale);
- theme->set_constant("minimum_grab_thickness", "HSplitContainer", 6 * scale);
- theme->set_constant("minimum_grab_thickness", "VSplitContainer", 6 * scale);
+ theme->set_constant("h_separation", "GridContainer", Math::round(4 * scale));
+ theme->set_constant("v_separation", "GridContainer", Math::round(4 * scale));
+ theme->set_constant("separation", "SplitContainer", Math::round(12 * scale));
+ theme->set_constant("separation", "HSplitContainer", Math::round(12 * scale));
+ theme->set_constant("separation", "VSplitContainer", Math::round(12 * scale));
+ theme->set_constant("minimum_grab_thickness", "SplitContainer", Math::round(6 * scale));
+ theme->set_constant("minimum_grab_thickness", "HSplitContainer", Math::round(6 * scale));
+ theme->set_constant("minimum_grab_thickness", "VSplitContainer", Math::round(6 * scale));
theme->set_constant("autohide", "SplitContainer", 1);
theme->set_constant("autohide", "HSplitContainer", 1);
theme->set_constant("autohide", "VSplitContainer", 1);
- theme->set_constant("h_separation", "FlowContainer", 4 * scale);
- theme->set_constant("v_separation", "FlowContainer", 4 * scale);
- theme->set_constant("h_separation", "HFlowContainer", 4 * scale);
- theme->set_constant("v_separation", "HFlowContainer", 4 * scale);
- theme->set_constant("h_separation", "VFlowContainer", 4 * scale);
- theme->set_constant("v_separation", "VFlowContainer", 4 * scale);
+ theme->set_constant("h_separation", "FlowContainer", Math::round(4 * scale));
+ theme->set_constant("v_separation", "FlowContainer", Math::round(4 * scale));
+ theme->set_constant("h_separation", "HFlowContainer", Math::round(4 * scale));
+ theme->set_constant("v_separation", "HFlowContainer", Math::round(4 * scale));
+ theme->set_constant("h_separation", "VFlowContainer", Math::round(4 * scale));
+ theme->set_constant("v_separation", "VFlowContainer", Math::round(4 * scale));
theme->set_stylebox("panel", "PanelContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
- theme->set_icon("minus", "GraphEdit", icons["zoom_less"]);
- theme->set_icon("reset", "GraphEdit", icons["zoom_reset"]);
- theme->set_icon("more", "GraphEdit", icons["zoom_more"]);
- theme->set_icon("snap", "GraphEdit", icons["grid_snap"]);
- theme->set_icon("minimap", "GraphEdit", icons["grid_minimap"]);
+ theme->set_icon("zoom_out", "GraphEdit", icons["zoom_less"]);
+ theme->set_icon("zoom_in", "GraphEdit", icons["zoom_more"]);
+ theme->set_icon("zoom_reset", "GraphEdit", icons["zoom_reset"]);
+ theme->set_icon("grid_toggle", "GraphEdit", icons["grid_toggle"]);
+ theme->set_icon("minimap_toggle", "GraphEdit", icons["grid_minimap"]);
+ theme->set_icon("snapping_toggle", "GraphEdit", icons["grid_snap"]);
theme->set_icon("layout", "GraphEdit", icons["grid_layout"]);
- theme->set_stylebox("bg", "GraphEdit", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
+
+ theme->set_stylebox("panel", "GraphEdit", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
+
theme->set_color("grid_minor", "GraphEdit", Color(1, 1, 1, 0.05));
theme->set_color("grid_major", "GraphEdit", Color(1, 1, 1, 0.2));
theme->set_color("selection_fill", "GraphEdit", Color(1, 1, 1, 0.3));
@@ -1121,7 +1131,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("port_hotzone_inner_extent", "GraphEdit", 22 * scale);
theme->set_constant("port_hotzone_outer_extent", "GraphEdit", 26 * scale);
- theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0));
+ theme->set_stylebox("panel", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0));
Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0, 0);
style_minimap_camera->set_border_color(Color(0.65, 0.65, 0.65, 0.45));
style_minimap_camera->set_border_width_all(1);
diff --git a/scene/resources/default_theme/grid_toggle.svg b/scene/resources/default_theme/grid_toggle.svg
new file mode 100644
index 0000000000..b0721db518
--- /dev/null
+++ b/scene/resources/default_theme/grid_toggle.svg
@@ -0,0 +1 @@
+<svg viewBox="0 0 16 16" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 0v3H0v2h3v4H0v2h3v3h2V5h9V3h-3V0H9v3H5V0z" fill="#b2b2b2" fill-opacity=".65"/><path d="M11 6.62c-1.747 0-3.957 1.344-4.752 3.936a.683.69 0 00-.004.394C7.012 13.665 9.292 14.9 11 14.9c1.708 0 3.988-1.235 4.756-3.95a.683.69 0 000-.382C15.004 7.955 12.746 6.62 11 6.62zM11 8a2.733 2.76 0 012.733 2.76A2.733 2.76 0 0111 13.52a2.733 2.76 0 01-2.733-2.76A2.733 2.76 0 0111 8zm0 1.38a1.367 1.38 0 00-1.367 1.38A1.367 1.38 0 0011 12.14a1.367 1.38 0 001.367-1.38A1.367 1.38 0 0011 9.38z" fill="#e0e0e0" /></svg>
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 757be51017..e48f744c72 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -31,9 +31,8 @@
#include "environment.h"
#include "core/config/project_settings.h"
-#include "core/core_string_names.h"
+#include "scene/resources/gradient_texture.h"
#include "servers/rendering_server.h"
-#include "texture.h"
RID Environment::get_rid() const {
return environment;
@@ -1004,9 +1003,7 @@ void Environment::set_adjustment_color_correction(Ref<Texture> p_color_correctio
adjustment_color_correction = p_color_correction;
Ref<GradientTexture1D> grad_tex = p_color_correction;
if (grad_tex.is_valid()) {
- if (!grad_tex->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &Environment::_update_adjustment))) {
- grad_tex->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Environment::_update_adjustment));
- }
+ grad_tex->connect_changed(callable_mp(this, &Environment::_update_adjustment));
}
Ref<Texture2D> adjustment_texture_2d = adjustment_color_correction;
if (adjustment_texture_2d.is_valid()) {
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 0047f443d0..09a835db1b 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -30,12 +30,12 @@
#include "font.h"
-#include "core/core_string_names.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/string/translation.h"
#include "core/templates/hash_map.h"
#include "core/templates/hashfuncs.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
#include "scene/resources/theme.h"
@@ -159,14 +159,14 @@ void Font::set_fallbacks(const TypedArray<Font> &p_fallbacks) {
for (int i = 0; i < fallbacks.size(); i++) {
Ref<Font> f = fallbacks[i];
if (f.is_valid()) {
- f->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Font::_invalidate_rids));
+ f->disconnect_changed(callable_mp(this, &Font::_invalidate_rids));
}
}
fallbacks = p_fallbacks;
for (int i = 0; i < fallbacks.size(); i++) {
Ref<Font> f = fallbacks[i];
if (f.is_valid()) {
- f->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ f->connect_changed(callable_mp(this, &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
}
_invalidate_rids();
@@ -1266,9 +1266,9 @@ void FontFile::_get_property_list(List<PropertyInfo> *p_list) const {
String prefix = "cache/" + itos(i) + "/";
TypedArray<Vector2i> sizes = get_size_cache_list(i);
p_list->push_back(PropertyInfo(Variant::DICTIONARY, prefix + "variation_coordinates", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::INT, "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::INT, prefix + "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + "embolden", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM2D, prefix + "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
for (int j = 0; j < sizes.size(); j++) {
Vector2i sz = sizes[j];
@@ -2674,12 +2674,12 @@ void FontVariation::_update_rids() const {
void FontVariation::reset_state() {
if (base_font.is_valid()) {
- base_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ base_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
base_font.unref();
}
if (theme_font.is_valid()) {
- theme_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ theme_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
theme_font.unref();
}
@@ -2696,11 +2696,11 @@ void FontVariation::reset_state() {
void FontVariation::set_base_font(const Ref<Font> &p_font) {
if (base_font != p_font) {
if (base_font.is_valid()) {
- base_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ base_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
}
base_font = p_font;
if (base_font.is_valid()) {
- base_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ base_font->connect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
_invalidate_rids();
notify_property_list_changed();
@@ -2713,7 +2713,7 @@ Ref<Font> FontVariation::get_base_font() const {
Ref<Font> FontVariation::_get_base_font_or_default() const {
if (theme_font.is_valid()) {
- theme_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids));
+ theme_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids));
theme_font.unref();
}
@@ -2734,7 +2734,7 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
}
if (f.is_valid()) {
theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
return f;
}
@@ -2754,7 +2754,7 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
}
if (f.is_valid()) {
theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
return f;
}
@@ -2765,7 +2765,7 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
if (f != this) {
if (f.is_valid()) {
theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
return f;
}
@@ -2949,7 +2949,7 @@ void SystemFont::_update_rids() const {
void SystemFont::_update_base_font() {
if (base_font.is_valid()) {
- base_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ base_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
base_font.unref();
}
@@ -3030,7 +3030,7 @@ void SystemFont::_update_base_font() {
}
if (base_font.is_valid()) {
- base_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ base_font->connect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
_invalidate_rids();
@@ -3039,12 +3039,12 @@ void SystemFont::_update_base_font() {
void SystemFont::reset_state() {
if (base_font.is_valid()) {
- base_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ base_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
base_font.unref();
}
if (theme_font.is_valid()) {
- theme_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ theme_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
theme_font.unref();
}
@@ -3070,7 +3070,7 @@ void SystemFont::reset_state() {
Ref<Font> SystemFont::_get_base_font_or_default() const {
if (theme_font.is_valid()) {
- theme_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids));
+ theme_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids));
theme_font.unref();
}
@@ -3091,7 +3091,7 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
}
if (f.is_valid()) {
theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
return f;
}
@@ -3111,7 +3111,7 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
}
if (f.is_valid()) {
theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
return f;
}
@@ -3122,7 +3122,7 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
if (f != this) {
if (f.is_valid()) {
theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
}
return f;
}
diff --git a/scene/resources/gradient_texture.cpp b/scene/resources/gradient_texture.cpp
new file mode 100644
index 0000000000..20868faaa2
--- /dev/null
+++ b/scene/resources/gradient_texture.cpp
@@ -0,0 +1,438 @@
+/**************************************************************************/
+/* gradient_texture.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 "gradient_texture.h"
+
+#include "core/core_string_names.h"
+#include "core/math/geometry_2d.h"
+
+GradientTexture1D::GradientTexture1D() {
+ _queue_update();
+}
+
+GradientTexture1D::~GradientTexture1D() {
+ if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(texture);
+ }
+}
+
+void GradientTexture1D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_gradient", "gradient"), &GradientTexture1D::set_gradient);
+ ClassDB::bind_method(D_METHOD("get_gradient"), &GradientTexture1D::get_gradient);
+
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture1D::set_width);
+ // The `get_width()` method is already exposed by the parent class Texture2D.
+
+ ClassDB::bind_method(D_METHOD("set_use_hdr", "enabled"), &GradientTexture1D::set_use_hdr);
+ ClassDB::bind_method(D_METHOD("is_using_hdr"), &GradientTexture1D::is_using_hdr);
+
+ ClassDB::bind_method(D_METHOD("_update"), &GradientTexture1D::_update);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,16384,suffix:px"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
+}
+
+void GradientTexture1D::set_gradient(Ref<Gradient> p_gradient) {
+ if (p_gradient == gradient) {
+ return;
+ }
+ if (gradient.is_valid()) {
+ gradient->disconnect_changed(callable_mp(this, &GradientTexture1D::_update));
+ }
+ gradient = p_gradient;
+ if (gradient.is_valid()) {
+ gradient->connect_changed(callable_mp(this, &GradientTexture1D::_update));
+ }
+ _update();
+ emit_changed();
+}
+
+Ref<Gradient> GradientTexture1D::get_gradient() const {
+ return gradient;
+}
+
+void GradientTexture1D::_queue_update() {
+ if (update_pending) {
+ return;
+ }
+
+ update_pending = true;
+ call_deferred(SNAME("_update"));
+}
+
+void GradientTexture1D::_update() {
+ update_pending = false;
+
+ if (gradient.is_null()) {
+ return;
+ }
+
+ if (use_hdr) {
+ // High dynamic range.
+ Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBAF));
+ Gradient &g = **gradient;
+ // `create()` isn't available for non-uint8_t data, so fill in the data manually.
+ for (int i = 0; i < width; i++) {
+ float ofs = float(i) / (width - 1);
+ image->set_pixel(i, 0, g.get_color_at_offset(ofs));
+ }
+
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_2d_create(image);
+ }
+ } else {
+ // Low dynamic range. "Overbright" colors will be clamped.
+ Vector<uint8_t> data;
+ data.resize(width * 4);
+ {
+ uint8_t *wd8 = data.ptrw();
+ Gradient &g = **gradient;
+
+ for (int i = 0; i < width; i++) {
+ float ofs = float(i) / (width - 1);
+ Color color = g.get_color_at_offset(ofs);
+
+ wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255));
+ wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255));
+ wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255));
+ wd8[i * 4 + 3] = uint8_t(CLAMP(color.a * 255.0, 0, 255));
+ }
+ }
+
+ Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
+
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_2d_create(image);
+ }
+ }
+
+ emit_changed();
+}
+
+void GradientTexture1D::set_width(int p_width) {
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
+ width = p_width;
+ _queue_update();
+}
+
+int GradientTexture1D::get_width() const {
+ return width;
+}
+
+void GradientTexture1D::set_use_hdr(bool p_enabled) {
+ if (p_enabled == use_hdr) {
+ return;
+ }
+
+ use_hdr = p_enabled;
+ _queue_update();
+}
+
+bool GradientTexture1D::is_using_hdr() const {
+ return use_hdr;
+}
+
+Ref<Image> GradientTexture1D::get_image() const {
+ if (!texture.is_valid()) {
+ return Ref<Image>();
+ }
+ return RenderingServer::get_singleton()->texture_2d_get(texture);
+}
+
+//////////////////
+
+GradientTexture2D::GradientTexture2D() {
+ _queue_update();
+}
+
+GradientTexture2D::~GradientTexture2D() {
+ if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(texture);
+ }
+}
+
+void GradientTexture2D::set_gradient(Ref<Gradient> p_gradient) {
+ if (gradient == p_gradient) {
+ return;
+ }
+ if (gradient.is_valid()) {
+ gradient->disconnect_changed(callable_mp(this, &GradientTexture2D::_queue_update));
+ }
+ gradient = p_gradient;
+ if (gradient.is_valid()) {
+ gradient->connect_changed(callable_mp(this, &GradientTexture2D::_queue_update));
+ }
+ _update();
+ emit_changed();
+}
+
+Ref<Gradient> GradientTexture2D::get_gradient() const {
+ return gradient;
+}
+
+void GradientTexture2D::_queue_update() {
+ if (update_pending) {
+ return;
+ }
+ update_pending = true;
+ call_deferred(SNAME("_update"));
+}
+
+void GradientTexture2D::_update() {
+ update_pending = false;
+
+ if (gradient.is_null()) {
+ return;
+ }
+ Ref<Image> image;
+ image.instantiate();
+
+ if (gradient->get_point_count() <= 1) { // No need to interpolate.
+ image->initialize_data(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8);
+ image->fill((gradient->get_point_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1));
+ } else {
+ if (use_hdr) {
+ image->initialize_data(width, height, false, Image::FORMAT_RGBAF);
+ Gradient &g = **gradient;
+ // `create()` isn't available for non-uint8_t data, so fill in the data manually.
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ float ofs = _get_gradient_offset_at(x, y);
+ image->set_pixel(x, y, g.get_color_at_offset(ofs));
+ }
+ }
+ } else {
+ Vector<uint8_t> data;
+ data.resize(width * height * 4);
+ {
+ uint8_t *wd8 = data.ptrw();
+ Gradient &g = **gradient;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ float ofs = _get_gradient_offset_at(x, y);
+ const Color &c = g.get_color_at_offset(ofs);
+
+ wd8[(x + (y * width)) * 4 + 0] = uint8_t(CLAMP(c.r * 255.0, 0, 255));
+ wd8[(x + (y * width)) * 4 + 1] = uint8_t(CLAMP(c.g * 255.0, 0, 255));
+ wd8[(x + (y * width)) * 4 + 2] = uint8_t(CLAMP(c.b * 255.0, 0, 255));
+ wd8[(x + (y * width)) * 4 + 3] = uint8_t(CLAMP(c.a * 255.0, 0, 255));
+ }
+ }
+ }
+ image->set_data(width, height, false, Image::FORMAT_RGBA8, data);
+ }
+ }
+
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_2d_create(image);
+ }
+ emit_changed();
+}
+
+float GradientTexture2D::_get_gradient_offset_at(int x, int y) const {
+ if (fill_to == fill_from) {
+ return 0;
+ }
+ float ofs = 0;
+ Vector2 pos;
+ if (width > 1) {
+ pos.x = static_cast<float>(x) / (width - 1);
+ }
+ if (height > 1) {
+ pos.y = static_cast<float>(y) / (height - 1);
+ }
+ if (fill == Fill::FILL_LINEAR) {
+ Vector2 segment[2];
+ segment[0] = fill_from;
+ segment[1] = fill_to;
+ Vector2 closest = Geometry2D::get_closest_point_to_segment_uncapped(pos, &segment[0]);
+ ofs = (closest - fill_from).length() / (fill_to - fill_from).length();
+ if ((closest - fill_from).dot(fill_to - fill_from) < 0) {
+ ofs *= -1;
+ }
+ } else if (fill == Fill::FILL_RADIAL) {
+ ofs = (pos - fill_from).length() / (fill_to - fill_from).length();
+ } else if (fill == Fill::FILL_SQUARE) {
+ ofs = MAX(Math::abs(pos.x - fill_from.x), Math::abs(pos.y - fill_from.y)) / MAX(Math::abs(fill_to.x - fill_from.x), Math::abs(fill_to.y - fill_from.y));
+ }
+ if (repeat == Repeat::REPEAT_NONE) {
+ ofs = CLAMP(ofs, 0.0, 1.0);
+ } else if (repeat == Repeat::REPEAT) {
+ ofs = Math::fmod(ofs, 1.0f);
+ if (ofs < 0) {
+ ofs = 1 + ofs;
+ }
+ } else if (repeat == Repeat::REPEAT_MIRROR) {
+ ofs = Math::abs(ofs);
+ ofs = Math::fmod(ofs, 2.0f);
+ if (ofs > 1.0) {
+ ofs = 2.0 - ofs;
+ }
+ }
+ return ofs;
+}
+
+void GradientTexture2D::set_width(int p_width) {
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
+ width = p_width;
+ _queue_update();
+}
+
+int GradientTexture2D::get_width() const {
+ return width;
+}
+
+void GradientTexture2D::set_height(int p_height) {
+ ERR_FAIL_COND_MSG(p_height <= 0 || p_height > 16384, "Texture dimensions have to be within 1 to 16384 range.");
+ height = p_height;
+ _queue_update();
+}
+int GradientTexture2D::get_height() const {
+ return height;
+}
+
+void GradientTexture2D::set_use_hdr(bool p_enabled) {
+ if (p_enabled == use_hdr) {
+ return;
+ }
+
+ use_hdr = p_enabled;
+ _queue_update();
+}
+
+bool GradientTexture2D::is_using_hdr() const {
+ return use_hdr;
+}
+
+void GradientTexture2D::set_fill_from(Vector2 p_fill_from) {
+ fill_from = p_fill_from;
+ _queue_update();
+}
+
+Vector2 GradientTexture2D::get_fill_from() const {
+ return fill_from;
+}
+
+void GradientTexture2D::set_fill_to(Vector2 p_fill_to) {
+ fill_to = p_fill_to;
+ _queue_update();
+}
+
+Vector2 GradientTexture2D::get_fill_to() const {
+ return fill_to;
+}
+
+void GradientTexture2D::set_fill(Fill p_fill) {
+ fill = p_fill;
+ _queue_update();
+}
+
+GradientTexture2D::Fill GradientTexture2D::get_fill() const {
+ return fill;
+}
+
+void GradientTexture2D::set_repeat(Repeat p_repeat) {
+ repeat = p_repeat;
+ _queue_update();
+}
+
+GradientTexture2D::Repeat GradientTexture2D::get_repeat() const {
+ return repeat;
+}
+
+RID GradientTexture2D::get_rid() const {
+ if (!texture.is_valid()) {
+ texture = RS::get_singleton()->texture_2d_placeholder_create();
+ }
+ return texture;
+}
+
+Ref<Image> GradientTexture2D::get_image() const {
+ if (!texture.is_valid()) {
+ return Ref<Image>();
+ }
+ return RenderingServer::get_singleton()->texture_2d_get(texture);
+}
+
+void GradientTexture2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_gradient", "gradient"), &GradientTexture2D::set_gradient);
+ ClassDB::bind_method(D_METHOD("get_gradient"), &GradientTexture2D::get_gradient);
+
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture2D::set_width);
+ ClassDB::bind_method(D_METHOD("set_height", "height"), &GradientTexture2D::set_height);
+
+ ClassDB::bind_method(D_METHOD("set_use_hdr", "enabled"), &GradientTexture2D::set_use_hdr);
+ ClassDB::bind_method(D_METHOD("is_using_hdr"), &GradientTexture2D::is_using_hdr);
+
+ ClassDB::bind_method(D_METHOD("set_fill", "fill"), &GradientTexture2D::set_fill);
+ ClassDB::bind_method(D_METHOD("get_fill"), &GradientTexture2D::get_fill);
+ ClassDB::bind_method(D_METHOD("set_fill_from", "fill_from"), &GradientTexture2D::set_fill_from);
+ ClassDB::bind_method(D_METHOD("get_fill_from"), &GradientTexture2D::get_fill_from);
+ ClassDB::bind_method(D_METHOD("set_fill_to", "fill_to"), &GradientTexture2D::set_fill_to);
+ ClassDB::bind_method(D_METHOD("get_fill_to"), &GradientTexture2D::get_fill_to);
+
+ ClassDB::bind_method(D_METHOD("set_repeat", "repeat"), &GradientTexture2D::set_repeat);
+ ClassDB::bind_method(D_METHOD("get_repeat"), &GradientTexture2D::get_repeat);
+
+ ClassDB::bind_method(D_METHOD("_update"), &GradientTexture2D::_update);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,or_greater,suffix:px"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,or_greater,suffix:px"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
+
+ ADD_GROUP("Fill", "fill_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fill", PROPERTY_HINT_ENUM, "Linear,Radial,Square"), "set_fill", "get_fill");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "fill_from"), "set_fill_from", "get_fill_from");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "fill_to"), "set_fill_to", "get_fill_to");
+
+ ADD_GROUP("Repeat", "repeat_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "repeat", PROPERTY_HINT_ENUM, "No Repeat,Repeat,Mirror Repeat"), "set_repeat", "get_repeat");
+
+ BIND_ENUM_CONSTANT(FILL_LINEAR);
+ BIND_ENUM_CONSTANT(FILL_RADIAL);
+ BIND_ENUM_CONSTANT(FILL_SQUARE);
+
+ BIND_ENUM_CONSTANT(REPEAT_NONE);
+ BIND_ENUM_CONSTANT(REPEAT);
+ BIND_ENUM_CONSTANT(REPEAT_MIRROR);
+}
diff --git a/scene/resources/gradient_texture.h b/scene/resources/gradient_texture.h
new file mode 100644
index 0000000000..b8768ce0a8
--- /dev/null
+++ b/scene/resources/gradient_texture.h
@@ -0,0 +1,144 @@
+/**************************************************************************/
+/* gradient_texture.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 GRADIENT_TEXTURE_H
+#define GRADIENT_TEXTURE_H
+
+#include "scene/resources/texture.h"
+
+class GradientTexture1D : public Texture2D {
+ GDCLASS(GradientTexture1D, Texture2D);
+
+private:
+ Ref<Gradient> gradient;
+ bool update_pending = false;
+ RID texture;
+ int width = 256;
+ bool use_hdr = false;
+
+ void _queue_update();
+ void _update();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_gradient(Ref<Gradient> p_gradient);
+ Ref<Gradient> get_gradient() const;
+
+ void set_width(int p_width);
+ int get_width() const override;
+
+ void set_use_hdr(bool p_enabled);
+ bool is_using_hdr() const;
+
+ virtual RID get_rid() const override { return texture; }
+ virtual int get_height() const override { return 1; }
+ virtual bool has_alpha() const override { return true; }
+
+ virtual Ref<Image> get_image() const override;
+
+ GradientTexture1D();
+ virtual ~GradientTexture1D();
+};
+
+class GradientTexture2D : public Texture2D {
+ GDCLASS(GradientTexture2D, Texture2D);
+
+public:
+ enum Fill {
+ FILL_LINEAR,
+ FILL_RADIAL,
+ FILL_SQUARE,
+ };
+ enum Repeat {
+ REPEAT_NONE,
+ REPEAT,
+ REPEAT_MIRROR,
+ };
+
+private:
+ Ref<Gradient> gradient;
+ mutable RID texture;
+
+ int width = 64;
+ int height = 64;
+
+ bool use_hdr = false;
+
+ Vector2 fill_from;
+ Vector2 fill_to = Vector2(1, 0);
+
+ Fill fill = FILL_LINEAR;
+ Repeat repeat = REPEAT_NONE;
+
+ float _get_gradient_offset_at(int x, int y) const;
+
+ bool update_pending = false;
+ void _queue_update();
+ void _update();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_gradient(Ref<Gradient> p_gradient);
+ Ref<Gradient> get_gradient() const;
+
+ void set_width(int p_width);
+ virtual int get_width() const override;
+ void set_height(int p_height);
+ virtual int get_height() const override;
+
+ void set_use_hdr(bool p_enabled);
+ bool is_using_hdr() const;
+
+ void set_fill(Fill p_fill);
+ Fill get_fill() const;
+ void set_fill_from(Vector2 p_fill_from);
+ Vector2 get_fill_from() const;
+ void set_fill_to(Vector2 p_fill_to);
+ Vector2 get_fill_to() const;
+
+ void set_repeat(Repeat p_repeat);
+ Repeat get_repeat() const;
+
+ virtual RID get_rid() const override;
+ virtual bool has_alpha() const override { return true; }
+ virtual Ref<Image> get_image() const override;
+
+ GradientTexture2D();
+ virtual ~GradientTexture2D();
+};
+
+VARIANT_ENUM_CAST(GradientTexture2D::Fill);
+VARIANT_ENUM_CAST(GradientTexture2D::Repeat);
+
+#endif // GRADIENT_TEXTURE_H
diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp
index 553daa93e6..718d701811 100644
--- a/scene/resources/height_map_shape_3d.cpp
+++ b/scene/resources/height_map_shape_3d.cpp
@@ -112,7 +112,7 @@ void HeightMapShape3D::set_map_width(int p_new) {
}
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
}
@@ -136,7 +136,7 @@ void HeightMapShape3D::set_map_depth(int p_new) {
}
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
}
@@ -172,7 +172,7 @@ void HeightMapShape3D::set_map_data(Vector<real_t> p_new) {
}
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
Vector<real_t> HeightMapShape3D::get_map_data() const {
diff --git a/scene/resources/image_texture.cpp b/scene/resources/image_texture.cpp
new file mode 100644
index 0000000000..ecf70d96ac
--- /dev/null
+++ b/scene/resources/image_texture.cpp
@@ -0,0 +1,514 @@
+/**************************************************************************/
+/* image_texture.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "image_texture.h"
+
+#include "core/io/image_loader.h"
+#include "scene/resources/bit_map.h"
+#include "scene/resources/placeholder_textures.h"
+
+void ImageTexture::reload_from_file() {
+ String path = ResourceLoader::path_remap(get_path());
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ Ref<Image> img;
+ img.instantiate();
+
+ if (ImageLoader::load_image(path, img) == OK) {
+ set_image(img);
+ } else {
+ Resource::reload_from_file();
+ notify_property_list_changed();
+ emit_changed();
+ }
+}
+
+bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "image") {
+ set_image(p_value);
+ return true;
+ }
+ return false;
+}
+
+bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
+ if (p_name == "image") {
+ r_ret = get_image();
+ return true;
+ }
+ return false;
+}
+
+void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("image"), PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
+}
+
+Ref<ImageTexture> ImageTexture::create_from_image(const Ref<Image> &p_image) {
+ ERR_FAIL_COND_V_MSG(p_image.is_null(), Ref<ImageTexture>(), "Invalid image: null");
+ ERR_FAIL_COND_V_MSG(p_image->is_empty(), Ref<ImageTexture>(), "Invalid image: image is empty");
+
+ Ref<ImageTexture> image_texture;
+ image_texture.instantiate();
+ image_texture->set_image(p_image);
+ return image_texture;
+}
+
+void ImageTexture::set_image(const Ref<Image> &p_image) {
+ ERR_FAIL_COND_MSG(p_image.is_null() || p_image->is_empty(), "Invalid image");
+ w = p_image->get_width();
+ h = p_image->get_height();
+ format = p_image->get_format();
+ mipmaps = p_image->has_mipmaps();
+
+ if (texture.is_null()) {
+ texture = RenderingServer::get_singleton()->texture_2d_create(p_image);
+ } else {
+ RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_image);
+ RenderingServer::get_singleton()->texture_replace(texture, new_texture);
+ }
+ notify_property_list_changed();
+ emit_changed();
+
+ image_stored = true;
+}
+
+Image::Format ImageTexture::get_format() const {
+ return format;
+}
+
+void ImageTexture::update(const Ref<Image> &p_image) {
+ ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image");
+ ERR_FAIL_COND_MSG(texture.is_null(), "Texture is not initialized.");
+ ERR_FAIL_COND_MSG(p_image->get_width() != w || p_image->get_height() != h,
+ "The new image dimensions must match the texture size.");
+ ERR_FAIL_COND_MSG(p_image->get_format() != format,
+ "The new image format must match the texture's image format.");
+ ERR_FAIL_COND_MSG(mipmaps != p_image->has_mipmaps(),
+ "The new image mipmaps configuration must match the texture's image mipmaps configuration");
+
+ RS::get_singleton()->texture_2d_update(texture, p_image);
+
+ notify_property_list_changed();
+ emit_changed();
+
+ alpha_cache.unref();
+ image_stored = true;
+}
+
+Ref<Image> ImageTexture::get_image() const {
+ if (image_stored) {
+ return RenderingServer::get_singleton()->texture_2d_get(texture);
+ } else {
+ return Ref<Image>();
+ }
+}
+
+int ImageTexture::get_width() const {
+ return w;
+}
+
+int ImageTexture::get_height() const {
+ return h;
+}
+
+RID ImageTexture::get_rid() const {
+ if (texture.is_null()) {
+ // We are in trouble, create something temporary.
+ texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
+ }
+ return texture;
+}
+
+bool ImageTexture::has_alpha() const {
+ return (format == Image::FORMAT_LA8 || format == Image::FORMAT_RGBA8);
+}
+
+void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
+ if ((w | h) == 0) {
+ return;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose);
+}
+
+void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
+ if ((w | h) == 0) {
+ return;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);
+}
+
+void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
+ if ((w | h) == 0) {
+ return;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv);
+}
+
+bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
+ if (!alpha_cache.is_valid()) {
+ Ref<Image> img = get_image();
+ if (img.is_valid()) {
+ if (img->is_compressed()) { //must decompress, if compressed
+ Ref<Image> decom = img->duplicate();
+ decom->decompress();
+ img = decom;
+ }
+ alpha_cache.instantiate();
+ alpha_cache->create_from_image_alpha(img);
+ }
+ }
+
+ if (alpha_cache.is_valid()) {
+ int aw = int(alpha_cache->get_size().width);
+ int ah = int(alpha_cache->get_size().height);
+ if (aw == 0 || ah == 0) {
+ return true;
+ }
+
+ int x = p_x * aw / w;
+ int y = p_y * ah / h;
+
+ x = CLAMP(x, 0, aw);
+ y = CLAMP(y, 0, ah);
+
+ return alpha_cache->get_bit(x, y);
+ }
+
+ return true;
+}
+
+void ImageTexture::set_size_override(const Size2i &p_size) {
+ Size2i s = p_size;
+ if (s.x != 0) {
+ w = s.x;
+ }
+ if (s.y != 0) {
+ h = s.y;
+ }
+ RenderingServer::get_singleton()->texture_set_size_override(texture, w, h);
+}
+
+void ImageTexture::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+void ImageTexture::_bind_methods() {
+ ClassDB::bind_static_method("ImageTexture", D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image);
+ ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format);
+
+ ClassDB::bind_method(D_METHOD("set_image", "image"), &ImageTexture::set_image);
+ ClassDB::bind_method(D_METHOD("update", "image"), &ImageTexture::update);
+ ClassDB::bind_method(D_METHOD("set_size_override", "size"), &ImageTexture::set_size_override);
+}
+
+ImageTexture::ImageTexture() {}
+
+ImageTexture::~ImageTexture() {
+ if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RenderingServer::get_singleton()->free(texture);
+ }
+}
+
+Image::Format ImageTextureLayered::get_format() const {
+ return format;
+}
+
+int ImageTextureLayered::get_width() const {
+ return width;
+}
+
+int ImageTextureLayered::get_height() const {
+ return height;
+}
+
+int ImageTextureLayered::get_layers() const {
+ return layers;
+}
+
+bool ImageTextureLayered::has_mipmaps() const {
+ return mipmaps;
+}
+
+ImageTextureLayered::LayeredType ImageTextureLayered::get_layered_type() const {
+ return layered_type;
+}
+
+Error ImageTextureLayered::_create_from_images(const TypedArray<Image> &p_images) {
+ Vector<Ref<Image>> images;
+ for (int i = 0; i < p_images.size(); i++) {
+ Ref<Image> img = p_images[i];
+ ERR_FAIL_COND_V(img.is_null(), ERR_INVALID_PARAMETER);
+ images.push_back(img);
+ }
+
+ return create_from_images(images);
+}
+
+TypedArray<Image> ImageTextureLayered::_get_images() const {
+ TypedArray<Image> images;
+ for (int i = 0; i < layers; i++) {
+ images.push_back(get_layer_data(i));
+ }
+ return images;
+}
+
+void ImageTextureLayered::_set_images(const TypedArray<Image> &p_images) {
+ ERR_FAIL_COND(_create_from_images(p_images) != OK);
+}
+
+Error ImageTextureLayered::create_from_images(Vector<Ref<Image>> p_images) {
+ int new_layers = p_images.size();
+ ERR_FAIL_COND_V(new_layers == 0, ERR_INVALID_PARAMETER);
+ if (layered_type == LAYERED_TYPE_CUBEMAP) {
+ ERR_FAIL_COND_V_MSG(new_layers != 6, ERR_INVALID_PARAMETER,
+ "Cubemaps require exactly 6 layers");
+ } else if (layered_type == LAYERED_TYPE_CUBEMAP_ARRAY) {
+ ERR_FAIL_COND_V_MSG((new_layers % 6) != 0, ERR_INVALID_PARAMETER,
+ "Cubemap array layers must be a multiple of 6");
+ }
+
+ ERR_FAIL_COND_V(p_images[0].is_null() || p_images[0]->is_empty(), ERR_INVALID_PARAMETER);
+
+ Image::Format new_format = p_images[0]->get_format();
+ int new_width = p_images[0]->get_width();
+ int new_height = p_images[0]->get_height();
+ bool new_mipmaps = p_images[0]->has_mipmaps();
+
+ for (int i = 1; i < p_images.size(); i++) {
+ ERR_FAIL_COND_V_MSG(p_images[i]->get_format() != new_format, ERR_INVALID_PARAMETER,
+ "All images must share the same format");
+ ERR_FAIL_COND_V_MSG(p_images[i]->get_width() != new_width || p_images[i]->get_height() != new_height, ERR_INVALID_PARAMETER,
+ "All images must share the same dimensions");
+ ERR_FAIL_COND_V_MSG(p_images[i]->has_mipmaps() != new_mipmaps, ERR_INVALID_PARAMETER,
+ "All images must share the usage of mipmaps");
+ }
+
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_2d_layered_create(p_images, RS::TextureLayeredType(layered_type));
+ ERR_FAIL_COND_V(!new_texture.is_valid(), ERR_CANT_CREATE);
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_2d_layered_create(p_images, RS::TextureLayeredType(layered_type));
+ ERR_FAIL_COND_V(!texture.is_valid(), ERR_CANT_CREATE);
+ }
+
+ format = new_format;
+ width = new_width;
+ height = new_height;
+ layers = new_layers;
+ mipmaps = new_mipmaps;
+ return OK;
+}
+
+void ImageTextureLayered::update_layer(const Ref<Image> &p_image, int p_layer) {
+ ERR_FAIL_COND_MSG(texture.is_null(), "Texture is not initialized.");
+ ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image.");
+ ERR_FAIL_COND_MSG(p_image->get_format() != format, "Image format must match texture's image format.");
+ ERR_FAIL_COND_MSG(p_image->get_width() != width || p_image->get_height() != height, "Image size must match texture's image size.");
+ ERR_FAIL_COND_MSG(p_image->has_mipmaps() != mipmaps, "Image mipmap configuration must match texture's image mipmap configuration.");
+ ERR_FAIL_INDEX_MSG(p_layer, layers, "Layer index is out of bounds.");
+ RS::get_singleton()->texture_2d_update(texture, p_image, p_layer);
+}
+
+Ref<Image> ImageTextureLayered::get_layer_data(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, layers, Ref<Image>());
+ return RS::get_singleton()->texture_2d_layer_get(texture, p_layer);
+}
+
+RID ImageTextureLayered::get_rid() const {
+ if (texture.is_null()) {
+ texture = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));
+ }
+ return texture;
+}
+
+void ImageTextureLayered::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ RS::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+void ImageTextureLayered::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("create_from_images", "images"), &ImageTextureLayered::_create_from_images);
+ ClassDB::bind_method(D_METHOD("update_layer", "image", "layer"), &ImageTextureLayered::update_layer);
+
+ ClassDB::bind_method(D_METHOD("_get_images"), &ImageTextureLayered::_get_images);
+ ClassDB::bind_method(D_METHOD("_set_images", "images"), &ImageTextureLayered::_set_images);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_ARRAY_TYPE, "Image", PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT), "_set_images", "_get_images");
+}
+
+ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) {
+ layered_type = p_layered_type;
+}
+
+ImageTextureLayered::~ImageTextureLayered() {
+ if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(texture);
+ }
+}
+
+Image::Format ImageTexture3D::get_format() const {
+ return format;
+}
+int ImageTexture3D::get_width() const {
+ return width;
+}
+int ImageTexture3D::get_height() const {
+ return height;
+}
+int ImageTexture3D::get_depth() const {
+ return depth;
+}
+bool ImageTexture3D::has_mipmaps() const {
+ return mipmaps;
+}
+
+Error ImageTexture3D::_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data) {
+ Vector<Ref<Image>> images;
+ images.resize(p_data.size());
+ for (int i = 0; i < images.size(); i++) {
+ images.write[i] = p_data[i];
+ }
+ return create(p_format, p_width, p_height, p_depth, p_mipmaps, images);
+}
+
+void ImageTexture3D::_update(const TypedArray<Image> &p_data) {
+ Vector<Ref<Image>> images;
+ images.resize(p_data.size());
+ for (int i = 0; i < images.size(); i++) {
+ images.write[i] = p_data[i];
+ }
+ return update(images);
+}
+
+Error ImageTexture3D::create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) {
+ RID tex = RenderingServer::get_singleton()->texture_3d_create(p_format, p_width, p_height, p_depth, p_mipmaps, p_data);
+ ERR_FAIL_COND_V(tex.is_null(), ERR_CANT_CREATE);
+
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_replace(texture, tex);
+ } else {
+ texture = tex;
+ }
+
+ format = p_format;
+ width = p_width;
+ height = p_height;
+ depth = p_depth;
+ mipmaps = p_mipmaps;
+
+ return OK;
+}
+
+void ImageTexture3D::update(const Vector<Ref<Image>> &p_data) {
+ ERR_FAIL_COND(!texture.is_valid());
+ RenderingServer::get_singleton()->texture_3d_update(texture, p_data);
+}
+
+Vector<Ref<Image>> ImageTexture3D::get_data() const {
+ ERR_FAIL_COND_V(!texture.is_valid(), Vector<Ref<Image>>());
+ return RS::get_singleton()->texture_3d_get(texture);
+}
+
+RID ImageTexture3D::get_rid() const {
+ if (!texture.is_valid()) {
+ texture = RS::get_singleton()->texture_3d_placeholder_create();
+ }
+ return texture;
+}
+void ImageTexture3D::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+void ImageTexture3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("create", "format", "width", "height", "depth", "use_mipmaps", "data"), &ImageTexture3D::_create);
+ ClassDB::bind_method(D_METHOD("update", "data"), &ImageTexture3D::_update);
+}
+
+ImageTexture3D::ImageTexture3D() {
+}
+
+ImageTexture3D::~ImageTexture3D() {
+ if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(texture);
+ }
+}
+
+void Texture2DArray::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("create_placeholder"), &Texture2DArray::create_placeholder);
+}
+
+Ref<Resource> Texture2DArray::create_placeholder() const {
+ Ref<PlaceholderTexture2DArray> placeholder;
+ placeholder.instantiate();
+ placeholder->set_size(Size2i(get_width(), get_height()));
+ placeholder->set_layers(get_layers());
+ return placeholder;
+}
+
+void Cubemap::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("create_placeholder"), &Cubemap::create_placeholder);
+}
+
+Ref<Resource> Cubemap::create_placeholder() const {
+ Ref<PlaceholderCubemap> placeholder;
+ placeholder.instantiate();
+ placeholder->set_size(Size2i(get_width(), get_height()));
+ placeholder->set_layers(get_layers());
+ return placeholder;
+}
+
+void CubemapArray::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("create_placeholder"), &CubemapArray::create_placeholder);
+}
+
+Ref<Resource> CubemapArray::create_placeholder() const {
+ Ref<PlaceholderCubemapArray> placeholder;
+ placeholder.instantiate();
+ placeholder->set_size(Size2i(get_width(), get_height()));
+ placeholder->set_layers(get_layers());
+ return placeholder;
+}
diff --git a/scene/resources/image_texture.h b/scene/resources/image_texture.h
new file mode 100644
index 0000000000..9d9c296a45
--- /dev/null
+++ b/scene/resources/image_texture.h
@@ -0,0 +1,203 @@
+/**************************************************************************/
+/* image_texture.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 IMAGE_TEXTURE_H
+#define IMAGE_TEXTURE_H
+
+#include "scene/resources/texture.h"
+
+class BitMap;
+
+class ImageTexture : public Texture2D {
+ GDCLASS(ImageTexture, Texture2D);
+ RES_BASE_EXTENSION("tex");
+
+ mutable RID texture;
+ Image::Format format = Image::FORMAT_L8;
+ bool mipmaps = false;
+ int w = 0;
+ int h = 0;
+ Size2 size_override;
+ mutable Ref<BitMap> alpha_cache;
+ bool image_stored = false;
+
+protected:
+ virtual void reload_from_file() 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;
+
+ static void _bind_methods();
+
+public:
+ void set_image(const Ref<Image> &p_image);
+ static Ref<ImageTexture> create_from_image(const Ref<Image> &p_image);
+
+ Image::Format get_format() const;
+
+ void update(const Ref<Image> &p_image);
+ Ref<Image> get_image() const override;
+
+ int get_width() const override;
+ int get_height() const override;
+
+ virtual RID get_rid() const override;
+
+ bool has_alpha() const override;
+ virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
+
+ bool is_pixel_opaque(int p_x, int p_y) const override;
+
+ void set_size_override(const Size2i &p_size);
+
+ virtual void set_path(const String &p_path, bool p_take_over = false) override;
+
+ ImageTexture();
+ ~ImageTexture();
+};
+
+class ImageTextureLayered : public TextureLayered {
+ GDCLASS(ImageTextureLayered, TextureLayered);
+
+ LayeredType layered_type;
+
+ mutable RID texture;
+ Image::Format format = Image::FORMAT_L8;
+
+ int width = 0;
+ int height = 0;
+ int layers = 0;
+ bool mipmaps = false;
+
+ Error _create_from_images(const TypedArray<Image> &p_images);
+
+ TypedArray<Image> _get_images() const;
+ void _set_images(const TypedArray<Image> &p_images);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Image::Format get_format() const override;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual int get_layers() const override;
+ virtual bool has_mipmaps() const override;
+ virtual LayeredType get_layered_type() const override;
+
+ Error create_from_images(Vector<Ref<Image>> p_images);
+ void update_layer(const Ref<Image> &p_image, int p_layer);
+ virtual Ref<Image> get_layer_data(int p_layer) const override;
+
+ virtual RID get_rid() const override;
+ virtual void set_path(const String &p_path, bool p_take_over = false) override;
+
+ ImageTextureLayered(LayeredType p_layered_type);
+ ~ImageTextureLayered();
+};
+
+class ImageTexture3D : public Texture3D {
+ GDCLASS(ImageTexture3D, Texture3D);
+
+ mutable RID texture;
+
+ Image::Format format = Image::FORMAT_L8;
+ int width = 1;
+ int height = 1;
+ int depth = 1;
+ bool mipmaps = false;
+
+protected:
+ static void _bind_methods();
+
+ Error _create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data);
+ void _update(const TypedArray<Image> &p_data);
+
+public:
+ virtual Image::Format get_format() const override;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual int get_depth() const override;
+ virtual bool has_mipmaps() const override;
+
+ Error create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data);
+ void update(const Vector<Ref<Image>> &p_data);
+ virtual Vector<Ref<Image>> get_data() const override;
+
+ virtual RID get_rid() const override;
+ virtual void set_path(const String &p_path, bool p_take_over = false) override;
+
+ ImageTexture3D();
+ ~ImageTexture3D();
+};
+
+class Texture2DArray : public ImageTextureLayered {
+ GDCLASS(Texture2DArray, ImageTextureLayered)
+
+protected:
+ static void _bind_methods();
+
+public:
+ Texture2DArray() :
+ ImageTextureLayered(LAYERED_TYPE_2D_ARRAY) {}
+
+ virtual Ref<Resource> create_placeholder() const;
+};
+
+class Cubemap : public ImageTextureLayered {
+ GDCLASS(Cubemap, ImageTextureLayered);
+
+protected:
+ static void _bind_methods();
+
+public:
+ Cubemap() :
+ ImageTextureLayered(LAYERED_TYPE_CUBEMAP) {}
+
+ virtual Ref<Resource> create_placeholder() const;
+};
+
+class CubemapArray : public ImageTextureLayered {
+ GDCLASS(CubemapArray, ImageTextureLayered);
+
+protected:
+ static void _bind_methods();
+
+public:
+ CubemapArray() :
+ ImageTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
+
+ virtual Ref<Resource> create_placeholder() const;
+};
+
+#endif // IMAGE_TEXTURE_H
diff --git a/scene/resources/label_settings.cpp b/scene/resources/label_settings.cpp
index 37912df921..9a530fb680 100644
--- a/scene/resources/label_settings.cpp
+++ b/scene/resources/label_settings.cpp
@@ -30,8 +30,6 @@
#include "label_settings.h"
-#include "core/core_string_names.h"
-
void LabelSettings::_font_changed() {
emit_changed();
}
@@ -95,11 +93,11 @@ real_t LabelSettings::get_line_spacing() const {
void LabelSettings::set_font(const Ref<Font> &p_font) {
if (font != p_font) {
if (font.is_valid()) {
- font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &LabelSettings::_font_changed));
+ font->disconnect_changed(callable_mp(this, &LabelSettings::_font_changed));
}
font = p_font;
if (font.is_valid()) {
- font->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &LabelSettings::_font_changed), CONNECT_REFERENCE_COUNTED);
+ font->connect_changed(callable_mp(this, &LabelSettings::_font_changed), CONNECT_REFERENCE_COUNTED);
}
emit_changed();
}
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 372b9fea55..65da0bc3c8 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -385,7 +385,7 @@ void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
// This can be a slow operation, and `notify_property_list_changed()` (which is called by `_shader_changed()`)
// does nothing in non-editor builds anyway. See GH-34741 for details.
if (shader.is_valid() && Engine::get_singleton()->is_editor_hint()) {
- shader->disconnect("changed", callable_mp(this, &ShaderMaterial::_shader_changed));
+ shader->disconnect_changed(callable_mp(this, &ShaderMaterial::_shader_changed));
}
shader = p_shader;
@@ -395,7 +395,7 @@ void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
rid = shader->get_rid();
if (Engine::get_singleton()->is_editor_hint()) {
- shader->connect("changed", callable_mp(this, &ShaderMaterial::_shader_changed));
+ shader->connect_changed(callable_mp(this, &ShaderMaterial::_shader_changed));
}
}
@@ -1139,7 +1139,7 @@ void BaseMaterial3D::_update_shader() {
if (!RenderingServer::get_singleton()->is_low_end() && features[FEATURE_HEIGHT_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //heightmap not supported with triplanar
code += " {\n";
- code += " vec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT*heightmap_flip.x,-BINORMAL*heightmap_flip.y,NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-)
+ code += " vec3 view_dir = normalize(normalize(-VERTEX + EYE_OFFSET) * mat3(TANGENT * heightmap_flip.x, -BINORMAL * heightmap_flip.y, NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-)
if (deep_parallax) {
code += " float num_layers = mix(float(heightmap_max_layers),float(heightmap_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));\n";
@@ -2876,7 +2876,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_proximity_fade_distance", "get_proximity_fade_distance");
ADD_GROUP("MSDF", "msdf_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), "set_msdf_pixel_range", "get_msdf_pixel_range");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_outline_size", PROPERTY_HINT_RANGE, "1,250,1"), "set_msdf_outline_size", "get_msdf_outline_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_outline_size", PROPERTY_HINT_RANGE, "0,250,1"), "set_msdf_outline_size", "get_msdf_outline_size");
ADD_GROUP("Distance Fade", "distance_fade_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "distance_fade_mode", PROPERTY_HINT_ENUM, "Disabled,PixelAlpha,PixelDither,ObjectDither"), "set_distance_fade", "get_distance_fade");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_distance_fade_min_distance", "get_distance_fade_min_distance");
@@ -3064,6 +3064,9 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_grow(0.0);
+ set_msdf_pixel_range(4.0);
+ set_msdf_outline_size(0.0);
+
set_heightmap_deep_parallax_min_layers(8);
set_heightmap_deep_parallax_max_layers(32);
set_heightmap_deep_parallax_flip_tangent(false); //also sets binormal
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index 015eb0fa45..5000541621 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -144,7 +144,6 @@ void MeshLibrary::set_item_name(int p_item, const String &p_name) {
void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].mesh = p_mesh;
- notify_change_to_owners();
emit_changed();
notify_property_list_changed();
}
@@ -152,7 +151,6 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
void MeshLibrary::set_item_mesh_transform(int p_item, const Transform3D &p_transform) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].mesh_transform = p_transform;
- notify_change_to_owners();
emit_changed();
}
@@ -160,7 +158,6 @@ void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes)
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].shapes = p_shapes;
notify_property_list_changed();
- notify_change_to_owners();
emit_changed();
notify_property_list_changed();
}
@@ -169,7 +166,6 @@ void MeshLibrary::set_item_navigation_mesh(int p_item, const Ref<NavigationMesh>
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navigation_mesh = p_navigation_mesh;
notify_property_list_changed();
- notify_change_to_owners();
emit_changed();
notify_property_list_changed();
}
@@ -177,7 +173,6 @@ void MeshLibrary::set_item_navigation_mesh(int p_item, const Ref<NavigationMesh>
void MeshLibrary::set_item_navigation_mesh_transform(int p_item, const Transform3D &p_transform) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navigation_mesh_transform = p_transform;
- notify_change_to_owners();
emit_changed();
notify_property_list_changed();
}
@@ -186,7 +181,6 @@ void MeshLibrary::set_item_navigation_layers(int p_item, uint32_t p_navigation_l
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navigation_layers = p_navigation_layers;
notify_property_list_changed();
- notify_change_to_owners();
emit_changed();
}
@@ -244,14 +238,12 @@ bool MeshLibrary::has_item(int p_item) const {
void MeshLibrary::remove_item(int p_item) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map.erase(p_item);
- notify_change_to_owners();
notify_property_list_changed();
emit_changed();
}
void MeshLibrary::clear() {
item_map.clear();
- notify_change_to_owners();
notify_property_list_changed();
emit_changed();
}
diff --git a/scene/resources/mesh_texture.cpp b/scene/resources/mesh_texture.cpp
new file mode 100644
index 0000000000..1440b7f02b
--- /dev/null
+++ b/scene/resources/mesh_texture.cpp
@@ -0,0 +1,156 @@
+/**************************************************************************/
+/* mesh_texture.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 "mesh_texture.h"
+
+#include "scene/resources/mesh.h"
+
+int MeshTexture::get_width() const {
+ return size.width;
+}
+
+int MeshTexture::get_height() const {
+ return size.height;
+}
+
+RID MeshTexture::get_rid() const {
+ return RID();
+}
+
+bool MeshTexture::has_alpha() const {
+ return false;
+}
+
+void MeshTexture::set_mesh(const Ref<Mesh> &p_mesh) {
+ mesh = p_mesh;
+}
+
+Ref<Mesh> MeshTexture::get_mesh() const {
+ return mesh;
+}
+
+void MeshTexture::set_image_size(const Size2 &p_size) {
+ size = p_size;
+}
+
+Size2 MeshTexture::get_image_size() const {
+ return size;
+}
+
+void MeshTexture::set_base_texture(const Ref<Texture2D> &p_texture) {
+ base_texture = p_texture;
+}
+
+Ref<Texture2D> MeshTexture::get_base_texture() const {
+ return base_texture;
+}
+
+void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
+ if (mesh.is_null() || base_texture.is_null()) {
+ return;
+ }
+ Transform2D xform;
+ xform.set_origin(p_pos);
+ if (p_transpose) {
+ SWAP(xform.columns[0][1], xform.columns[1][0]);
+ SWAP(xform.columns[0][0], xform.columns[1][1]);
+ }
+ RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid());
+}
+
+void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
+ if (mesh.is_null() || base_texture.is_null()) {
+ return;
+ }
+ Transform2D xform;
+ Vector2 origin = p_rect.position;
+ if (p_rect.size.x < 0) {
+ origin.x += size.x;
+ }
+ if (p_rect.size.y < 0) {
+ origin.y += size.y;
+ }
+ xform.set_origin(origin);
+ xform.set_scale(p_rect.size / size);
+
+ if (p_transpose) {
+ SWAP(xform.columns[0][1], xform.columns[1][0]);
+ SWAP(xform.columns[0][0], xform.columns[1][1]);
+ }
+ RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid());
+}
+
+void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
+ if (mesh.is_null() || base_texture.is_null()) {
+ return;
+ }
+ Transform2D xform;
+ Vector2 origin = p_rect.position;
+ if (p_rect.size.x < 0) {
+ origin.x += size.x;
+ }
+ if (p_rect.size.y < 0) {
+ origin.y += size.y;
+ }
+ xform.set_origin(origin);
+ xform.set_scale(p_rect.size / size);
+
+ if (p_transpose) {
+ SWAP(xform.columns[0][1], xform.columns[1][0]);
+ SWAP(xform.columns[0][0], xform.columns[1][1]);
+ }
+ RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid());
+}
+
+bool MeshTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
+ r_rect = p_rect;
+ r_src_rect = p_src_rect;
+ return true;
+}
+
+bool MeshTexture::is_pixel_opaque(int p_x, int p_y) const {
+ return true;
+}
+
+void MeshTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshTexture::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &MeshTexture::get_mesh);
+ ClassDB::bind_method(D_METHOD("set_image_size", "size"), &MeshTexture::set_image_size);
+ ClassDB::bind_method(D_METHOD("get_image_size"), &MeshTexture::get_image_size);
+ ClassDB::bind_method(D_METHOD("set_base_texture", "texture"), &MeshTexture::set_base_texture);
+ ClassDB::bind_method(D_METHOD("get_base_texture"), &MeshTexture::get_base_texture);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_base_texture", "get_base_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1,suffix:px"), "set_image_size", "get_image_size");
+}
+
+MeshTexture::MeshTexture() {
+}
diff --git a/scene/resources/mesh_texture.h b/scene/resources/mesh_texture.h
new file mode 100644
index 0000000000..35ccb727c4
--- /dev/null
+++ b/scene/resources/mesh_texture.h
@@ -0,0 +1,75 @@
+/**************************************************************************/
+/* mesh_texture.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 MESH_TEXTURE_H
+#define MESH_TEXTURE_H
+
+#include "scene/resources/texture.h"
+
+class Mesh;
+
+class MeshTexture : public Texture2D {
+ GDCLASS(MeshTexture, Texture2D);
+ RES_BASE_EXTENSION("meshtex");
+
+ Ref<Texture2D> base_texture;
+ Ref<Mesh> mesh;
+ Size2i size;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual RID get_rid() const override;
+
+ virtual bool has_alpha() const override;
+
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
+
+ void set_image_size(const Size2 &p_size);
+ Size2 get_image_size() const;
+
+ void set_base_texture(const Ref<Texture2D> &p_texture);
+ Ref<Texture2D> get_base_texture() const;
+
+ virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
+ virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const override;
+
+ bool is_pixel_opaque(int p_x, int p_y) const override;
+
+ MeshTexture();
+};
+
+#endif // MESH_TEXTURE_H
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 1d13f07b12..82b5c6257c 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -341,6 +341,11 @@ void NavigationMesh::clear_polygons() {
polygons.clear();
}
+void NavigationMesh::clear() {
+ polygons.clear();
+ vertices.clear();
+}
+
#ifdef DEBUG_ENABLED
Ref<ArrayMesh> NavigationMesh::get_debug_mesh() {
if (debug_mesh.is_valid()) {
@@ -518,6 +523,8 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationMesh::_set_polygons);
ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationMesh::_get_polygons);
+ ClassDB::bind_method(D_METHOD("clear"), &NavigationMesh::clear);
+
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index c3b8c13c05..8b9b810038 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -43,19 +43,6 @@ class NavigationMesh : public Resource {
Vector<Polygon> polygons;
Ref<ArrayMesh> debug_mesh;
- struct _EdgeKey {
- Vector3 from;
- Vector3 to;
-
- static uint32_t hash(const _EdgeKey &p_key) {
- return HashMapHasherDefault::hash(p_key.from) ^ HashMapHasherDefault::hash(p_key.to);
- }
-
- bool operator==(const _EdgeKey &p_with) const {
- return HashMapComparatorDefault<Vector3>::compare(from, p_with.from) && HashMapComparatorDefault<Vector3>::compare(to, p_with.to);
- }
- };
-
protected:
static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
@@ -99,7 +86,7 @@ protected:
float agent_max_slope = 45.0f;
float region_min_size = 2.0f;
float region_merge_size = 20.0f;
- float edge_max_length = 12.0f;
+ float edge_max_length = 0.0f;
float edge_max_error = 1.3f;
float vertices_per_polygon = 6.0f;
float detail_sample_distance = 6.0f;
@@ -202,6 +189,8 @@ public:
Vector<int> get_polygon(int p_idx);
void clear_polygons();
+ void clear();
+
#ifdef DEBUG_ENABLED
Ref<ArrayMesh> get_debug_mesh();
#endif // DEBUG_ENABLED
diff --git a/scene/resources/navigation_polygon.cpp b/scene/resources/navigation_polygon.cpp
index 0b60d46d40..e521bfb2e0 100644
--- a/scene/resources/navigation_polygon.cpp
+++ b/scene/resources/navigation_polygon.cpp
@@ -162,6 +162,15 @@ void NavigationPolygon::clear_polygons() {
}
}
+void NavigationPolygon::clear() {
+ polygons.clear();
+ vertices.clear();
+ {
+ MutexLock lock(navigation_mesh_generation);
+ navigation_mesh.unref();
+ }
+}
+
Ref<NavigationMesh> NavigationPolygon::get_navigation_mesh() {
MutexLock lock(navigation_mesh_generation);
@@ -360,6 +369,8 @@ void NavigationPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationPolygon::set_cell_size);
ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationPolygon::get_cell_size);
+ ClassDB::bind_method(D_METHOD("clear"), &NavigationPolygon::clear);
+
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
diff --git a/scene/resources/navigation_polygon.h b/scene/resources/navigation_polygon.h
index 3ab666eb16..7926709a9e 100644
--- a/scene/resources/navigation_polygon.h
+++ b/scene/resources/navigation_polygon.h
@@ -92,6 +92,8 @@ public:
void set_cell_size(real_t p_cell_size);
real_t get_cell_size() const;
+ void clear();
+
NavigationPolygon() {}
~NavigationPolygon() {}
};
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 35799dc1ee..2be3ac08af 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -255,6 +255,7 @@ public:
virtual void set_path(const String &p_path, bool p_take_over = false) override;
#ifdef TOOLS_ENABLED
virtual void set_last_modified_time(uint64_t p_time) override {
+ Resource::set_last_modified_time(p_time);
state->set_last_modified_time(p_time);
}
diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index d6639d4e3f..745c71626c 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -31,6 +31,7 @@
#include "particle_process_material.h"
#include "core/version.h"
+#include "scene/resources/curve_texture.h"
Mutex ParticleProcessMaterial::material_mutex;
SelfList<ParticleProcessMaterial>::List *ParticleProcessMaterial::dirty_materials = nullptr;
diff --git a/scene/resources/placeholder_textures.cpp b/scene/resources/placeholder_textures.cpp
new file mode 100644
index 0000000000..224ea1f177
--- /dev/null
+++ b/scene/resources/placeholder_textures.cpp
@@ -0,0 +1,177 @@
+/**************************************************************************/
+/* placeholder_textures.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 "placeholder_textures.h"
+
+void PlaceholderTexture2D::set_size(Size2 p_size) {
+ size = p_size;
+}
+
+int PlaceholderTexture2D::get_width() const {
+ return size.width;
+}
+
+int PlaceholderTexture2D::get_height() const {
+ return size.height;
+}
+
+bool PlaceholderTexture2D::has_alpha() const {
+ return false;
+}
+
+Ref<Image> PlaceholderTexture2D::get_image() const {
+ return Ref<Image>();
+}
+
+RID PlaceholderTexture2D::get_rid() const {
+ return rid;
+}
+
+void PlaceholderTexture2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture2D::set_size);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
+}
+
+PlaceholderTexture2D::PlaceholderTexture2D() {
+ rid = RS::get_singleton()->texture_2d_placeholder_create();
+}
+
+PlaceholderTexture2D::~PlaceholderTexture2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(rid);
+}
+
+///////////////////////////////////////////////
+
+void PlaceholderTexture3D::set_size(const Vector3i &p_size) {
+ size = p_size;
+}
+
+Vector3i PlaceholderTexture3D::get_size() const {
+ return size;
+}
+
+Image::Format PlaceholderTexture3D::get_format() const {
+ return Image::FORMAT_RGB8;
+}
+
+int PlaceholderTexture3D::get_width() const {
+ return size.x;
+}
+
+int PlaceholderTexture3D::get_height() const {
+ return size.y;
+}
+
+int PlaceholderTexture3D::get_depth() const {
+ return size.z;
+}
+
+bool PlaceholderTexture3D::has_mipmaps() const {
+ return false;
+}
+
+Vector<Ref<Image>> PlaceholderTexture3D::get_data() const {
+ return Vector<Ref<Image>>();
+}
+
+void PlaceholderTexture3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture3D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTexture3D::get_size);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
+}
+
+PlaceholderTexture3D::PlaceholderTexture3D() {
+ rid = RS::get_singleton()->texture_3d_placeholder_create();
+}
+PlaceholderTexture3D::~PlaceholderTexture3D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(rid);
+}
+
+/////////////////////////////////////////////////
+
+void PlaceholderTextureLayered::set_size(const Size2i &p_size) {
+ size = p_size;
+}
+
+Size2i PlaceholderTextureLayered::get_size() const {
+ return size;
+}
+
+void PlaceholderTextureLayered::set_layers(int p_layers) {
+ layers = p_layers;
+}
+
+Image::Format PlaceholderTextureLayered::get_format() const {
+ return Image::FORMAT_RGB8;
+}
+
+TextureLayered::LayeredType PlaceholderTextureLayered::get_layered_type() const {
+ return layered_type;
+}
+
+int PlaceholderTextureLayered::get_width() const {
+ return size.x;
+}
+
+int PlaceholderTextureLayered::get_height() const {
+ return size.y;
+}
+
+int PlaceholderTextureLayered::get_layers() const {
+ return layers;
+}
+
+bool PlaceholderTextureLayered::has_mipmaps() const {
+ return false;
+}
+
+Ref<Image> PlaceholderTextureLayered::get_layer_data(int p_layer) const {
+ return Ref<Image>();
+}
+
+void PlaceholderTextureLayered::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTextureLayered::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTextureLayered::get_size);
+ ClassDB::bind_method(D_METHOD("set_layers", "layers"), &PlaceholderTextureLayered::set_layers);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_RANGE, "1,4096"), "set_layers", "get_layers");
+}
+
+PlaceholderTextureLayered::PlaceholderTextureLayered(LayeredType p_type) {
+ layered_type = p_type;
+ rid = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));
+}
+PlaceholderTextureLayered::~PlaceholderTextureLayered() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RS::get_singleton()->free(rid);
+}
diff --git a/scene/resources/placeholder_textures.h b/scene/resources/placeholder_textures.h
new file mode 100644
index 0000000000..116ed0f0f0
--- /dev/null
+++ b/scene/resources/placeholder_textures.h
@@ -0,0 +1,130 @@
+/**************************************************************************/
+/* placeholder_textures.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 PLACEHOLDER_TEXTURES_H
+#define PLACEHOLDER_TEXTURES_H
+
+#include "scene/resources/texture.h"
+
+class PlaceholderTexture2D : public Texture2D {
+ GDCLASS(PlaceholderTexture2D, Texture2D)
+
+ RID rid;
+ Size2 size = Size2(1, 1);
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_size(Size2 p_size);
+
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual RID get_rid() const override;
+ virtual bool has_alpha() const override;
+
+ virtual Ref<Image> get_image() const override;
+
+ PlaceholderTexture2D();
+ ~PlaceholderTexture2D();
+};
+
+class PlaceholderTexture3D : public Texture3D {
+ GDCLASS(PlaceholderTexture3D, Texture3D)
+
+ RID rid;
+ Vector3i size = Vector3i(1, 1, 1);
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_size(const Vector3i &p_size);
+ Vector3i get_size() const;
+ virtual Image::Format get_format() const override;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual int get_depth() const override;
+ virtual bool has_mipmaps() const override;
+ virtual Vector<Ref<Image>> get_data() const override;
+
+ PlaceholderTexture3D();
+ ~PlaceholderTexture3D();
+};
+
+class PlaceholderTextureLayered : public TextureLayered {
+ GDCLASS(PlaceholderTextureLayered, TextureLayered)
+
+ RID rid;
+ Size2i size = Size2i(1, 1);
+ int layers = 1;
+ LayeredType layered_type = LAYERED_TYPE_2D_ARRAY;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_size(const Size2i &p_size);
+ Size2i get_size() const;
+ void set_layers(int p_layers);
+ virtual Image::Format get_format() const override;
+ virtual LayeredType get_layered_type() const override;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual int get_layers() const override;
+ virtual bool has_mipmaps() const override;
+ virtual Ref<Image> get_layer_data(int p_layer) const override;
+
+ PlaceholderTextureLayered(LayeredType p_type);
+ ~PlaceholderTextureLayered();
+};
+
+class PlaceholderTexture2DArray : public PlaceholderTextureLayered {
+ GDCLASS(PlaceholderTexture2DArray, PlaceholderTextureLayered)
+public:
+ PlaceholderTexture2DArray() :
+ PlaceholderTextureLayered(LAYERED_TYPE_2D_ARRAY) {}
+};
+
+class PlaceholderCubemap : public PlaceholderTextureLayered {
+ GDCLASS(PlaceholderCubemap, PlaceholderTextureLayered)
+public:
+ PlaceholderCubemap() :
+ PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP) {}
+};
+
+class PlaceholderCubemapArray : public PlaceholderTextureLayered {
+ GDCLASS(PlaceholderCubemapArray, PlaceholderTextureLayered)
+public:
+ PlaceholderCubemapArray() :
+ PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
+};
+
+#endif // PLACEHOLDER_TEXTURES_H
diff --git a/scene/resources/portable_compressed_texture.cpp b/scene/resources/portable_compressed_texture.cpp
new file mode 100644
index 0000000000..a61799c7d6
--- /dev/null
+++ b/scene/resources/portable_compressed_texture.cpp
@@ -0,0 +1,339 @@
+/**************************************************************************/
+/* portable_compressed_texture.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 "portable_compressed_texture.h"
+
+#include "core/io/marshalls.h"
+#include "scene/resources/bit_map.h"
+
+void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
+ if (p_data.size() == 0) {
+ return; //nothing to do
+ }
+
+ const uint8_t *data = p_data.ptr();
+ uint32_t data_size = p_data.size();
+ ERR_FAIL_COND(data_size < 20);
+ compression_mode = CompressionMode(decode_uint32(data + 0));
+ format = Image::Format(decode_uint32(data + 4));
+ uint32_t mipmap_count = decode_uint32(data + 8);
+ size.width = decode_uint32(data + 12);
+ size.height = decode_uint32(data + 16);
+ mipmaps = mipmap_count > 1;
+
+ data += 20;
+ data_size -= 20;
+
+ Ref<Image> image;
+
+ switch (compression_mode) {
+ case COMPRESSION_MODE_LOSSLESS:
+ case COMPRESSION_MODE_LOSSY: {
+ Vector<uint8_t> image_data;
+
+ ERR_FAIL_COND(data_size < 4);
+ for (uint32_t i = 0; i < mipmap_count; i++) {
+ uint32_t mipsize = decode_uint32(data);
+ data += 4;
+ data_size -= 4;
+ ERR_FAIL_COND(mipsize < data_size);
+ Ref<Image> img = memnew(Image(data, data_size));
+ ERR_FAIL_COND(img->is_empty());
+ if (img->get_format() != format) { // May happen due to webp/png in the tiny mipmaps.
+ img->convert(format);
+ }
+ image_data.append_array(img->get_data());
+
+ data += mipsize;
+ data_size -= mipsize;
+ }
+
+ image = Ref<Image>(memnew(Image(size.width, size.height, mipmap_count > 1, format, image_data)));
+
+ } break;
+ case COMPRESSION_MODE_BASIS_UNIVERSAL: {
+ ERR_FAIL_NULL(Image::basis_universal_unpacker_ptr);
+ image = Image::basis_universal_unpacker_ptr(data, data_size);
+
+ } break;
+ case COMPRESSION_MODE_S3TC:
+ case COMPRESSION_MODE_ETC2:
+ case COMPRESSION_MODE_BPTC: {
+ image = Ref<Image>(memnew(Image(size.width, size.height, mipmap_count > 1, format, p_data.slice(20))));
+ } break;
+ }
+ ERR_FAIL_COND(image.is_null());
+
+ if (texture.is_null()) {
+ texture = RenderingServer::get_singleton()->texture_2d_create(image);
+ } else {
+ RID new_texture = RenderingServer::get_singleton()->texture_2d_create(image);
+ RenderingServer::get_singleton()->texture_replace(texture, new_texture);
+ }
+
+ image_stored = true;
+ RenderingServer::get_singleton()->texture_set_size_override(texture, size_override.width, size_override.height);
+ alpha_cache.unref();
+
+ if (keep_all_compressed_buffers || keep_compressed_buffer) {
+ compressed_buffer = p_data;
+ } else {
+ compressed_buffer.clear();
+ }
+}
+
+PortableCompressedTexture2D::CompressionMode PortableCompressedTexture2D::get_compression_mode() const {
+ return compression_mode;
+}
+Vector<uint8_t> PortableCompressedTexture2D::_get_data() const {
+ return compressed_buffer;
+}
+
+void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, CompressionMode p_compression_mode, bool p_normal_map, float p_lossy_quality) {
+ ERR_FAIL_COND(p_image.is_null() || p_image->is_empty());
+
+ Vector<uint8_t> buffer;
+
+ buffer.resize(20);
+ encode_uint32(p_compression_mode, buffer.ptrw());
+ encode_uint32(p_image->get_format(), buffer.ptrw() + 4);
+ encode_uint32(p_image->get_mipmap_count() + 1, buffer.ptrw() + 8);
+ encode_uint32(p_image->get_width(), buffer.ptrw() + 12);
+ encode_uint32(p_image->get_height(), buffer.ptrw() + 16);
+
+ switch (p_compression_mode) {
+ case COMPRESSION_MODE_LOSSLESS:
+ case COMPRESSION_MODE_LOSSY: {
+ for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
+ Vector<uint8_t> data;
+ if (p_compression_mode == COMPRESSION_MODE_LOSSY) {
+ data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
+ } else {
+ data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
+ }
+ int data_len = data.size();
+ buffer.resize(buffer.size() + 4);
+ encode_uint32(data_len, buffer.ptrw() + buffer.size() - 4);
+ buffer.append_array(data);
+ }
+ } break;
+ case COMPRESSION_MODE_BASIS_UNIVERSAL: {
+ Image::UsedChannels uc = p_image->detect_used_channels(p_normal_map ? Image::COMPRESS_SOURCE_NORMAL : Image::COMPRESS_SOURCE_GENERIC);
+ Vector<uint8_t> budata = Image::basis_universal_packer(p_image, uc);
+ buffer.append_array(budata);
+
+ } break;
+ case COMPRESSION_MODE_S3TC:
+ case COMPRESSION_MODE_ETC2:
+ case COMPRESSION_MODE_BPTC: {
+ Ref<Image> copy = p_image->duplicate();
+ switch (p_compression_mode) {
+ case COMPRESSION_MODE_S3TC:
+ copy->compress(Image::COMPRESS_S3TC);
+ break;
+ case COMPRESSION_MODE_ETC2:
+ copy->compress(Image::COMPRESS_ETC2);
+ break;
+ case COMPRESSION_MODE_BPTC:
+ copy->compress(Image::COMPRESS_BPTC);
+ break;
+ default: {
+ };
+ }
+
+ buffer.append_array(copy->get_data());
+
+ } break;
+ }
+
+ _set_data(buffer);
+}
+
+Image::Format PortableCompressedTexture2D::get_format() const {
+ return format;
+}
+
+Ref<Image> PortableCompressedTexture2D::get_image() const {
+ if (image_stored) {
+ return RenderingServer::get_singleton()->texture_2d_get(texture);
+ } else {
+ return Ref<Image>();
+ }
+}
+
+int PortableCompressedTexture2D::get_width() const {
+ return size.width;
+}
+
+int PortableCompressedTexture2D::get_height() const {
+ return size.height;
+}
+
+RID PortableCompressedTexture2D::get_rid() const {
+ if (texture.is_null()) {
+ // We are in trouble, create something temporary.
+ texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
+ }
+ return texture;
+}
+
+bool PortableCompressedTexture2D::has_alpha() const {
+ return (format == Image::FORMAT_LA8 || format == Image::FORMAT_RGBA8);
+}
+
+void PortableCompressedTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
+ if (size.width == 0 || size.height == 0) {
+ return;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, size), texture, false, p_modulate, p_transpose);
+}
+
+void PortableCompressedTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
+ if (size.width == 0 || size.height == 0) {
+ return;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);
+}
+
+void PortableCompressedTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
+ if (size.width == 0 || size.height == 0) {
+ return;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv);
+}
+
+bool PortableCompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {
+ if (!alpha_cache.is_valid()) {
+ Ref<Image> img = get_image();
+ if (img.is_valid()) {
+ if (img->is_compressed()) { //must decompress, if compressed
+ Ref<Image> decom = img->duplicate();
+ decom->decompress();
+ img = decom;
+ }
+ alpha_cache.instantiate();
+ alpha_cache->create_from_image_alpha(img);
+ }
+ }
+
+ if (alpha_cache.is_valid()) {
+ int aw = int(alpha_cache->get_size().width);
+ int ah = int(alpha_cache->get_size().height);
+ if (aw == 0 || ah == 0) {
+ return true;
+ }
+
+ int x = p_x * aw / size.width;
+ int y = p_y * ah / size.height;
+
+ x = CLAMP(x, 0, aw);
+ y = CLAMP(y, 0, ah);
+
+ return alpha_cache->get_bit(x, y);
+ }
+
+ return true;
+}
+
+void PortableCompressedTexture2D::set_size_override(const Size2 &p_size) {
+ size_override = p_size;
+ RenderingServer::get_singleton()->texture_set_size_override(texture, size_override.width, size_override.height);
+}
+
+Size2 PortableCompressedTexture2D::get_size_override() const {
+ return size_override;
+}
+
+void PortableCompressedTexture2D::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+bool PortableCompressedTexture2D::keep_all_compressed_buffers = false;
+
+void PortableCompressedTexture2D::set_keep_all_compressed_buffers(bool p_keep) {
+ keep_all_compressed_buffers = p_keep;
+}
+
+bool PortableCompressedTexture2D::is_keeping_all_compressed_buffers() {
+ return keep_all_compressed_buffers;
+}
+
+void PortableCompressedTexture2D::set_keep_compressed_buffer(bool p_keep) {
+ keep_compressed_buffer = p_keep;
+ if (!p_keep) {
+ compressed_buffer.clear();
+ }
+}
+
+bool PortableCompressedTexture2D::is_keeping_compressed_buffer() const {
+ return keep_compressed_buffer;
+}
+
+void PortableCompressedTexture2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("create_from_image", "image", "compression_mode", "normal_map", "lossy_quality"), &PortableCompressedTexture2D::create_from_image, DEFVAL(false), DEFVAL(0.8));
+ ClassDB::bind_method(D_METHOD("get_format"), &PortableCompressedTexture2D::get_format);
+ ClassDB::bind_method(D_METHOD("get_compression_mode"), &PortableCompressedTexture2D::get_compression_mode);
+
+ ClassDB::bind_method(D_METHOD("set_size_override", "size"), &PortableCompressedTexture2D::set_size_override);
+ ClassDB::bind_method(D_METHOD("get_size_override"), &PortableCompressedTexture2D::get_size_override);
+
+ ClassDB::bind_method(D_METHOD("set_keep_compressed_buffer", "keep"), &PortableCompressedTexture2D::set_keep_compressed_buffer);
+ ClassDB::bind_method(D_METHOD("is_keeping_compressed_buffer"), &PortableCompressedTexture2D::is_keeping_compressed_buffer);
+
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &PortableCompressedTexture2D::_set_data);
+ ClassDB::bind_method(D_METHOD("_get_data"), &PortableCompressedTexture2D::_get_data);
+
+ ClassDB::bind_static_method("PortableCompressedTexture2D", D_METHOD("set_keep_all_compressed_buffers", "keep"), &PortableCompressedTexture2D::set_keep_all_compressed_buffers);
+ ClassDB::bind_static_method("PortableCompressedTexture2D", D_METHOD("is_keeping_all_compressed_buffers"), &PortableCompressedTexture2D::is_keeping_all_compressed_buffers);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_data", "_get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_override", PROPERTY_HINT_NONE, "suffix:px"), "set_size_override", "get_size_override");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_compressed_buffer"), "set_keep_compressed_buffer", "is_keeping_compressed_buffer");
+
+ BIND_ENUM_CONSTANT(COMPRESSION_MODE_LOSSLESS);
+ BIND_ENUM_CONSTANT(COMPRESSION_MODE_LOSSY);
+ BIND_ENUM_CONSTANT(COMPRESSION_MODE_BASIS_UNIVERSAL);
+ BIND_ENUM_CONSTANT(COMPRESSION_MODE_S3TC);
+ BIND_ENUM_CONSTANT(COMPRESSION_MODE_ETC2);
+ BIND_ENUM_CONSTANT(COMPRESSION_MODE_BPTC);
+}
+
+PortableCompressedTexture2D::PortableCompressedTexture2D() {}
+
+PortableCompressedTexture2D::~PortableCompressedTexture2D() {
+ if (texture.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RenderingServer::get_singleton()->free(texture);
+ }
+}
diff --git a/scene/resources/portable_compressed_texture.h b/scene/resources/portable_compressed_texture.h
new file mode 100644
index 0000000000..86d80e39f7
--- /dev/null
+++ b/scene/resources/portable_compressed_texture.h
@@ -0,0 +1,110 @@
+/**************************************************************************/
+/* portable_compressed_texture.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 PORTABLE_COMPRESSED_TEXTURE_H
+#define PORTABLE_COMPRESSED_TEXTURE_H
+
+#include "scene/resources/texture.h"
+
+class BitMap;
+
+class PortableCompressedTexture2D : public Texture2D {
+ GDCLASS(PortableCompressedTexture2D, Texture2D);
+
+public:
+ enum CompressionMode {
+ COMPRESSION_MODE_LOSSLESS,
+ COMPRESSION_MODE_LOSSY,
+ COMPRESSION_MODE_BASIS_UNIVERSAL,
+ COMPRESSION_MODE_S3TC,
+ COMPRESSION_MODE_ETC2,
+ COMPRESSION_MODE_BPTC,
+ };
+
+private:
+ CompressionMode compression_mode = COMPRESSION_MODE_LOSSLESS;
+ static bool keep_all_compressed_buffers;
+ bool keep_compressed_buffer = false;
+ Vector<uint8_t> compressed_buffer;
+ Size2 size;
+ Size2 size_override;
+ bool mipmaps = false;
+ Image::Format format = Image::FORMAT_L8;
+
+ mutable RID texture;
+ mutable Ref<BitMap> alpha_cache;
+
+ bool image_stored = false;
+
+protected:
+ Vector<uint8_t> _get_data() const;
+ void _set_data(const Vector<uint8_t> &p_data);
+
+ static void _bind_methods();
+
+public:
+ CompressionMode get_compression_mode() const;
+ void create_from_image(const Ref<Image> &p_image, CompressionMode p_compression_mode, bool p_normal_map = false, float p_lossy_quality = 0.8);
+
+ Image::Format get_format() const;
+
+ void update(const Ref<Image> &p_image);
+ Ref<Image> get_image() const override;
+
+ int get_width() const override;
+ int get_height() const override;
+
+ virtual RID get_rid() const override;
+
+ bool has_alpha() const override;
+ virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
+ virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
+
+ bool is_pixel_opaque(int p_x, int p_y) const override;
+
+ virtual void set_path(const String &p_path, bool p_take_over = false) override;
+
+ void set_size_override(const Size2 &p_size);
+ Size2 get_size_override() const;
+
+ void set_keep_compressed_buffer(bool p_keep);
+ bool is_keeping_compressed_buffer() const;
+
+ static void set_keep_all_compressed_buffers(bool p_keep);
+ static bool is_keeping_all_compressed_buffers();
+
+ PortableCompressedTexture2D();
+ ~PortableCompressedTexture2D();
+};
+
+VARIANT_ENUM_CAST(PortableCompressedTexture2D::CompressionMode)
+
+#endif // PORTABLE_COMPRESSED_TEXTURE_H
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 204987cac9..6430a1302d 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -31,7 +31,6 @@
#include "primitive_meshes.h"
#include "core/config/project_settings.h"
-#include "core/core_string_names.h"
#include "scene/resources/theme.h"
#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
@@ -2194,11 +2193,11 @@ void TubeTrailMesh::set_curve(const Ref<Curve> &p_curve) {
return;
}
if (curve.is_valid()) {
- curve->disconnect("changed", callable_mp(this, &TubeTrailMesh::_curve_changed));
+ curve->disconnect_changed(callable_mp(this, &TubeTrailMesh::_curve_changed));
}
curve = p_curve;
if (curve.is_valid()) {
- curve->connect("changed", callable_mp(this, &TubeTrailMesh::_curve_changed));
+ curve->connect_changed(callable_mp(this, &TubeTrailMesh::_curve_changed));
}
_request_update();
}
@@ -2533,11 +2532,11 @@ void RibbonTrailMesh::set_curve(const Ref<Curve> &p_curve) {
return;
}
if (curve.is_valid()) {
- curve->disconnect("changed", callable_mp(this, &RibbonTrailMesh::_curve_changed));
+ curve->disconnect_changed(callable_mp(this, &RibbonTrailMesh::_curve_changed));
}
curve = p_curve;
if (curve.is_valid()) {
- curve->connect("changed", callable_mp(this, &RibbonTrailMesh::_curve_changed));
+ curve->connect_changed(callable_mp(this, &RibbonTrailMesh::_curve_changed));
}
_request_update();
}
@@ -3446,13 +3445,13 @@ void TextMesh::_font_changed() {
void TextMesh::set_font(const Ref<Font> &p_font) {
if (font_override != p_font) {
if (font_override.is_valid()) {
- font_override->disconnect(CoreStringNames::get_singleton()->changed, Callable(this, "_font_changed"));
+ font_override->disconnect_changed(Callable(this, "_font_changed"));
}
font_override = p_font;
dirty_font = true;
dirty_cache = true;
if (font_override.is_valid()) {
- font_override->connect(CoreStringNames::get_singleton()->changed, Callable(this, "_font_changed"));
+ font_override->connect_changed(Callable(this, "_font_changed"));
}
_request_update();
}
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 7719cc28d2..a2c04698e1 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -1828,6 +1828,10 @@ String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Res
}
String ResourceFormatSaverTextInstance::_write_resource(const Ref<Resource> &res) {
+ if (res->get_meta(SNAME("_skip_save_"), false)) {
+ return "null";
+ }
+
if (external_resources.has(res)) {
return "ExtResource(\"" + external_resources[res] + "\")";
} else {
@@ -1852,7 +1856,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
case Variant::OBJECT: {
Ref<Resource> res = p_variant;
- if (res.is_null() || external_resources.has(res)) {
+ if (res.is_null() || external_resources.has(res) || res->get_meta(SNAME("_skip_save_"), false)) {
return;
}
@@ -1873,6 +1877,8 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
return;
}
+ resource_set.insert(res);
+
List<PropertyInfo> property_list;
res->get_property_list(&property_list);
@@ -1887,14 +1893,17 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
Variant v = res->get(I->get().name);
if (pi.usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) {
+ NonPersistentKey npk;
+ npk.base = res;
+ npk.property = pi.name;
+ non_persistent_map[npk] = v;
+
Ref<Resource> sres = v;
if (sres.is_valid()) {
- NonPersistentKey npk;
- npk.base = res;
- npk.property = pi.name;
- non_persistent_map[npk] = sres;
resource_set.insert(sres);
saved_resources.push_back(sres);
+ } else {
+ _find_resources(v);
}
} else {
_find_resources(v);
@@ -1904,8 +1913,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
I = I->next();
}
- resource_set.insert(res); //saved after, so the children it needs are available when loaded
- saved_resources.push_back(res);
+ saved_resources.push_back(res); // Saved after, so the children it needs are available when loaded
} break;
case Variant::ARRAY: {
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index c35a594f72..1734ccc98b 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -171,7 +171,7 @@ class ResourceFormatSaverTextInstance {
bool operator<(const NonPersistentKey &p_key) const { return base == p_key.base ? property < p_key.property : base < p_key.base; }
};
- RBMap<NonPersistentKey, Ref<Resource>> non_persistent_map;
+ RBMap<NonPersistentKey, Variant> non_persistent_map;
HashSet<Ref<Resource>> resource_set;
List<Ref<Resource>> saved_resources;
diff --git a/scene/resources/separation_ray_shape_3d.cpp b/scene/resources/separation_ray_shape_3d.cpp
index 3d8e2af201..07e93b8b79 100644
--- a/scene/resources/separation_ray_shape_3d.cpp
+++ b/scene/resources/separation_ray_shape_3d.cpp
@@ -56,7 +56,7 @@ void SeparationRayShape3D::_update_shape() {
void SeparationRayShape3D::set_length(float p_length) {
length = p_length;
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
float SeparationRayShape3D::get_length() const {
@@ -66,7 +66,7 @@ float SeparationRayShape3D::get_length() const {
void SeparationRayShape3D::set_slide_on_slope(bool p_active) {
slide_on_slope = p_active;
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
bool SeparationRayShape3D::get_slide_on_slope() const {
@@ -88,5 +88,5 @@ SeparationRayShape3D::SeparationRayShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SEPARATION_RAY)) {
/* Code copied from setters to prevent the use of uninitialized variables */
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 62c2483a93..f919386980 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -63,21 +63,7 @@ void Shader::set_include_path(const String &p_path) {
void Shader::set_code(const String &p_code) {
for (const Ref<ShaderInclude> &E : include_dependencies) {
- E->disconnect(SNAME("changed"), callable_mp(this, &Shader::_dependency_changed));
- }
-
- String type = ShaderLanguage::get_shader_type(p_code);
-
- if (type == "canvas_item") {
- mode = MODE_CANVAS_ITEM;
- } else if (type == "particles") {
- mode = MODE_PARTICLES;
- } else if (type == "sky") {
- mode = MODE_SKY;
- } else if (type == "fog") {
- mode = MODE_FOG;
- } else {
- mode = MODE_SPATIAL;
+ E->disconnect_changed(callable_mp(this, &Shader::_dependency_changed));
}
code = p_code;
@@ -100,8 +86,23 @@ void Shader::set_code(const String &p_code) {
}
}
+ // Try to get the shader type from the final, fully preprocessed shader code.
+ String type = ShaderLanguage::get_shader_type(pp_code);
+
+ if (type == "canvas_item") {
+ mode = MODE_CANVAS_ITEM;
+ } else if (type == "particles") {
+ mode = MODE_PARTICLES;
+ } else if (type == "sky") {
+ mode = MODE_SKY;
+ } else if (type == "fog") {
+ mode = MODE_FOG;
+ } else {
+ mode = MODE_SPATIAL;
+ }
+
for (const Ref<ShaderInclude> &E : include_dependencies) {
- E->connect(SNAME("changed"), callable_mp(this, &Shader::_dependency_changed));
+ E->connect_changed(callable_mp(this, &Shader::_dependency_changed));
}
RenderingServer::get_singleton()->shader_set_code(shader, pp_code);
diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp
index 6e9c64d34b..aead484cc1 100644
--- a/scene/resources/shader_include.cpp
+++ b/scene/resources/shader_include.cpp
@@ -40,7 +40,7 @@ void ShaderInclude::set_code(const String &p_code) {
code = p_code;
for (const Ref<ShaderInclude> &E : dependencies) {
- E->disconnect(SNAME("changed"), callable_mp(this, &ShaderInclude::_dependency_changed));
+ E->disconnect_changed(callable_mp(this, &ShaderInclude::_dependency_changed));
}
{
@@ -60,7 +60,7 @@ void ShaderInclude::set_code(const String &p_code) {
}
for (const Ref<ShaderInclude> &E : dependencies) {
- E->connect(SNAME("changed"), callable_mp(this, &ShaderInclude::_dependency_changed));
+ E->connect_changed(callable_mp(this, &ShaderInclude::_dependency_changed));
}
emit_changed();
diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp
index fa22aabe5b..56b78471ec 100644
--- a/scene/resources/sphere_shape_3d.cpp
+++ b/scene/resources/sphere_shape_3d.cpp
@@ -67,7 +67,7 @@ void SphereShape3D::set_radius(float p_radius) {
ERR_FAIL_COND_MSG(p_radius < 0, "SphereShape3D radius cannot be negative.");
radius = p_radius;
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
float SphereShape3D::get_radius() const {
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index a9ebb21345..f87bf1ee05 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -32,8 +32,6 @@
#include "scene/main/canvas_item.h"
-#include <limits.h>
-
Size2 StyleBox::get_minimum_size() const {
Size2 min_size = Size2(get_margin(SIDE_LEFT) + get_margin(SIDE_RIGHT), get_margin(SIDE_TOP) + get_margin(SIDE_BOTTOM));
Size2 custom_size;
@@ -145,925 +143,3 @@ StyleBox::StyleBox() {
content_margin[i] = -1;
}
}
-
-void StyleBoxTexture::set_texture(Ref<Texture2D> p_texture) {
- if (texture == p_texture) {
- return;
- }
- texture = p_texture;
- emit_changed();
-}
-
-Ref<Texture2D> StyleBoxTexture::get_texture() const {
- return texture;
-}
-
-void StyleBoxTexture::set_texture_margin(Side p_side, float p_size) {
- ERR_FAIL_INDEX((int)p_side, 4);
-
- texture_margin[p_side] = p_size;
- emit_changed();
-}
-
-void StyleBoxTexture::set_texture_margin_all(float p_size) {
- for (int i = 0; i < 4; i++) {
- texture_margin[i] = p_size;
- }
- emit_changed();
-}
-
-void StyleBoxTexture::set_texture_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
- texture_margin[SIDE_LEFT] = p_left;
- texture_margin[SIDE_TOP] = p_top;
- texture_margin[SIDE_RIGHT] = p_right;
- texture_margin[SIDE_BOTTOM] = p_bottom;
- emit_changed();
-}
-
-float StyleBoxTexture::get_texture_margin(Side p_side) const {
- ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
-
- return texture_margin[p_side];
-}
-
-float StyleBoxTexture::get_style_margin(Side p_side) const {
- ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
-
- return texture_margin[p_side];
-}
-
-Rect2 StyleBoxTexture::get_draw_rect(const Rect2 &p_rect) const {
- return p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]);
-}
-
-void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const {
- if (texture.is_null()) {
- return;
- }
-
- Rect2 rect = p_rect;
- Rect2 src_rect = region_rect;
-
- texture->get_rect_region(rect, src_rect, rect, src_rect);
-
- rect.position.x -= expand_margin[SIDE_LEFT];
- rect.position.y -= expand_margin[SIDE_TOP];
- rect.size.x += expand_margin[SIDE_LEFT] + expand_margin[SIDE_RIGHT];
- rect.size.y += expand_margin[SIDE_TOP] + expand_margin[SIDE_BOTTOM];
-
- Vector2 start_offset = Vector2(texture_margin[SIDE_LEFT], texture_margin[SIDE_TOP]);
- Vector2 end_offset = Vector2(texture_margin[SIDE_RIGHT], texture_margin[SIDE_BOTTOM]);
-
- RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), start_offset, end_offset, RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate);
-}
-
-void StyleBoxTexture::set_draw_center(bool p_enabled) {
- draw_center = p_enabled;
- emit_changed();
-}
-
-bool StyleBoxTexture::is_draw_center_enabled() const {
- return draw_center;
-}
-
-void StyleBoxTexture::set_expand_margin(Side p_side, float p_size) {
- ERR_FAIL_INDEX((int)p_side, 4);
- expand_margin[p_side] = p_size;
- emit_changed();
-}
-
-void StyleBoxTexture::set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
- expand_margin[SIDE_LEFT] = p_left;
- expand_margin[SIDE_TOP] = p_top;
- expand_margin[SIDE_RIGHT] = p_right;
- expand_margin[SIDE_BOTTOM] = p_bottom;
- emit_changed();
-}
-
-void StyleBoxTexture::set_expand_margin_all(float p_expand_margin_size) {
- for (int i = 0; i < 4; i++) {
- expand_margin[i] = p_expand_margin_size;
- }
- emit_changed();
-}
-
-float StyleBoxTexture::get_expand_margin(Side p_side) const {
- ERR_FAIL_INDEX_V((int)p_side, 4, 0);
- return expand_margin[p_side];
-}
-
-void StyleBoxTexture::set_region_rect(const Rect2 &p_region_rect) {
- if (region_rect == p_region_rect) {
- return;
- }
-
- region_rect = p_region_rect;
- emit_changed();
-}
-
-Rect2 StyleBoxTexture::get_region_rect() const {
- return region_rect;
-}
-
-void StyleBoxTexture::set_h_axis_stretch_mode(AxisStretchMode p_mode) {
- ERR_FAIL_INDEX((int)p_mode, 3);
- axis_h = p_mode;
- emit_changed();
-}
-
-StyleBoxTexture::AxisStretchMode StyleBoxTexture::get_h_axis_stretch_mode() const {
- return axis_h;
-}
-
-void StyleBoxTexture::set_v_axis_stretch_mode(AxisStretchMode p_mode) {
- ERR_FAIL_INDEX((int)p_mode, 3);
- axis_v = p_mode;
- emit_changed();
-}
-
-StyleBoxTexture::AxisStretchMode StyleBoxTexture::get_v_axis_stretch_mode() const {
- return axis_v;
-}
-
-void StyleBoxTexture::set_modulate(const Color &p_modulate) {
- if (modulate == p_modulate) {
- return;
- }
- modulate = p_modulate;
- emit_changed();
-}
-
-Color StyleBoxTexture::get_modulate() const {
- return modulate;
-}
-
-void StyleBoxTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_texture", "texture"), &StyleBoxTexture::set_texture);
- ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture);
-
- ClassDB::bind_method(D_METHOD("set_texture_margin", "margin", "size"), &StyleBoxTexture::set_texture_margin);
- ClassDB::bind_method(D_METHOD("set_texture_margin_all", "size"), &StyleBoxTexture::set_texture_margin_all);
- ClassDB::bind_method(D_METHOD("get_texture_margin", "margin"), &StyleBoxTexture::get_texture_margin);
-
- ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxTexture::set_expand_margin);
- ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_all);
- ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxTexture::get_expand_margin);
-
- ClassDB::bind_method(D_METHOD("set_region_rect", "region"), &StyleBoxTexture::set_region_rect);
- ClassDB::bind_method(D_METHOD("get_region_rect"), &StyleBoxTexture::get_region_rect);
-
- ClassDB::bind_method(D_METHOD("set_draw_center", "enable"), &StyleBoxTexture::set_draw_center);
- ClassDB::bind_method(D_METHOD("is_draw_center_enabled"), &StyleBoxTexture::is_draw_center_enabled);
-
- ClassDB::bind_method(D_METHOD("set_modulate", "color"), &StyleBoxTexture::set_modulate);
- ClassDB::bind_method(D_METHOD("get_modulate"), &StyleBoxTexture::get_modulate);
-
- ClassDB::bind_method(D_METHOD("set_h_axis_stretch_mode", "mode"), &StyleBoxTexture::set_h_axis_stretch_mode);
- ClassDB::bind_method(D_METHOD("get_h_axis_stretch_mode"), &StyleBoxTexture::get_h_axis_stretch_mode);
-
- ClassDB::bind_method(D_METHOD("set_v_axis_stretch_mode", "mode"), &StyleBoxTexture::set_v_axis_stretch_mode);
- ClassDB::bind_method(D_METHOD("get_v_axis_stretch_mode"), &StyleBoxTexture::get_v_axis_stretch_mode);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
-
- ADD_GROUP("Texture Margins", "texture_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_BOTTOM);
-
- ADD_GROUP("Expand Margins", "expand_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
-
- ADD_GROUP("Axis Stretch", "axis_stretch_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
-
- ADD_GROUP("Sub-Region", "region_");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_region_rect", "get_region_rect");
-
- ADD_GROUP("Modulate", "modulate_");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate_color"), "set_modulate", "get_modulate");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
-
- BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_STRETCH);
- BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE);
- BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE_FIT);
-}
-
-StyleBoxTexture::StyleBoxTexture() {}
-
-StyleBoxTexture::~StyleBoxTexture() {}
-
-////////////////
-
-void StyleBoxFlat::set_bg_color(const Color &p_color) {
- bg_color = p_color;
- emit_changed();
-}
-
-Color StyleBoxFlat::get_bg_color() const {
- return bg_color;
-}
-
-void StyleBoxFlat::set_border_color(const Color &p_color) {
- border_color = p_color;
- emit_changed();
-}
-
-Color StyleBoxFlat::get_border_color() const {
- return border_color;
-}
-
-void StyleBoxFlat::set_border_width_all(int p_size) {
- border_width[0] = p_size;
- border_width[1] = p_size;
- border_width[2] = p_size;
- border_width[3] = p_size;
- emit_changed();
-}
-
-int StyleBoxFlat::get_border_width_min() const {
- return MIN(MIN(border_width[0], border_width[1]), MIN(border_width[2], border_width[3]));
-}
-
-void StyleBoxFlat::set_border_width(Side p_side, int p_width) {
- ERR_FAIL_INDEX((int)p_side, 4);
- border_width[p_side] = p_width;
- emit_changed();
-}
-
-int StyleBoxFlat::get_border_width(Side p_side) const {
- ERR_FAIL_INDEX_V((int)p_side, 4, 0);
- return border_width[p_side];
-}
-
-void StyleBoxFlat::set_border_blend(bool p_blend) {
- blend_border = p_blend;
- emit_changed();
-}
-
-bool StyleBoxFlat::get_border_blend() const {
- return blend_border;
-}
-
-void StyleBoxFlat::set_corner_radius_all(int radius) {
- for (int i = 0; i < 4; i++) {
- corner_radius[i] = radius;
- }
-
- emit_changed();
-}
-
-void StyleBoxFlat::set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_bottom_right, const int radius_bottom_left) {
- corner_radius[0] = radius_top_left;
- corner_radius[1] = radius_top_right;
- corner_radius[2] = radius_bottom_right;
- corner_radius[3] = radius_bottom_left;
-
- emit_changed();
-}
-
-void StyleBoxFlat::set_corner_radius(const Corner p_corner, const int radius) {
- ERR_FAIL_INDEX((int)p_corner, 4);
- corner_radius[p_corner] = radius;
- emit_changed();
-}
-
-int StyleBoxFlat::get_corner_radius(const Corner p_corner) const {
- ERR_FAIL_INDEX_V((int)p_corner, 4, 0);
- return corner_radius[p_corner];
-}
-
-void StyleBoxFlat::set_expand_margin(Side p_side, float p_size) {
- ERR_FAIL_INDEX((int)p_side, 4);
- expand_margin[p_side] = p_size;
- emit_changed();
-}
-
-void StyleBoxFlat::set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
- expand_margin[SIDE_LEFT] = p_left;
- expand_margin[SIDE_TOP] = p_top;
- expand_margin[SIDE_RIGHT] = p_right;
- expand_margin[SIDE_BOTTOM] = p_bottom;
- emit_changed();
-}
-
-void StyleBoxFlat::set_expand_margin_all(float p_expand_margin_size) {
- for (int i = 0; i < 4; i++) {
- expand_margin[i] = p_expand_margin_size;
- }
- emit_changed();
-}
-
-float StyleBoxFlat::get_expand_margin(Side p_side) const {
- ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
- return expand_margin[p_side];
-}
-
-void StyleBoxFlat::set_draw_center(bool p_enabled) {
- draw_center = p_enabled;
- emit_changed();
-}
-
-bool StyleBoxFlat::is_draw_center_enabled() const {
- return draw_center;
-}
-
-void StyleBoxFlat::set_skew(Vector2 p_skew) {
- skew = p_skew;
- emit_changed();
-}
-
-Vector2 StyleBoxFlat::get_skew() const {
- return skew;
-}
-
-void StyleBoxFlat::set_shadow_color(const Color &p_color) {
- shadow_color = p_color;
- emit_changed();
-}
-
-Color StyleBoxFlat::get_shadow_color() const {
- return shadow_color;
-}
-
-void StyleBoxFlat::set_shadow_size(const int &p_size) {
- shadow_size = p_size;
- emit_changed();
-}
-
-int StyleBoxFlat::get_shadow_size() const {
- return shadow_size;
-}
-
-void StyleBoxFlat::set_shadow_offset(const Point2 &p_offset) {
- shadow_offset = p_offset;
- emit_changed();
-}
-
-Point2 StyleBoxFlat::get_shadow_offset() const {
- return shadow_offset;
-}
-
-void StyleBoxFlat::set_anti_aliased(const bool &p_anti_aliased) {
- anti_aliased = p_anti_aliased;
- emit_changed();
- notify_property_list_changed();
-}
-
-bool StyleBoxFlat::is_anti_aliased() const {
- return anti_aliased;
-}
-
-void StyleBoxFlat::set_aa_size(const real_t p_aa_size) {
- aa_size = CLAMP(p_aa_size, 0.01, 10);
- emit_changed();
-}
-
-real_t StyleBoxFlat::get_aa_size() const {
- return aa_size;
-}
-
-void StyleBoxFlat::set_corner_detail(const int &p_corner_detail) {
- corner_detail = CLAMP(p_corner_detail, 1, 20);
- emit_changed();
-}
-
-int StyleBoxFlat::get_corner_detail() const {
- return corner_detail;
-}
-
-inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_rect, const real_t corner_radius[4], real_t *inner_corner_radius) {
- real_t border_left = inner_rect.position.x - style_rect.position.x;
- real_t border_top = inner_rect.position.y - style_rect.position.y;
- real_t border_right = style_rect.size.width - inner_rect.size.width - border_left;
- real_t border_bottom = style_rect.size.height - inner_rect.size.height - border_top;
-
- real_t rad;
-
- // Top left.
- rad = MIN(border_top, border_left);
- inner_corner_radius[0] = MAX(corner_radius[0] - rad, 0);
-
- // Top right;
- rad = MIN(border_top, border_right);
- inner_corner_radius[1] = MAX(corner_radius[1] - rad, 0);
-
- // Bottom right.
- rad = MIN(border_bottom, border_right);
- inner_corner_radius[2] = MAX(corner_radius[2] - rad, 0);
-
- // Bottom left.
- rad = MIN(border_bottom, border_left);
- inner_corner_radius[3] = MAX(corner_radius[3] - rad, 0);
-}
-
-inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 &style_rect, const real_t corner_radius[4],
- const Rect2 &ring_rect, const Rect2 &inner_rect, const Color &inner_color, const Color &outer_color, const int corner_detail, const Vector2 &skew, bool is_filled = false) {
- int vert_offset = verts.size();
- if (!vert_offset) {
- vert_offset = 0;
- }
-
- int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail;
-
- bool draw_border = !is_filled;
-
- real_t ring_corner_radius[4];
- set_inner_corner_radius(style_rect, ring_rect, corner_radius, ring_corner_radius);
-
- // Corner radius center points.
- Vector<Point2> outer_points = {
- ring_rect.position + Vector2(ring_corner_radius[0], ring_corner_radius[0]), //tl
- Point2(ring_rect.position.x + ring_rect.size.x - ring_corner_radius[1], ring_rect.position.y + ring_corner_radius[1]), //tr
- ring_rect.position + ring_rect.size - Vector2(ring_corner_radius[2], ring_corner_radius[2]), //br
- Point2(ring_rect.position.x + ring_corner_radius[3], ring_rect.position.y + ring_rect.size.y - ring_corner_radius[3]) //bl
- };
-
- real_t inner_corner_radius[4];
- set_inner_corner_radius(style_rect, inner_rect, corner_radius, inner_corner_radius);
-
- Vector<Point2> inner_points = {
- inner_rect.position + Vector2(inner_corner_radius[0], inner_corner_radius[0]), //tl
- Point2(inner_rect.position.x + inner_rect.size.x - inner_corner_radius[1], inner_rect.position.y + inner_corner_radius[1]), //tr
- inner_rect.position + inner_rect.size - Vector2(inner_corner_radius[2], inner_corner_radius[2]), //br
- Point2(inner_rect.position.x + inner_corner_radius[3], inner_rect.position.y + inner_rect.size.y - inner_corner_radius[3]) //bl
- };
- // Calculate the vertices.
-
- // If the center is filled, we do not draw the border and directly use the inner ring as reference. Because all calls to this
- // method either draw a ring or a filled rounded rectangle, but not both.
- int max_inner_outer = draw_border ? 2 : 1;
-
- for (int corner_index = 0; corner_index < 4; corner_index++) {
- for (int detail = 0; detail <= adapted_corner_detail; detail++) {
- for (int inner_outer = 0; inner_outer < max_inner_outer; inner_outer++) {
- real_t radius;
- Color color;
- Point2 corner_point;
- if (inner_outer == 0) {
- radius = inner_corner_radius[corner_index];
- color = inner_color;
- corner_point = inner_points[corner_index];
- } else {
- radius = ring_corner_radius[corner_index];
- color = outer_color;
- corner_point = outer_points[corner_index];
- }
-
- const real_t x = radius * (real_t)cos((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.x;
- const real_t y = radius * (real_t)sin((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.y;
- const float x_skew = -skew.x * (y - ring_rect.get_center().y);
- const float y_skew = -skew.y * (x - ring_rect.get_center().x);
- verts.push_back(Vector2(x + x_skew, y + y_skew));
- colors.push_back(color);
- }
- }
- }
-
- int ring_vert_count = verts.size() - vert_offset;
-
- // Fill the indices and the colors for the border.
-
- if (draw_border) {
- for (int i = 0; i < ring_vert_count; i++) {
- indices.push_back(vert_offset + ((i + 0) % ring_vert_count));
- indices.push_back(vert_offset + ((i + 2) % ring_vert_count));
- indices.push_back(vert_offset + ((i + 1) % ring_vert_count));
- }
- }
-
- if (is_filled) {
- // Compute the triangles pattern to draw the rounded rectangle.
- // Consists of vertical stripes of two triangles each.
-
- int stripes_count = ring_vert_count / 2 - 1;
- int last_vert_id = ring_vert_count - 1;
-
- for (int i = 0; i < stripes_count; i++) {
- // Polygon 1.
- indices.push_back(vert_offset + i);
- indices.push_back(vert_offset + last_vert_id - i - 1);
- indices.push_back(vert_offset + i + 1);
- // Polygon 2.
- indices.push_back(vert_offset + i);
- indices.push_back(vert_offset + last_vert_id - 0 - i);
- indices.push_back(vert_offset + last_vert_id - 1 - i);
- }
- }
-}
-
-inline void adapt_values(int p_index_a, int p_index_b, real_t *adapted_values, const real_t *p_values, const real_t p_width, const real_t p_max_a, const real_t p_max_b) {
- if (p_values[p_index_a] + p_values[p_index_b] > p_width) {
- real_t factor;
- real_t new_value;
-
- factor = (real_t)p_width / (real_t)(p_values[p_index_a] + p_values[p_index_b]);
-
- new_value = (p_values[p_index_a] * factor);
- if (new_value < adapted_values[p_index_a]) {
- adapted_values[p_index_a] = new_value;
- }
- new_value = (p_values[p_index_b] * factor);
- if (new_value < adapted_values[p_index_b]) {
- adapted_values[p_index_b] = new_value;
- }
- } else {
- adapted_values[p_index_a] = MIN(p_values[p_index_a], adapted_values[p_index_a]);
- adapted_values[p_index_b] = MIN(p_values[p_index_b], adapted_values[p_index_b]);
- }
- adapted_values[p_index_a] = MIN(p_max_a, adapted_values[p_index_a]);
- adapted_values[p_index_b] = MIN(p_max_b, adapted_values[p_index_b]);
-}
-
-Rect2 StyleBoxFlat::get_draw_rect(const Rect2 &p_rect) const {
- Rect2 draw_rect = p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]);
-
- if (shadow_size > 0) {
- Rect2 shadow_rect = draw_rect.grow(shadow_size);
- shadow_rect.position += shadow_offset;
- draw_rect = draw_rect.merge(shadow_rect);
- }
-
- return draw_rect;
-}
-
-void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
- bool draw_border = (border_width[0] > 0) || (border_width[1] > 0) || (border_width[2] > 0) || (border_width[3] > 0);
- bool draw_shadow = (shadow_size > 0);
- if (!draw_border && !draw_center && !draw_shadow) {
- return;
- }
-
- Rect2 style_rect = p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]);
- if (Math::is_zero_approx(style_rect.size.width) || Math::is_zero_approx(style_rect.size.height)) {
- return;
- }
-
- const bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
- // Only enable antialiasing if it is actually needed. This improve performances
- // and maximizes sharpness for non-skewed StyleBoxes with sharp corners.
- const bool aa_on = (rounded_corners || !skew.is_zero_approx()) && anti_aliased;
-
- const bool blend_on = blend_border && draw_border;
-
- Color border_color_alpha = Color(border_color.r, border_color.g, border_color.b, 0);
- Color border_color_blend = (draw_center ? bg_color : border_color_alpha);
- Color border_color_inner = blend_on ? border_color_blend : border_color;
-
- // Adapt borders (prevent weird overlapping/glitchy drawings).
- real_t width = MAX(style_rect.size.width, 0);
- real_t height = MAX(style_rect.size.height, 0);
- real_t adapted_border[4] = { 1000000.0, 1000000.0, 1000000.0, 1000000.0 };
- adapt_values(SIDE_TOP, SIDE_BOTTOM, adapted_border, border_width, height, height, height);
- adapt_values(SIDE_LEFT, SIDE_RIGHT, adapted_border, border_width, width, width, width);
-
- // Adapt corners (prevent weird overlapping/glitchy drawings).
- real_t adapted_corner[4] = { 1000000.0, 1000000.0, 1000000.0, 1000000.0 };
- adapt_values(CORNER_TOP_RIGHT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]);
- adapt_values(CORNER_TOP_LEFT, CORNER_BOTTOM_LEFT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]);
- adapt_values(CORNER_TOP_LEFT, CORNER_TOP_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[SIDE_RIGHT], width - adapted_border[SIDE_LEFT]);
- adapt_values(CORNER_BOTTOM_LEFT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[SIDE_RIGHT], width - adapted_border[SIDE_LEFT]);
-
- Rect2 infill_rect = style_rect.grow_individual(-adapted_border[SIDE_LEFT], -adapted_border[SIDE_TOP], -adapted_border[SIDE_RIGHT], -adapted_border[SIDE_BOTTOM]);
-
- Rect2 border_style_rect = style_rect;
- if (aa_on) {
- for (int i = 0; i < 4; i++) {
- if (border_width[i] > 0) {
- border_style_rect = border_style_rect.grow_side((Side)i, -aa_size);
- }
- }
- }
-
- Vector<Point2> verts;
- Vector<int> indices;
- Vector<Color> colors;
- Vector<Point2> uvs;
-
- // Create shadow
- if (draw_shadow) {
- Rect2 shadow_inner_rect = style_rect;
- shadow_inner_rect.position += shadow_offset;
-
- Rect2 shadow_rect = style_rect.grow(shadow_size);
- shadow_rect.position += shadow_offset;
-
- Color shadow_color_transparent = Color(shadow_color.r, shadow_color.g, shadow_color.b, 0);
-
- draw_rounded_rectangle(verts, indices, colors, shadow_inner_rect, adapted_corner,
- shadow_rect, shadow_inner_rect, shadow_color, shadow_color_transparent, corner_detail, skew);
-
- if (draw_center) {
- draw_rounded_rectangle(verts, indices, colors, shadow_inner_rect, adapted_corner,
- shadow_inner_rect, shadow_inner_rect, shadow_color, shadow_color, corner_detail, skew, true);
- }
- }
-
- // Create border (no AA).
- if (draw_border && !aa_on) {
- draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
- border_style_rect, infill_rect, border_color_inner, border_color, corner_detail, skew);
- }
-
- // Create infill (no AA).
- if (draw_center && (!aa_on || blend_on)) {
- draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
- infill_rect, infill_rect, bg_color, bg_color, corner_detail, skew, true);
- }
-
- if (aa_on) {
- real_t aa_border_width[4];
- real_t aa_border_width_half[4];
- real_t aa_fill_width[4];
- real_t aa_fill_width_half[4];
- if (draw_border) {
- for (int i = 0; i < 4; i++) {
- if (border_width[i] > 0) {
- aa_border_width[i] = aa_size;
- aa_border_width_half[i] = aa_size / 2;
- aa_fill_width[i] = 0;
- aa_fill_width_half[i] = 0;
- } else {
- aa_border_width[i] = 0;
- aa_border_width_half[i] = 0;
- aa_fill_width[i] = aa_size;
- aa_fill_width_half[i] = aa_size / 2;
- }
- }
- } else {
- for (int i = 0; i < 4; i++) {
- aa_border_width[i] = 0;
- aa_border_width_half[i] = 0;
- aa_fill_width[i] = aa_size;
- aa_fill_width_half[i] = aa_size / 2;
- }
- }
-
- if (draw_center) {
- // Infill rect, transparent side of antialiasing gradient (base infill rect enlarged by AA size)
- Rect2 infill_rect_aa_transparent = infill_rect.grow_individual(aa_fill_width_half[SIDE_LEFT], aa_fill_width_half[SIDE_TOP],
- aa_fill_width_half[SIDE_RIGHT], aa_fill_width_half[SIDE_BOTTOM]);
- // Infill rect, colored side of antialiasing gradient (base infill rect shrunk by AA size)
- Rect2 infill_rect_aa_colored = infill_rect_aa_transparent.grow_individual(-aa_fill_width[SIDE_LEFT], -aa_fill_width[SIDE_TOP],
- -aa_fill_width[SIDE_RIGHT], -aa_fill_width[SIDE_BOTTOM]);
- if (!blend_on) {
- // Create center fill, not antialiased yet
- draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
- infill_rect_aa_colored, infill_rect_aa_colored, bg_color, bg_color, corner_detail, skew, true);
- }
- if (!blend_on || !draw_border) {
- Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0);
- // Add antialiasing on the center fill
- draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
- infill_rect_aa_transparent, infill_rect_aa_colored, bg_color, alpha_bg, corner_detail, skew);
- }
- }
-
- if (draw_border) {
- // Inner border recct, fully colored side of antialiasing gradient (base inner rect enlarged by AA size)
- Rect2 inner_rect_aa_colored = infill_rect.grow_individual(aa_border_width_half[SIDE_LEFT], aa_border_width_half[SIDE_TOP],
- aa_border_width_half[SIDE_RIGHT], aa_border_width_half[SIDE_BOTTOM]);
- // Inner border rect, transparent side of antialiasing gradient (base inner rect shrunk by AA size)
- Rect2 inner_rect_aa_transparent = inner_rect_aa_colored.grow_individual(-aa_border_width[SIDE_LEFT], -aa_border_width[SIDE_TOP],
- -aa_border_width[SIDE_RIGHT], -aa_border_width[SIDE_BOTTOM]);
- // Outer border rect, transparent side of antialiasing gradient (base outer rect enlarged by AA size)
- Rect2 outer_rect_aa_transparent = style_rect.grow_individual(aa_border_width_half[SIDE_LEFT], aa_border_width_half[SIDE_TOP],
- aa_border_width_half[SIDE_RIGHT], aa_border_width_half[SIDE_BOTTOM]);
- // Outer border rect, colored side of antialiasing gradient (base outer rect shrunk by AA size)
- Rect2 outer_rect_aa_colored = border_style_rect.grow_individual(aa_border_width_half[SIDE_LEFT], aa_border_width_half[SIDE_TOP],
- aa_border_width_half[SIDE_RIGHT], aa_border_width_half[SIDE_BOTTOM]);
-
- // Create border ring, not antialiased yet
- draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
- outer_rect_aa_colored, ((blend_on) ? infill_rect : inner_rect_aa_colored), border_color_inner, border_color, corner_detail, skew);
- if (!blend_on) {
- // Add antialiasing on the ring inner border
- draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
- inner_rect_aa_colored, inner_rect_aa_transparent, border_color_blend, border_color, corner_detail, skew);
- }
- // Add antialiasing on the ring outer border
- draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
- outer_rect_aa_transparent, outer_rect_aa_colored, border_color, border_color_alpha, corner_detail, skew);
- }
- }
-
- // Compute UV coordinates.
- Rect2 uv_rect = style_rect.grow(aa_on ? aa_size : 0);
- uvs.resize(verts.size());
- for (int i = 0; i < verts.size(); i++) {
- uvs.write[i].x = (verts[i].x - uv_rect.position.x) / uv_rect.size.width;
- uvs.write[i].y = (verts[i].y - uv_rect.position.y) / uv_rect.size.height;
- }
-
- // Draw stylebox.
- RenderingServer *vs = RenderingServer::get_singleton();
- vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors, uvs);
-}
-
-float StyleBoxFlat::get_style_margin(Side p_side) const {
- ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
- return border_width[p_side];
-}
-
-void StyleBoxFlat::_validate_property(PropertyInfo &p_property) const {
- if (!anti_aliased && p_property.name == "anti_aliasing_size") {
- p_property.usage = PROPERTY_USAGE_NO_EDITOR;
- }
-}
-
-void StyleBoxFlat::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &StyleBoxFlat::set_bg_color);
- ClassDB::bind_method(D_METHOD("get_bg_color"), &StyleBoxFlat::get_bg_color);
-
- ClassDB::bind_method(D_METHOD("set_border_color", "color"), &StyleBoxFlat::set_border_color);
- ClassDB::bind_method(D_METHOD("get_border_color"), &StyleBoxFlat::get_border_color);
-
- ClassDB::bind_method(D_METHOD("set_border_width_all", "width"), &StyleBoxFlat::set_border_width_all);
- ClassDB::bind_method(D_METHOD("get_border_width_min"), &StyleBoxFlat::get_border_width_min);
-
- ClassDB::bind_method(D_METHOD("set_border_width", "margin", "width"), &StyleBoxFlat::set_border_width);
- ClassDB::bind_method(D_METHOD("get_border_width", "margin"), &StyleBoxFlat::get_border_width);
-
- ClassDB::bind_method(D_METHOD("set_border_blend", "blend"), &StyleBoxFlat::set_border_blend);
- ClassDB::bind_method(D_METHOD("get_border_blend"), &StyleBoxFlat::get_border_blend);
-
- ClassDB::bind_method(D_METHOD("set_corner_radius_all", "radius"), &StyleBoxFlat::set_corner_radius_all);
-
- ClassDB::bind_method(D_METHOD("set_corner_radius", "corner", "radius"), &StyleBoxFlat::set_corner_radius);
- ClassDB::bind_method(D_METHOD("get_corner_radius", "corner"), &StyleBoxFlat::get_corner_radius);
-
- ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin);
- ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_all);
- ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin);
-
- ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center);
- ClassDB::bind_method(D_METHOD("is_draw_center_enabled"), &StyleBoxFlat::is_draw_center_enabled);
-
- ClassDB::bind_method(D_METHOD("set_skew", "skew"), &StyleBoxFlat::set_skew);
- ClassDB::bind_method(D_METHOD("get_skew"), &StyleBoxFlat::get_skew);
-
- ClassDB::bind_method(D_METHOD("set_shadow_color", "color"), &StyleBoxFlat::set_shadow_color);
- ClassDB::bind_method(D_METHOD("get_shadow_color"), &StyleBoxFlat::get_shadow_color);
-
- ClassDB::bind_method(D_METHOD("set_shadow_size", "size"), &StyleBoxFlat::set_shadow_size);
- ClassDB::bind_method(D_METHOD("get_shadow_size"), &StyleBoxFlat::get_shadow_size);
-
- ClassDB::bind_method(D_METHOD("set_shadow_offset", "offset"), &StyleBoxFlat::set_shadow_offset);
- ClassDB::bind_method(D_METHOD("get_shadow_offset"), &StyleBoxFlat::get_shadow_offset);
-
- ClassDB::bind_method(D_METHOD("set_anti_aliased", "anti_aliased"), &StyleBoxFlat::set_anti_aliased);
- ClassDB::bind_method(D_METHOD("is_anti_aliased"), &StyleBoxFlat::is_anti_aliased);
-
- ClassDB::bind_method(D_METHOD("set_aa_size", "size"), &StyleBoxFlat::set_aa_size);
- ClassDB::bind_method(D_METHOD("get_aa_size"), &StyleBoxFlat::get_aa_size);
-
- ClassDB::bind_method(D_METHOD("set_corner_detail", "detail"), &StyleBoxFlat::set_corner_detail);
- ClassDB::bind_method(D_METHOD("get_corner_detail"), &StyleBoxFlat::get_corner_detail);
-
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "bg_color"), "set_bg_color", "get_bg_color");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "skew"), "set_skew", "get_skew");
-
- ADD_GROUP("Border Width", "border_width_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_BOTTOM);
-
- ADD_GROUP("Border", "border_");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "border_blend"), "set_border_blend", "get_border_blend");
-
- ADD_GROUP("Corner Radius", "corner_radius_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail");
-
- ADD_GROUP("Expand Margins", "expand_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
-
- ADD_GROUP("Shadow", "shadow_");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_shadow_size", "get_shadow_size");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_shadow_offset", "get_shadow_offset");
-
- ADD_GROUP("Anti Aliasing", "anti_aliasing_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "anti_aliasing"), "set_anti_aliased", "is_anti_aliased");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "0.01,10,0.001,suffix:px"), "set_aa_size", "get_aa_size");
-}
-
-StyleBoxFlat::StyleBoxFlat() {}
-
-StyleBoxFlat::~StyleBoxFlat() {}
-
-void StyleBoxLine::set_color(const Color &p_color) {
- color = p_color;
- emit_changed();
-}
-
-Color StyleBoxLine::get_color() const {
- return color;
-}
-
-void StyleBoxLine::set_thickness(int p_thickness) {
- thickness = p_thickness;
- emit_changed();
-}
-
-int StyleBoxLine::get_thickness() const {
- return thickness;
-}
-
-void StyleBoxLine::set_vertical(bool p_vertical) {
- vertical = p_vertical;
- emit_changed();
-}
-
-bool StyleBoxLine::is_vertical() const {
- return vertical;
-}
-
-void StyleBoxLine::set_grow_end(float p_grow_end) {
- grow_end = p_grow_end;
- emit_changed();
-}
-
-float StyleBoxLine::get_grow_end() const {
- return grow_end;
-}
-
-void StyleBoxLine::set_grow_begin(float p_grow_begin) {
- grow_begin = p_grow_begin;
- emit_changed();
-}
-
-float StyleBoxLine::get_grow_begin() const {
- return grow_begin;
-}
-
-void StyleBoxLine::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_color", "color"), &StyleBoxLine::set_color);
- ClassDB::bind_method(D_METHOD("get_color"), &StyleBoxLine::get_color);
- ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &StyleBoxLine::set_thickness);
- ClassDB::bind_method(D_METHOD("get_thickness"), &StyleBoxLine::get_thickness);
- ClassDB::bind_method(D_METHOD("set_grow_begin", "offset"), &StyleBoxLine::set_grow_begin);
- ClassDB::bind_method(D_METHOD("get_grow_begin"), &StyleBoxLine::get_grow_begin);
- ClassDB::bind_method(D_METHOD("set_grow_end", "offset"), &StyleBoxLine::set_grow_end);
- ClassDB::bind_method(D_METHOD("get_grow_end"), &StyleBoxLine::get_grow_end);
- ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &StyleBoxLine::set_vertical);
- ClassDB::bind_method(D_METHOD("is_vertical"), &StyleBoxLine::is_vertical);
-
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_begin", "get_grow_begin");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_end", "get_grow_end");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,100,suffix:px"), "set_thickness", "get_thickness");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
-}
-
-float StyleBoxLine::get_style_margin(Side p_side) const {
- ERR_FAIL_INDEX_V((int)p_side, 4, 0);
-
- if (vertical) {
- if (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) {
- return thickness / 2.0;
- }
- } else if (p_side == SIDE_TOP || p_side == SIDE_BOTTOM) {
- return thickness / 2.0;
- }
-
- return 0;
-}
-
-void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const {
- RenderingServer *vs = RenderingServer::get_singleton();
- Rect2i r = p_rect;
-
- if (vertical) {
- r.position.y -= grow_begin;
- r.size.y += (grow_begin + grow_end);
- r.size.x = thickness;
- } else {
- r.position.x -= grow_begin;
- r.size.x += (grow_begin + grow_end);
- r.size.y = thickness;
- }
-
- vs->canvas_item_add_rect(p_canvas_item, r, color);
-}
-
-StyleBoxLine::StyleBoxLine() {}
-
-StyleBoxLine::~StyleBoxLine() {}
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 9d96e9a3b7..3f9a96be2f 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -32,8 +32,9 @@
#define STYLE_BOX_H
#include "core/io/resource.h"
-#include "scene/resources/texture.h"
-#include "servers/rendering_server.h"
+#include "core/object/class_db.h"
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
class CanvasItem;
@@ -41,11 +42,12 @@ class StyleBox : public Resource {
GDCLASS(StyleBox, Resource);
RES_BASE_EXTENSION("stylebox");
OBJ_SAVE_TYPE(StyleBox);
+
float content_margin[4];
protected:
- virtual float get_style_margin(Side p_side) const { return 0; }
static void _bind_methods();
+ virtual float get_style_margin(Side p_side) const { return 0; }
GDVIRTUAL2C(_draw, RID, Rect2)
GDVIRTUAL1RC(Rect2, _get_draw_rect, Rect2)
@@ -82,184 +84,4 @@ public:
StyleBoxEmpty() {}
};
-class StyleBoxTexture : public StyleBox {
- GDCLASS(StyleBoxTexture, StyleBox);
-
-public:
- enum AxisStretchMode {
- AXIS_STRETCH_MODE_STRETCH,
- AXIS_STRETCH_MODE_TILE,
- AXIS_STRETCH_MODE_TILE_FIT,
- };
-
-private:
- float expand_margin[4] = {};
- float texture_margin[4] = {};
- Rect2 region_rect;
- Ref<Texture2D> texture;
- bool draw_center = true;
- Color modulate = Color(1, 1, 1, 1);
- AxisStretchMode axis_h = AXIS_STRETCH_MODE_STRETCH;
- AxisStretchMode axis_v = AXIS_STRETCH_MODE_STRETCH;
-
-protected:
- virtual float get_style_margin(Side p_side) const override;
- static void _bind_methods();
-
-public:
- void set_expand_margin(Side p_expand_side, float p_size);
- void set_expand_margin_all(float p_expand_margin_size);
- void set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
- float get_expand_margin(Side p_expand_side) const;
-
- void set_texture_margin(Side p_side, float p_size);
- void set_texture_margin_all(float p_size);
- void set_texture_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
- float get_texture_margin(Side p_side) const;
-
- void set_region_rect(const Rect2 &p_region_rect);
- Rect2 get_region_rect() const;
-
- void set_texture(Ref<Texture2D> p_texture);
- Ref<Texture2D> get_texture() const;
-
- void set_draw_center(bool p_enabled);
- bool is_draw_center_enabled() const;
-
- void set_h_axis_stretch_mode(AxisStretchMode p_mode);
- AxisStretchMode get_h_axis_stretch_mode() const;
-
- void set_v_axis_stretch_mode(AxisStretchMode p_mode);
- AxisStretchMode get_v_axis_stretch_mode() const;
-
- void set_modulate(const Color &p_modulate);
- Color get_modulate() const;
-
- virtual Rect2 get_draw_rect(const Rect2 &p_rect) const override;
- virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override;
-
- StyleBoxTexture();
- ~StyleBoxTexture();
-};
-
-VARIANT_ENUM_CAST(StyleBoxTexture::AxisStretchMode)
-
-class StyleBoxFlat : public StyleBox {
- GDCLASS(StyleBoxFlat, StyleBox);
-
- Color bg_color = Color(0.6, 0.6, 0.6);
- Color shadow_color = Color(0, 0, 0, 0.6);
- Color border_color = Color(0.8, 0.8, 0.8);
-
- real_t border_width[4] = {};
- real_t expand_margin[4] = {};
- real_t corner_radius[4] = {};
-
- bool draw_center = true;
- bool blend_border = false;
- Vector2 skew;
- bool anti_aliased = true;
-
- int corner_detail = 8;
- int shadow_size = 0;
- Point2 shadow_offset;
- real_t aa_size = 1;
-
-protected:
- virtual float get_style_margin(Side p_side) const override;
- static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const;
-
-public:
- void set_bg_color(const Color &p_color);
- Color get_bg_color() const;
-
- void set_border_color(const Color &p_color);
- Color get_border_color() const;
-
- void set_border_width_all(int p_size);
- int get_border_width_min() const;
-
- void set_border_width(Side p_side, int p_width);
- int get_border_width(Side p_side) const;
-
- void set_border_blend(bool p_blend);
- bool get_border_blend() const;
-
- void set_corner_radius_all(int radius);
- void set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_bottom_right, const int radius_bottom_left);
-
- void set_corner_radius(Corner p_corner, const int radius);
- int get_corner_radius(Corner p_corner) const;
-
- void set_corner_detail(const int &p_corner_detail);
- int get_corner_detail() const;
-
- void set_expand_margin(Side p_expand_side, float p_size);
- void set_expand_margin_all(float p_expand_margin_size);
- void set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
- float get_expand_margin(Side p_expand_side) const;
-
- void set_draw_center(bool p_enabled);
- bool is_draw_center_enabled() const;
-
- void set_skew(Vector2 p_skew);
- Vector2 get_skew() const;
-
- void set_shadow_color(const Color &p_color);
- Color get_shadow_color() const;
-
- void set_shadow_size(const int &p_size);
- int get_shadow_size() const;
-
- void set_shadow_offset(const Point2 &p_offset);
- Point2 get_shadow_offset() const;
-
- void set_anti_aliased(const bool &p_anti_aliased);
- bool is_anti_aliased() const;
- void set_aa_size(const real_t p_aa_size);
- real_t get_aa_size() const;
-
- virtual Rect2 get_draw_rect(const Rect2 &p_rect) const override;
- virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override;
-
- StyleBoxFlat();
- ~StyleBoxFlat();
-};
-
-// Just used to draw lines.
-class StyleBoxLine : public StyleBox {
- GDCLASS(StyleBoxLine, StyleBox);
- Color color;
- int thickness = 1;
- bool vertical = false;
- float grow_begin = 1.0;
- float grow_end = 1.0;
-
-protected:
- virtual float get_style_margin(Side p_side) const override;
- static void _bind_methods();
-
-public:
- void set_color(const Color &p_color);
- Color get_color() const;
-
- void set_thickness(int p_thickness);
- int get_thickness() const;
-
- void set_vertical(bool p_vertical);
- bool is_vertical() const;
-
- void set_grow_begin(float p_grow);
- float get_grow_begin() const;
-
- void set_grow_end(float p_grow);
- float get_grow_end() const;
-
- virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override;
-
- StyleBoxLine();
- ~StyleBoxLine();
-};
-
#endif // STYLE_BOX_H
diff --git a/scene/resources/style_box_flat.cpp b/scene/resources/style_box_flat.cpp
new file mode 100644
index 0000000000..52d02e92cb
--- /dev/null
+++ b/scene/resources/style_box_flat.cpp
@@ -0,0 +1,642 @@
+/**************************************************************************/
+/* style_box_flat.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 "style_box_flat.h"
+
+#include "servers/rendering_server.h"
+
+float StyleBoxFlat::get_style_margin(Side p_side) const {
+ ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
+ return border_width[p_side];
+}
+
+void StyleBoxFlat::_validate_property(PropertyInfo &p_property) const {
+ if (!anti_aliased && p_property.name == "anti_aliasing_size") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+}
+
+void StyleBoxFlat::set_bg_color(const Color &p_color) {
+ bg_color = p_color;
+ emit_changed();
+}
+
+Color StyleBoxFlat::get_bg_color() const {
+ return bg_color;
+}
+
+void StyleBoxFlat::set_border_color(const Color &p_color) {
+ border_color = p_color;
+ emit_changed();
+}
+
+Color StyleBoxFlat::get_border_color() const {
+ return border_color;
+}
+
+void StyleBoxFlat::set_border_width_all(int p_size) {
+ border_width[0] = p_size;
+ border_width[1] = p_size;
+ border_width[2] = p_size;
+ border_width[3] = p_size;
+ emit_changed();
+}
+
+int StyleBoxFlat::get_border_width_min() const {
+ return MIN(MIN(border_width[0], border_width[1]), MIN(border_width[2], border_width[3]));
+}
+
+void StyleBoxFlat::set_border_width(Side p_side, int p_width) {
+ ERR_FAIL_INDEX((int)p_side, 4);
+ border_width[p_side] = p_width;
+ emit_changed();
+}
+
+int StyleBoxFlat::get_border_width(Side p_side) const {
+ ERR_FAIL_INDEX_V((int)p_side, 4, 0);
+ return border_width[p_side];
+}
+
+void StyleBoxFlat::set_border_blend(bool p_blend) {
+ blend_border = p_blend;
+ emit_changed();
+}
+
+bool StyleBoxFlat::get_border_blend() const {
+ return blend_border;
+}
+
+void StyleBoxFlat::set_corner_radius(const Corner p_corner, const int radius) {
+ ERR_FAIL_INDEX((int)p_corner, 4);
+ corner_radius[p_corner] = radius;
+ emit_changed();
+}
+
+void StyleBoxFlat::set_corner_radius_all(int radius) {
+ for (int i = 0; i < 4; i++) {
+ corner_radius[i] = radius;
+ }
+
+ emit_changed();
+}
+
+void StyleBoxFlat::set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_bottom_right, const int radius_bottom_left) {
+ corner_radius[0] = radius_top_left;
+ corner_radius[1] = radius_top_right;
+ corner_radius[2] = radius_bottom_right;
+ corner_radius[3] = radius_bottom_left;
+
+ emit_changed();
+}
+
+int StyleBoxFlat::get_corner_radius(const Corner p_corner) const {
+ ERR_FAIL_INDEX_V((int)p_corner, 4, 0);
+ return corner_radius[p_corner];
+}
+
+void StyleBoxFlat::set_corner_detail(const int &p_corner_detail) {
+ corner_detail = CLAMP(p_corner_detail, 1, 20);
+ emit_changed();
+}
+
+int StyleBoxFlat::get_corner_detail() const {
+ return corner_detail;
+}
+
+void StyleBoxFlat::set_expand_margin(Side p_side, float p_size) {
+ ERR_FAIL_INDEX((int)p_side, 4);
+ expand_margin[p_side] = p_size;
+ emit_changed();
+}
+
+void StyleBoxFlat::set_expand_margin_all(float p_expand_margin_size) {
+ for (int i = 0; i < 4; i++) {
+ expand_margin[i] = p_expand_margin_size;
+ }
+ emit_changed();
+}
+
+void StyleBoxFlat::set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ expand_margin[SIDE_LEFT] = p_left;
+ expand_margin[SIDE_TOP] = p_top;
+ expand_margin[SIDE_RIGHT] = p_right;
+ expand_margin[SIDE_BOTTOM] = p_bottom;
+ emit_changed();
+}
+
+float StyleBoxFlat::get_expand_margin(Side p_side) const {
+ ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
+ return expand_margin[p_side];
+}
+
+void StyleBoxFlat::set_draw_center(bool p_enabled) {
+ draw_center = p_enabled;
+ emit_changed();
+}
+
+bool StyleBoxFlat::is_draw_center_enabled() const {
+ return draw_center;
+}
+
+void StyleBoxFlat::set_skew(Vector2 p_skew) {
+ skew = p_skew;
+ emit_changed();
+}
+
+Vector2 StyleBoxFlat::get_skew() const {
+ return skew;
+}
+
+void StyleBoxFlat::set_shadow_color(const Color &p_color) {
+ shadow_color = p_color;
+ emit_changed();
+}
+
+Color StyleBoxFlat::get_shadow_color() const {
+ return shadow_color;
+}
+
+void StyleBoxFlat::set_shadow_size(const int &p_size) {
+ shadow_size = p_size;
+ emit_changed();
+}
+
+int StyleBoxFlat::get_shadow_size() const {
+ return shadow_size;
+}
+
+void StyleBoxFlat::set_shadow_offset(const Point2 &p_offset) {
+ shadow_offset = p_offset;
+ emit_changed();
+}
+
+Point2 StyleBoxFlat::get_shadow_offset() const {
+ return shadow_offset;
+}
+
+void StyleBoxFlat::set_anti_aliased(const bool &p_anti_aliased) {
+ anti_aliased = p_anti_aliased;
+ emit_changed();
+ notify_property_list_changed();
+}
+
+bool StyleBoxFlat::is_anti_aliased() const {
+ return anti_aliased;
+}
+
+void StyleBoxFlat::set_aa_size(const real_t p_aa_size) {
+ aa_size = CLAMP(p_aa_size, 0.01, 10);
+ emit_changed();
+}
+
+real_t StyleBoxFlat::get_aa_size() const {
+ return aa_size;
+}
+
+inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_rect, const real_t corner_radius[4], real_t *inner_corner_radius) {
+ real_t border_left = inner_rect.position.x - style_rect.position.x;
+ real_t border_top = inner_rect.position.y - style_rect.position.y;
+ real_t border_right = style_rect.size.width - inner_rect.size.width - border_left;
+ real_t border_bottom = style_rect.size.height - inner_rect.size.height - border_top;
+
+ real_t rad;
+
+ // Top left.
+ rad = MIN(border_top, border_left);
+ inner_corner_radius[0] = MAX(corner_radius[0] - rad, 0);
+
+ // Top right;
+ rad = MIN(border_top, border_right);
+ inner_corner_radius[1] = MAX(corner_radius[1] - rad, 0);
+
+ // Bottom right.
+ rad = MIN(border_bottom, border_right);
+ inner_corner_radius[2] = MAX(corner_radius[2] - rad, 0);
+
+ // Bottom left.
+ rad = MIN(border_bottom, border_left);
+ inner_corner_radius[3] = MAX(corner_radius[3] - rad, 0);
+}
+
+inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 &style_rect, const real_t corner_radius[4],
+ const Rect2 &ring_rect, const Rect2 &inner_rect, const Color &inner_color, const Color &outer_color, const int corner_detail, const Vector2 &skew, bool is_filled = false) {
+ int vert_offset = verts.size();
+ if (!vert_offset) {
+ vert_offset = 0;
+ }
+
+ int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail;
+
+ bool draw_border = !is_filled;
+
+ real_t ring_corner_radius[4];
+ set_inner_corner_radius(style_rect, ring_rect, corner_radius, ring_corner_radius);
+
+ // Corner radius center points.
+ Vector<Point2> outer_points = {
+ ring_rect.position + Vector2(ring_corner_radius[0], ring_corner_radius[0]), //tl
+ Point2(ring_rect.position.x + ring_rect.size.x - ring_corner_radius[1], ring_rect.position.y + ring_corner_radius[1]), //tr
+ ring_rect.position + ring_rect.size - Vector2(ring_corner_radius[2], ring_corner_radius[2]), //br
+ Point2(ring_rect.position.x + ring_corner_radius[3], ring_rect.position.y + ring_rect.size.y - ring_corner_radius[3]) //bl
+ };
+
+ real_t inner_corner_radius[4];
+ set_inner_corner_radius(style_rect, inner_rect, corner_radius, inner_corner_radius);
+
+ Vector<Point2> inner_points = {
+ inner_rect.position + Vector2(inner_corner_radius[0], inner_corner_radius[0]), //tl
+ Point2(inner_rect.position.x + inner_rect.size.x - inner_corner_radius[1], inner_rect.position.y + inner_corner_radius[1]), //tr
+ inner_rect.position + inner_rect.size - Vector2(inner_corner_radius[2], inner_corner_radius[2]), //br
+ Point2(inner_rect.position.x + inner_corner_radius[3], inner_rect.position.y + inner_rect.size.y - inner_corner_radius[3]) //bl
+ };
+ // Calculate the vertices.
+
+ // If the center is filled, we do not draw the border and directly use the inner ring as reference. Because all calls to this
+ // method either draw a ring or a filled rounded rectangle, but not both.
+ int max_inner_outer = draw_border ? 2 : 1;
+
+ for (int corner_index = 0; corner_index < 4; corner_index++) {
+ for (int detail = 0; detail <= adapted_corner_detail; detail++) {
+ for (int inner_outer = 0; inner_outer < max_inner_outer; inner_outer++) {
+ real_t radius;
+ Color color;
+ Point2 corner_point;
+ if (inner_outer == 0) {
+ radius = inner_corner_radius[corner_index];
+ color = inner_color;
+ corner_point = inner_points[corner_index];
+ } else {
+ radius = ring_corner_radius[corner_index];
+ color = outer_color;
+ corner_point = outer_points[corner_index];
+ }
+
+ const real_t x = radius * (real_t)cos((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.x;
+ const real_t y = radius * (real_t)sin((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.y;
+ const float x_skew = -skew.x * (y - ring_rect.get_center().y);
+ const float y_skew = -skew.y * (x - ring_rect.get_center().x);
+ verts.push_back(Vector2(x + x_skew, y + y_skew));
+ colors.push_back(color);
+ }
+ }
+ }
+
+ int ring_vert_count = verts.size() - vert_offset;
+
+ // Fill the indices and the colors for the border.
+
+ if (draw_border) {
+ for (int i = 0; i < ring_vert_count; i++) {
+ indices.push_back(vert_offset + ((i + 0) % ring_vert_count));
+ indices.push_back(vert_offset + ((i + 2) % ring_vert_count));
+ indices.push_back(vert_offset + ((i + 1) % ring_vert_count));
+ }
+ }
+
+ if (is_filled) {
+ // Compute the triangles pattern to draw the rounded rectangle.
+ // Consists of vertical stripes of two triangles each.
+
+ int stripes_count = ring_vert_count / 2 - 1;
+ int last_vert_id = ring_vert_count - 1;
+
+ for (int i = 0; i < stripes_count; i++) {
+ // Polygon 1.
+ indices.push_back(vert_offset + i);
+ indices.push_back(vert_offset + last_vert_id - i - 1);
+ indices.push_back(vert_offset + i + 1);
+ // Polygon 2.
+ indices.push_back(vert_offset + i);
+ indices.push_back(vert_offset + last_vert_id - 0 - i);
+ indices.push_back(vert_offset + last_vert_id - 1 - i);
+ }
+ }
+}
+
+inline void adapt_values(int p_index_a, int p_index_b, real_t *adapted_values, const real_t *p_values, const real_t p_width, const real_t p_max_a, const real_t p_max_b) {
+ if (p_values[p_index_a] + p_values[p_index_b] > p_width) {
+ real_t factor;
+ real_t new_value;
+
+ factor = (real_t)p_width / (real_t)(p_values[p_index_a] + p_values[p_index_b]);
+
+ new_value = (p_values[p_index_a] * factor);
+ if (new_value < adapted_values[p_index_a]) {
+ adapted_values[p_index_a] = new_value;
+ }
+ new_value = (p_values[p_index_b] * factor);
+ if (new_value < adapted_values[p_index_b]) {
+ adapted_values[p_index_b] = new_value;
+ }
+ } else {
+ adapted_values[p_index_a] = MIN(p_values[p_index_a], adapted_values[p_index_a]);
+ adapted_values[p_index_b] = MIN(p_values[p_index_b], adapted_values[p_index_b]);
+ }
+ adapted_values[p_index_a] = MIN(p_max_a, adapted_values[p_index_a]);
+ adapted_values[p_index_b] = MIN(p_max_b, adapted_values[p_index_b]);
+}
+
+Rect2 StyleBoxFlat::get_draw_rect(const Rect2 &p_rect) const {
+ Rect2 draw_rect = p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]);
+
+ if (shadow_size > 0) {
+ Rect2 shadow_rect = draw_rect.grow(shadow_size);
+ shadow_rect.position += shadow_offset;
+ draw_rect = draw_rect.merge(shadow_rect);
+ }
+
+ return draw_rect;
+}
+
+void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
+ bool draw_border = (border_width[0] > 0) || (border_width[1] > 0) || (border_width[2] > 0) || (border_width[3] > 0);
+ bool draw_shadow = (shadow_size > 0);
+ if (!draw_border && !draw_center && !draw_shadow) {
+ return;
+ }
+
+ Rect2 style_rect = p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]);
+ if (Math::is_zero_approx(style_rect.size.width) || Math::is_zero_approx(style_rect.size.height)) {
+ return;
+ }
+
+ const bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
+ // Only enable antialiasing if it is actually needed. This improve performances
+ // and maximizes sharpness for non-skewed StyleBoxes with sharp corners.
+ const bool aa_on = (rounded_corners || !skew.is_zero_approx()) && anti_aliased;
+
+ const bool blend_on = blend_border && draw_border;
+
+ Color border_color_alpha = Color(border_color.r, border_color.g, border_color.b, 0);
+ Color border_color_blend = (draw_center ? bg_color : border_color_alpha);
+ Color border_color_inner = blend_on ? border_color_blend : border_color;
+
+ // Adapt borders (prevent weird overlapping/glitchy drawings).
+ real_t width = MAX(style_rect.size.width, 0);
+ real_t height = MAX(style_rect.size.height, 0);
+ real_t adapted_border[4] = { 1000000.0, 1000000.0, 1000000.0, 1000000.0 };
+ adapt_values(SIDE_TOP, SIDE_BOTTOM, adapted_border, border_width, height, height, height);
+ adapt_values(SIDE_LEFT, SIDE_RIGHT, adapted_border, border_width, width, width, width);
+
+ // Adapt corners (prevent weird overlapping/glitchy drawings).
+ real_t adapted_corner[4] = { 1000000.0, 1000000.0, 1000000.0, 1000000.0 };
+ adapt_values(CORNER_TOP_RIGHT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]);
+ adapt_values(CORNER_TOP_LEFT, CORNER_BOTTOM_LEFT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]);
+ adapt_values(CORNER_TOP_LEFT, CORNER_TOP_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[SIDE_RIGHT], width - adapted_border[SIDE_LEFT]);
+ adapt_values(CORNER_BOTTOM_LEFT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[SIDE_RIGHT], width - adapted_border[SIDE_LEFT]);
+
+ Rect2 infill_rect = style_rect.grow_individual(-adapted_border[SIDE_LEFT], -adapted_border[SIDE_TOP], -adapted_border[SIDE_RIGHT], -adapted_border[SIDE_BOTTOM]);
+
+ Rect2 border_style_rect = style_rect;
+ if (aa_on) {
+ for (int i = 0; i < 4; i++) {
+ if (border_width[i] > 0) {
+ border_style_rect = border_style_rect.grow_side((Side)i, -aa_size);
+ }
+ }
+ }
+
+ Vector<Point2> verts;
+ Vector<int> indices;
+ Vector<Color> colors;
+ Vector<Point2> uvs;
+
+ // Create shadow
+ if (draw_shadow) {
+ Rect2 shadow_inner_rect = style_rect;
+ shadow_inner_rect.position += shadow_offset;
+
+ Rect2 shadow_rect = style_rect.grow(shadow_size);
+ shadow_rect.position += shadow_offset;
+
+ Color shadow_color_transparent = Color(shadow_color.r, shadow_color.g, shadow_color.b, 0);
+
+ draw_rounded_rectangle(verts, indices, colors, shadow_inner_rect, adapted_corner,
+ shadow_rect, shadow_inner_rect, shadow_color, shadow_color_transparent, corner_detail, skew);
+
+ if (draw_center) {
+ draw_rounded_rectangle(verts, indices, colors, shadow_inner_rect, adapted_corner,
+ shadow_inner_rect, shadow_inner_rect, shadow_color, shadow_color, corner_detail, skew, true);
+ }
+ }
+
+ // Create border (no AA).
+ if (draw_border && !aa_on) {
+ draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
+ border_style_rect, infill_rect, border_color_inner, border_color, corner_detail, skew);
+ }
+
+ // Create infill (no AA).
+ if (draw_center && (!aa_on || blend_on)) {
+ draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
+ infill_rect, infill_rect, bg_color, bg_color, corner_detail, skew, true);
+ }
+
+ if (aa_on) {
+ real_t aa_border_width[4];
+ real_t aa_border_width_half[4];
+ real_t aa_fill_width[4];
+ real_t aa_fill_width_half[4];
+ if (draw_border) {
+ for (int i = 0; i < 4; i++) {
+ if (border_width[i] > 0) {
+ aa_border_width[i] = aa_size;
+ aa_border_width_half[i] = aa_size / 2;
+ aa_fill_width[i] = 0;
+ aa_fill_width_half[i] = 0;
+ } else {
+ aa_border_width[i] = 0;
+ aa_border_width_half[i] = 0;
+ aa_fill_width[i] = aa_size;
+ aa_fill_width_half[i] = aa_size / 2;
+ }
+ }
+ } else {
+ for (int i = 0; i < 4; i++) {
+ aa_border_width[i] = 0;
+ aa_border_width_half[i] = 0;
+ aa_fill_width[i] = aa_size;
+ aa_fill_width_half[i] = aa_size / 2;
+ }
+ }
+
+ if (draw_center) {
+ // Infill rect, transparent side of antialiasing gradient (base infill rect enlarged by AA size)
+ Rect2 infill_rect_aa_transparent = infill_rect.grow_individual(aa_fill_width_half[SIDE_LEFT], aa_fill_width_half[SIDE_TOP],
+ aa_fill_width_half[SIDE_RIGHT], aa_fill_width_half[SIDE_BOTTOM]);
+ // Infill rect, colored side of antialiasing gradient (base infill rect shrunk by AA size)
+ Rect2 infill_rect_aa_colored = infill_rect_aa_transparent.grow_individual(-aa_fill_width[SIDE_LEFT], -aa_fill_width[SIDE_TOP],
+ -aa_fill_width[SIDE_RIGHT], -aa_fill_width[SIDE_BOTTOM]);
+ if (!blend_on) {
+ // Create center fill, not antialiased yet
+ draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
+ infill_rect_aa_colored, infill_rect_aa_colored, bg_color, bg_color, corner_detail, skew, true);
+ }
+ if (!blend_on || !draw_border) {
+ Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0);
+ // Add antialiasing on the center fill
+ draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
+ infill_rect_aa_transparent, infill_rect_aa_colored, bg_color, alpha_bg, corner_detail, skew);
+ }
+ }
+
+ if (draw_border) {
+ // Inner border recct, fully colored side of antialiasing gradient (base inner rect enlarged by AA size)
+ Rect2 inner_rect_aa_colored = infill_rect.grow_individual(aa_border_width_half[SIDE_LEFT], aa_border_width_half[SIDE_TOP],
+ aa_border_width_half[SIDE_RIGHT], aa_border_width_half[SIDE_BOTTOM]);
+ // Inner border rect, transparent side of antialiasing gradient (base inner rect shrunk by AA size)
+ Rect2 inner_rect_aa_transparent = inner_rect_aa_colored.grow_individual(-aa_border_width[SIDE_LEFT], -aa_border_width[SIDE_TOP],
+ -aa_border_width[SIDE_RIGHT], -aa_border_width[SIDE_BOTTOM]);
+ // Outer border rect, transparent side of antialiasing gradient (base outer rect enlarged by AA size)
+ Rect2 outer_rect_aa_transparent = style_rect.grow_individual(aa_border_width_half[SIDE_LEFT], aa_border_width_half[SIDE_TOP],
+ aa_border_width_half[SIDE_RIGHT], aa_border_width_half[SIDE_BOTTOM]);
+ // Outer border rect, colored side of antialiasing gradient (base outer rect shrunk by AA size)
+ Rect2 outer_rect_aa_colored = border_style_rect.grow_individual(aa_border_width_half[SIDE_LEFT], aa_border_width_half[SIDE_TOP],
+ aa_border_width_half[SIDE_RIGHT], aa_border_width_half[SIDE_BOTTOM]);
+
+ // Create border ring, not antialiased yet
+ draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
+ outer_rect_aa_colored, ((blend_on) ? infill_rect : inner_rect_aa_colored), border_color_inner, border_color, corner_detail, skew);
+ if (!blend_on) {
+ // Add antialiasing on the ring inner border
+ draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
+ inner_rect_aa_colored, inner_rect_aa_transparent, border_color_blend, border_color, corner_detail, skew);
+ }
+ // Add antialiasing on the ring outer border
+ draw_rounded_rectangle(verts, indices, colors, border_style_rect, adapted_corner,
+ outer_rect_aa_transparent, outer_rect_aa_colored, border_color, border_color_alpha, corner_detail, skew);
+ }
+ }
+
+ // Compute UV coordinates.
+ Rect2 uv_rect = style_rect.grow(aa_on ? aa_size : 0);
+ uvs.resize(verts.size());
+ for (int i = 0; i < verts.size(); i++) {
+ uvs.write[i].x = (verts[i].x - uv_rect.position.x) / uv_rect.size.width;
+ uvs.write[i].y = (verts[i].y - uv_rect.position.y) / uv_rect.size.height;
+ }
+
+ // Draw stylebox.
+ RenderingServer *vs = RenderingServer::get_singleton();
+ vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors, uvs);
+}
+
+void StyleBoxFlat::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &StyleBoxFlat::set_bg_color);
+ ClassDB::bind_method(D_METHOD("get_bg_color"), &StyleBoxFlat::get_bg_color);
+
+ ClassDB::bind_method(D_METHOD("set_border_color", "color"), &StyleBoxFlat::set_border_color);
+ ClassDB::bind_method(D_METHOD("get_border_color"), &StyleBoxFlat::get_border_color);
+
+ ClassDB::bind_method(D_METHOD("set_border_width_all", "width"), &StyleBoxFlat::set_border_width_all);
+ ClassDB::bind_method(D_METHOD("get_border_width_min"), &StyleBoxFlat::get_border_width_min);
+
+ ClassDB::bind_method(D_METHOD("set_border_width", "margin", "width"), &StyleBoxFlat::set_border_width);
+ ClassDB::bind_method(D_METHOD("get_border_width", "margin"), &StyleBoxFlat::get_border_width);
+
+ ClassDB::bind_method(D_METHOD("set_border_blend", "blend"), &StyleBoxFlat::set_border_blend);
+ ClassDB::bind_method(D_METHOD("get_border_blend"), &StyleBoxFlat::get_border_blend);
+
+ ClassDB::bind_method(D_METHOD("set_corner_radius_all", "radius"), &StyleBoxFlat::set_corner_radius_all);
+
+ ClassDB::bind_method(D_METHOD("set_corner_radius", "corner", "radius"), &StyleBoxFlat::set_corner_radius);
+ ClassDB::bind_method(D_METHOD("get_corner_radius", "corner"), &StyleBoxFlat::get_corner_radius);
+
+ ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin);
+ ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_all);
+ ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin);
+
+ ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center);
+ ClassDB::bind_method(D_METHOD("is_draw_center_enabled"), &StyleBoxFlat::is_draw_center_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_skew", "skew"), &StyleBoxFlat::set_skew);
+ ClassDB::bind_method(D_METHOD("get_skew"), &StyleBoxFlat::get_skew);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_color", "color"), &StyleBoxFlat::set_shadow_color);
+ ClassDB::bind_method(D_METHOD("get_shadow_color"), &StyleBoxFlat::get_shadow_color);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_size", "size"), &StyleBoxFlat::set_shadow_size);
+ ClassDB::bind_method(D_METHOD("get_shadow_size"), &StyleBoxFlat::get_shadow_size);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_offset", "offset"), &StyleBoxFlat::set_shadow_offset);
+ ClassDB::bind_method(D_METHOD("get_shadow_offset"), &StyleBoxFlat::get_shadow_offset);
+
+ ClassDB::bind_method(D_METHOD("set_anti_aliased", "anti_aliased"), &StyleBoxFlat::set_anti_aliased);
+ ClassDB::bind_method(D_METHOD("is_anti_aliased"), &StyleBoxFlat::is_anti_aliased);
+
+ ClassDB::bind_method(D_METHOD("set_aa_size", "size"), &StyleBoxFlat::set_aa_size);
+ ClassDB::bind_method(D_METHOD("get_aa_size"), &StyleBoxFlat::get_aa_size);
+
+ ClassDB::bind_method(D_METHOD("set_corner_detail", "detail"), &StyleBoxFlat::set_corner_detail);
+ ClassDB::bind_method(D_METHOD("get_corner_detail"), &StyleBoxFlat::get_corner_detail);
+
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "bg_color"), "set_bg_color", "get_bg_color");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "skew"), "set_skew", "get_skew");
+
+ ADD_GROUP("Border Width", "border_width_");
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_BOTTOM);
+
+ ADD_GROUP("Border", "border_");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "border_blend"), "set_border_blend", "get_border_blend");
+
+ ADD_GROUP("Corner Radius", "corner_radius_");
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail");
+
+ ADD_GROUP("Expand Margins", "expand_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
+
+ ADD_GROUP("Shadow", "shadow_");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_shadow_size", "get_shadow_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_shadow_offset", "get_shadow_offset");
+
+ ADD_GROUP("Anti Aliasing", "anti_aliasing_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "anti_aliasing"), "set_anti_aliased", "is_anti_aliased");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "0.01,10,0.001,suffix:px"), "set_aa_size", "get_aa_size");
+}
+
+StyleBoxFlat::StyleBoxFlat() {}
+
+StyleBoxFlat::~StyleBoxFlat() {}
diff --git a/scene/resources/style_box_flat.h b/scene/resources/style_box_flat.h
new file mode 100644
index 0000000000..b6bb145f05
--- /dev/null
+++ b/scene/resources/style_box_flat.h
@@ -0,0 +1,118 @@
+/**************************************************************************/
+/* style_box_flat.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 STYLE_BOX_FLAT_H
+#define STYLE_BOX_FLAT_H
+
+#include "scene/resources/style_box.h"
+
+class StyleBoxFlat : public StyleBox {
+ GDCLASS(StyleBoxFlat, StyleBox);
+
+ Color bg_color = Color(0.6, 0.6, 0.6);
+ Color shadow_color = Color(0, 0, 0, 0.6);
+ Color border_color = Color(0.8, 0.8, 0.8);
+
+ real_t border_width[4] = {};
+ real_t expand_margin[4] = {};
+ real_t corner_radius[4] = {};
+
+ bool draw_center = true;
+ bool blend_border = false;
+ Vector2 skew;
+ bool anti_aliased = true;
+
+ int corner_detail = 8;
+ int shadow_size = 0;
+ Point2 shadow_offset;
+ real_t aa_size = 1;
+
+protected:
+ virtual float get_style_margin(Side p_side) const override;
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+public:
+ void set_bg_color(const Color &p_color);
+ Color get_bg_color() const;
+
+ void set_border_color(const Color &p_color);
+ Color get_border_color() const;
+
+ void set_border_width_all(int p_size);
+ int get_border_width_min() const;
+
+ void set_border_width(Side p_side, int p_width);
+ int get_border_width(Side p_side) const;
+
+ void set_border_blend(bool p_blend);
+ bool get_border_blend() const;
+
+ void set_corner_radius_all(int radius);
+ void set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_bottom_right, const int radius_bottom_left);
+ void set_corner_radius(Corner p_corner, const int radius);
+ int get_corner_radius(Corner p_corner) const;
+
+ void set_corner_detail(const int &p_corner_detail);
+ int get_corner_detail() const;
+
+ void set_expand_margin(Side p_expand_side, float p_size);
+ void set_expand_margin_all(float p_expand_margin_size);
+ void set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
+ float get_expand_margin(Side p_expand_side) const;
+
+ void set_draw_center(bool p_enabled);
+ bool is_draw_center_enabled() const;
+
+ void set_skew(Vector2 p_skew);
+ Vector2 get_skew() const;
+
+ void set_shadow_color(const Color &p_color);
+ Color get_shadow_color() const;
+
+ void set_shadow_size(const int &p_size);
+ int get_shadow_size() const;
+
+ void set_shadow_offset(const Point2 &p_offset);
+ Point2 get_shadow_offset() const;
+
+ void set_anti_aliased(const bool &p_anti_aliased);
+ bool is_anti_aliased() const;
+ void set_aa_size(const real_t p_aa_size);
+ real_t get_aa_size() const;
+
+ virtual Rect2 get_draw_rect(const Rect2 &p_rect) const override;
+ virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override;
+
+ StyleBoxFlat();
+ ~StyleBoxFlat();
+};
+
+#endif // STYLE_BOX_FLAT_H
diff --git a/scene/resources/style_box_line.cpp b/scene/resources/style_box_line.cpp
new file mode 100644
index 0000000000..9aeba88531
--- /dev/null
+++ b/scene/resources/style_box_line.cpp
@@ -0,0 +1,132 @@
+/**************************************************************************/
+/* style_box_line.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 "style_box_line.h"
+
+#include "servers/rendering_server.h"
+
+float StyleBoxLine::get_style_margin(Side p_side) const {
+ ERR_FAIL_INDEX_V((int)p_side, 4, 0);
+
+ if (vertical) {
+ if (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) {
+ return thickness / 2.0;
+ }
+ } else if (p_side == SIDE_TOP || p_side == SIDE_BOTTOM) {
+ return thickness / 2.0;
+ }
+
+ return 0;
+}
+
+void StyleBoxLine::set_color(const Color &p_color) {
+ color = p_color;
+ emit_changed();
+}
+
+Color StyleBoxLine::get_color() const {
+ return color;
+}
+
+void StyleBoxLine::set_thickness(int p_thickness) {
+ thickness = p_thickness;
+ emit_changed();
+}
+
+int StyleBoxLine::get_thickness() const {
+ return thickness;
+}
+
+void StyleBoxLine::set_vertical(bool p_vertical) {
+ vertical = p_vertical;
+ emit_changed();
+}
+
+bool StyleBoxLine::is_vertical() const {
+ return vertical;
+}
+
+void StyleBoxLine::set_grow_end(float p_grow_end) {
+ grow_end = p_grow_end;
+ emit_changed();
+}
+
+float StyleBoxLine::get_grow_end() const {
+ return grow_end;
+}
+
+void StyleBoxLine::set_grow_begin(float p_grow_begin) {
+ grow_begin = p_grow_begin;
+ emit_changed();
+}
+
+float StyleBoxLine::get_grow_begin() const {
+ return grow_begin;
+}
+
+void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const {
+ RenderingServer *vs = RenderingServer::get_singleton();
+ Rect2i r = p_rect;
+
+ if (vertical) {
+ r.position.y -= grow_begin;
+ r.size.y += (grow_begin + grow_end);
+ r.size.x = thickness;
+ } else {
+ r.position.x -= grow_begin;
+ r.size.x += (grow_begin + grow_end);
+ r.size.y = thickness;
+ }
+
+ vs->canvas_item_add_rect(p_canvas_item, r, color);
+}
+
+void StyleBoxLine::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &StyleBoxLine::set_color);
+ ClassDB::bind_method(D_METHOD("get_color"), &StyleBoxLine::get_color);
+ ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &StyleBoxLine::set_thickness);
+ ClassDB::bind_method(D_METHOD("get_thickness"), &StyleBoxLine::get_thickness);
+ ClassDB::bind_method(D_METHOD("set_grow_begin", "offset"), &StyleBoxLine::set_grow_begin);
+ ClassDB::bind_method(D_METHOD("get_grow_begin"), &StyleBoxLine::get_grow_begin);
+ ClassDB::bind_method(D_METHOD("set_grow_end", "offset"), &StyleBoxLine::set_grow_end);
+ ClassDB::bind_method(D_METHOD("get_grow_end"), &StyleBoxLine::get_grow_end);
+ ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &StyleBoxLine::set_vertical);
+ ClassDB::bind_method(D_METHOD("is_vertical"), &StyleBoxLine::is_vertical);
+
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_begin", "get_grow_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_end", "get_grow_end");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,100,suffix:px"), "set_thickness", "get_thickness");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
+}
+
+StyleBoxLine::StyleBoxLine() {}
+
+StyleBoxLine::~StyleBoxLine() {}
diff --git a/scene/resources/style_box_line.h b/scene/resources/style_box_line.h
new file mode 100644
index 0000000000..18f765a1e4
--- /dev/null
+++ b/scene/resources/style_box_line.h
@@ -0,0 +1,70 @@
+/**************************************************************************/
+/* style_box_line.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 STYLE_BOX_LINE_H
+#define STYLE_BOX_LINE_H
+
+#include "scene/resources/style_box.h"
+
+class StyleBoxLine : public StyleBox {
+ GDCLASS(StyleBoxLine, StyleBox);
+ Color color;
+ int thickness = 1;
+ bool vertical = false;
+ float grow_begin = 1.0;
+ float grow_end = 1.0;
+
+protected:
+ virtual float get_style_margin(Side p_side) const override;
+ static void _bind_methods();
+
+public:
+ void set_color(const Color &p_color);
+ Color get_color() const;
+
+ void set_thickness(int p_thickness);
+ int get_thickness() const;
+
+ void set_vertical(bool p_vertical);
+ bool is_vertical() const;
+
+ void set_grow_begin(float p_grow);
+ float get_grow_begin() const;
+
+ void set_grow_end(float p_grow);
+ float get_grow_end() const;
+
+ virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override;
+
+ StyleBoxLine();
+ ~StyleBoxLine();
+};
+
+#endif // STYLE_BOX_LINE_H
diff --git a/scene/resources/style_box_texture.cpp b/scene/resources/style_box_texture.cpp
new file mode 100644
index 0000000000..156525d21c
--- /dev/null
+++ b/scene/resources/style_box_texture.cpp
@@ -0,0 +1,243 @@
+/**************************************************************************/
+/* style_box_texture.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 "style_box_texture.h"
+
+float StyleBoxTexture::get_style_margin(Side p_side) const {
+ ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
+
+ return texture_margin[p_side];
+}
+
+void StyleBoxTexture::set_texture(Ref<Texture2D> p_texture) {
+ if (texture == p_texture) {
+ return;
+ }
+ texture = p_texture;
+ emit_changed();
+}
+
+Ref<Texture2D> StyleBoxTexture::get_texture() const {
+ return texture;
+}
+
+void StyleBoxTexture::set_texture_margin(Side p_side, float p_size) {
+ ERR_FAIL_INDEX((int)p_side, 4);
+
+ texture_margin[p_side] = p_size;
+ emit_changed();
+}
+
+void StyleBoxTexture::set_texture_margin_all(float p_size) {
+ for (int i = 0; i < 4; i++) {
+ texture_margin[i] = p_size;
+ }
+ emit_changed();
+}
+
+void StyleBoxTexture::set_texture_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ texture_margin[SIDE_LEFT] = p_left;
+ texture_margin[SIDE_TOP] = p_top;
+ texture_margin[SIDE_RIGHT] = p_right;
+ texture_margin[SIDE_BOTTOM] = p_bottom;
+ emit_changed();
+}
+
+float StyleBoxTexture::get_texture_margin(Side p_side) const {
+ ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
+
+ return texture_margin[p_side];
+}
+
+void StyleBoxTexture::set_expand_margin(Side p_side, float p_size) {
+ ERR_FAIL_INDEX((int)p_side, 4);
+ expand_margin[p_side] = p_size;
+ emit_changed();
+}
+
+void StyleBoxTexture::set_expand_margin_all(float p_expand_margin_size) {
+ for (int i = 0; i < 4; i++) {
+ expand_margin[i] = p_expand_margin_size;
+ }
+ emit_changed();
+}
+
+void StyleBoxTexture::set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ expand_margin[SIDE_LEFT] = p_left;
+ expand_margin[SIDE_TOP] = p_top;
+ expand_margin[SIDE_RIGHT] = p_right;
+ expand_margin[SIDE_BOTTOM] = p_bottom;
+ emit_changed();
+}
+
+float StyleBoxTexture::get_expand_margin(Side p_side) const {
+ ERR_FAIL_INDEX_V((int)p_side, 4, 0);
+ return expand_margin[p_side];
+}
+
+void StyleBoxTexture::set_region_rect(const Rect2 &p_region_rect) {
+ if (region_rect == p_region_rect) {
+ return;
+ }
+
+ region_rect = p_region_rect;
+ emit_changed();
+}
+
+Rect2 StyleBoxTexture::get_region_rect() const {
+ return region_rect;
+}
+
+void StyleBoxTexture::set_draw_center(bool p_enabled) {
+ draw_center = p_enabled;
+ emit_changed();
+}
+
+bool StyleBoxTexture::is_draw_center_enabled() const {
+ return draw_center;
+}
+
+void StyleBoxTexture::set_h_axis_stretch_mode(AxisStretchMode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, 3);
+ axis_h = p_mode;
+ emit_changed();
+}
+
+StyleBoxTexture::AxisStretchMode StyleBoxTexture::get_h_axis_stretch_mode() const {
+ return axis_h;
+}
+
+void StyleBoxTexture::set_v_axis_stretch_mode(AxisStretchMode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, 3);
+ axis_v = p_mode;
+ emit_changed();
+}
+
+StyleBoxTexture::AxisStretchMode StyleBoxTexture::get_v_axis_stretch_mode() const {
+ return axis_v;
+}
+
+void StyleBoxTexture::set_modulate(const Color &p_modulate) {
+ if (modulate == p_modulate) {
+ return;
+ }
+ modulate = p_modulate;
+ emit_changed();
+}
+
+Color StyleBoxTexture::get_modulate() const {
+ return modulate;
+}
+
+Rect2 StyleBoxTexture::get_draw_rect(const Rect2 &p_rect) const {
+ return p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]);
+}
+
+void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const {
+ if (texture.is_null()) {
+ return;
+ }
+
+ Rect2 rect = p_rect;
+ Rect2 src_rect = region_rect;
+
+ texture->get_rect_region(rect, src_rect, rect, src_rect);
+
+ rect.position.x -= expand_margin[SIDE_LEFT];
+ rect.position.y -= expand_margin[SIDE_TOP];
+ rect.size.x += expand_margin[SIDE_LEFT] + expand_margin[SIDE_RIGHT];
+ rect.size.y += expand_margin[SIDE_TOP] + expand_margin[SIDE_BOTTOM];
+
+ Vector2 start_offset = Vector2(texture_margin[SIDE_LEFT], texture_margin[SIDE_TOP]);
+ Vector2 end_offset = Vector2(texture_margin[SIDE_RIGHT], texture_margin[SIDE_BOTTOM]);
+
+ RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), start_offset, end_offset, RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate);
+}
+
+void StyleBoxTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &StyleBoxTexture::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_texture_margin", "margin", "size"), &StyleBoxTexture::set_texture_margin);
+ ClassDB::bind_method(D_METHOD("set_texture_margin_all", "size"), &StyleBoxTexture::set_texture_margin_all);
+ ClassDB::bind_method(D_METHOD("get_texture_margin", "margin"), &StyleBoxTexture::get_texture_margin);
+
+ ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxTexture::set_expand_margin);
+ ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_all);
+ ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxTexture::get_expand_margin);
+
+ ClassDB::bind_method(D_METHOD("set_region_rect", "region"), &StyleBoxTexture::set_region_rect);
+ ClassDB::bind_method(D_METHOD("get_region_rect"), &StyleBoxTexture::get_region_rect);
+
+ ClassDB::bind_method(D_METHOD("set_draw_center", "enable"), &StyleBoxTexture::set_draw_center);
+ ClassDB::bind_method(D_METHOD("is_draw_center_enabled"), &StyleBoxTexture::is_draw_center_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_modulate", "color"), &StyleBoxTexture::set_modulate);
+ ClassDB::bind_method(D_METHOD("get_modulate"), &StyleBoxTexture::get_modulate);
+
+ ClassDB::bind_method(D_METHOD("set_h_axis_stretch_mode", "mode"), &StyleBoxTexture::set_h_axis_stretch_mode);
+ ClassDB::bind_method(D_METHOD("get_h_axis_stretch_mode"), &StyleBoxTexture::get_h_axis_stretch_mode);
+
+ ClassDB::bind_method(D_METHOD("set_v_axis_stretch_mode", "mode"), &StyleBoxTexture::set_v_axis_stretch_mode);
+ ClassDB::bind_method(D_METHOD("get_v_axis_stretch_mode"), &StyleBoxTexture::get_v_axis_stretch_mode);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
+
+ ADD_GROUP("Texture Margins", "texture_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_BOTTOM);
+
+ ADD_GROUP("Expand Margins", "expand_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
+
+ ADD_GROUP("Axis Stretch", "axis_stretch_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
+
+ ADD_GROUP("Sub-Region", "region_");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_region_rect", "get_region_rect");
+
+ ADD_GROUP("Modulate", "modulate_");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate_color"), "set_modulate", "get_modulate");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
+
+ BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_STRETCH);
+ BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE);
+ BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE_FIT);
+}
+
+StyleBoxTexture::StyleBoxTexture() {}
+
+StyleBoxTexture::~StyleBoxTexture() {}
diff --git a/scene/resources/style_box_texture.h b/scene/resources/style_box_texture.h
new file mode 100644
index 0000000000..b1b833f470
--- /dev/null
+++ b/scene/resources/style_box_texture.h
@@ -0,0 +1,99 @@
+/**************************************************************************/
+/* style_box_texture.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 STYLE_BOX_TEXTURE_H
+#define STYLE_BOX_TEXTURE_H
+
+#include "scene/resources/style_box.h"
+#include "scene/resources/texture.h"
+
+class StyleBoxTexture : public StyleBox {
+ GDCLASS(StyleBoxTexture, StyleBox);
+
+public:
+ enum AxisStretchMode {
+ AXIS_STRETCH_MODE_STRETCH,
+ AXIS_STRETCH_MODE_TILE,
+ AXIS_STRETCH_MODE_TILE_FIT,
+ };
+
+private:
+ float expand_margin[4] = {};
+ float texture_margin[4] = {};
+ Rect2 region_rect;
+ Ref<Texture2D> texture;
+ bool draw_center = true;
+ Color modulate = Color(1, 1, 1, 1);
+ AxisStretchMode axis_h = AXIS_STRETCH_MODE_STRETCH;
+ AxisStretchMode axis_v = AXIS_STRETCH_MODE_STRETCH;
+
+protected:
+ virtual float get_style_margin(Side p_side) const override;
+ static void _bind_methods();
+
+public:
+ void set_texture(Ref<Texture2D> p_texture);
+ Ref<Texture2D> get_texture() const;
+
+ void set_texture_margin(Side p_side, float p_size);
+ void set_texture_margin_all(float p_size);
+ void set_texture_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
+ float get_texture_margin(Side p_side) const;
+
+ void set_expand_margin(Side p_expand_side, float p_size);
+ void set_expand_margin_all(float p_expand_margin_size);
+ void set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
+ float get_expand_margin(Side p_expand_side) const;
+
+ void set_region_rect(const Rect2 &p_region_rect);
+ Rect2 get_region_rect() const;
+
+ void set_draw_center(bool p_enabled);
+ bool is_draw_center_enabled() const;
+
+ void set_h_axis_stretch_mode(AxisStretchMode p_mode);
+ AxisStretchMode get_h_axis_stretch_mode() const;
+
+ void set_v_axis_stretch_mode(AxisStretchMode p_mode);
+ AxisStretchMode get_v_axis_stretch_mode() const;
+
+ void set_modulate(const Color &p_modulate);
+ Color get_modulate() const;
+
+ virtual Rect2 get_draw_rect(const Rect2 &p_rect) const override;
+ virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override;
+
+ StyleBoxTexture();
+ ~StyleBoxTexture();
+};
+
+VARIANT_ENUM_CAST(StyleBoxTexture::AxisStretchMode)
+
+#endif // STYLE_BOX_TEXTURE_H
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 837aa39ce1..0efaad61fe 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -30,14 +30,7 @@
#include "texture.h"
-#include "core/core_string_names.h"
-#include "core/io/image_loader.h"
-#include "core/io/marshalls.h"
-#include "core/math/geometry_2d.h"
-#include "core/os/os.h"
-#include "scene/resources/bit_map.h"
-#include "scene/resources/mesh.h"
-#include "servers/camera/camera_feed.h"
+#include "scene/resources/placeholder_textures.h"
int Texture2D::get_width() const {
int ret = 0;
@@ -127,991 +120,6 @@ void Texture2D::_bind_methods() {
Texture2D::Texture2D() {
}
-/////////////////////
-
-void ImageTexture::reload_from_file() {
- String path = ResourceLoader::path_remap(get_path());
- if (!path.is_resource_file()) {
- return;
- }
-
- Ref<Image> img;
- img.instantiate();
-
- if (ImageLoader::load_image(path, img) == OK) {
- set_image(img);
- } else {
- Resource::reload_from_file();
- notify_property_list_changed();
- emit_changed();
- }
-}
-
-bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
- if (p_name == "image") {
- set_image(p_value);
- return true;
- }
- return false;
-}
-
-bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
- if (p_name == "image") {
- r_ret = get_image();
- return true;
- }
- return false;
-}
-
-void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("image"), PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
-}
-
-Ref<ImageTexture> ImageTexture::create_from_image(const Ref<Image> &p_image) {
- ERR_FAIL_COND_V_MSG(p_image.is_null(), Ref<ImageTexture>(), "Invalid image: null");
- ERR_FAIL_COND_V_MSG(p_image->is_empty(), Ref<ImageTexture>(), "Invalid image: image is empty");
-
- Ref<ImageTexture> image_texture;
- image_texture.instantiate();
- image_texture->set_image(p_image);
- return image_texture;
-}
-
-void ImageTexture::set_image(const Ref<Image> &p_image) {
- ERR_FAIL_COND_MSG(p_image.is_null() || p_image->is_empty(), "Invalid image");
- w = p_image->get_width();
- h = p_image->get_height();
- format = p_image->get_format();
- mipmaps = p_image->has_mipmaps();
-
- if (texture.is_null()) {
- texture = RenderingServer::get_singleton()->texture_2d_create(p_image);
- } else {
- RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_image);
- RenderingServer::get_singleton()->texture_replace(texture, new_texture);
- }
- notify_property_list_changed();
- emit_changed();
-
- image_stored = true;
-}
-
-Image::Format ImageTexture::get_format() const {
- return format;
-}
-
-void ImageTexture::update(const Ref<Image> &p_image) {
- ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image");
- ERR_FAIL_COND_MSG(texture.is_null(), "Texture is not initialized.");
- ERR_FAIL_COND_MSG(p_image->get_width() != w || p_image->get_height() != h,
- "The new image dimensions must match the texture size.");
- ERR_FAIL_COND_MSG(p_image->get_format() != format,
- "The new image format must match the texture's image format.");
- ERR_FAIL_COND_MSG(mipmaps != p_image->has_mipmaps(),
- "The new image mipmaps configuration must match the texture's image mipmaps configuration");
-
- RS::get_singleton()->texture_2d_update(texture, p_image);
-
- notify_property_list_changed();
- emit_changed();
-
- alpha_cache.unref();
- image_stored = true;
-}
-
-Ref<Image> ImageTexture::get_image() const {
- if (image_stored) {
- return RenderingServer::get_singleton()->texture_2d_get(texture);
- } else {
- return Ref<Image>();
- }
-}
-
-int ImageTexture::get_width() const {
- return w;
-}
-
-int ImageTexture::get_height() const {
- return h;
-}
-
-RID ImageTexture::get_rid() const {
- if (texture.is_null()) {
- //we are in trouble, create something temporary
- texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
- }
- return texture;
-}
-
-bool ImageTexture::has_alpha() const {
- return (format == Image::FORMAT_LA8 || format == Image::FORMAT_RGBA8);
-}
-
-void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
- if ((w | h) == 0) {
- return;
- }
- RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose);
-}
-
-void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
- if ((w | h) == 0) {
- return;
- }
- RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);
-}
-
-void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
- if ((w | h) == 0) {
- return;
- }
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv);
-}
-
-bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
- if (!alpha_cache.is_valid()) {
- Ref<Image> img = get_image();
- if (img.is_valid()) {
- if (img->is_compressed()) { //must decompress, if compressed
- Ref<Image> decom = img->duplicate();
- decom->decompress();
- img = decom;
- }
- alpha_cache.instantiate();
- alpha_cache->create_from_image_alpha(img);
- }
- }
-
- if (alpha_cache.is_valid()) {
- int aw = int(alpha_cache->get_size().width);
- int ah = int(alpha_cache->get_size().height);
- if (aw == 0 || ah == 0) {
- return true;
- }
-
- int x = p_x * aw / w;
- int y = p_y * ah / h;
-
- x = CLAMP(x, 0, aw);
- y = CLAMP(y, 0, ah);
-
- return alpha_cache->get_bit(x, y);
- }
-
- return true;
-}
-
-void ImageTexture::set_size_override(const Size2i &p_size) {
- Size2i s = p_size;
- if (s.x != 0) {
- w = s.x;
- }
- if (s.y != 0) {
- h = s.y;
- }
- RenderingServer::get_singleton()->texture_set_size_override(texture, w, h);
-}
-
-void ImageTexture::set_path(const String &p_path, bool p_take_over) {
- if (texture.is_valid()) {
- RenderingServer::get_singleton()->texture_set_path(texture, p_path);
- }
-
- Resource::set_path(p_path, p_take_over);
-}
-
-void ImageTexture::_bind_methods() {
- ClassDB::bind_static_method("ImageTexture", D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image);
- ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format);
-
- ClassDB::bind_method(D_METHOD("set_image", "image"), &ImageTexture::set_image);
- ClassDB::bind_method(D_METHOD("update", "image"), &ImageTexture::update);
- ClassDB::bind_method(D_METHOD("set_size_override", "size"), &ImageTexture::set_size_override);
-}
-
-ImageTexture::ImageTexture() {}
-
-ImageTexture::~ImageTexture() {
- if (texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RenderingServer::get_singleton()->free(texture);
- }
-}
-
-/////////////////////
-
-void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
- if (p_data.size() == 0) {
- return; //nothing to do
- }
-
- const uint8_t *data = p_data.ptr();
- uint32_t data_size = p_data.size();
- ERR_FAIL_COND(data_size < 20);
- compression_mode = CompressionMode(decode_uint32(data + 0));
- format = Image::Format(decode_uint32(data + 4));
- uint32_t mipmap_count = decode_uint32(data + 8);
- size.width = decode_uint32(data + 12);
- size.height = decode_uint32(data + 16);
- mipmaps = mipmap_count > 1;
-
- data += 20;
- data_size -= 20;
-
- Ref<Image> image;
-
- switch (compression_mode) {
- case COMPRESSION_MODE_LOSSLESS:
- case COMPRESSION_MODE_LOSSY: {
- Vector<uint8_t> image_data;
-
- ERR_FAIL_COND(data_size < 4);
- for (uint32_t i = 0; i < mipmap_count; i++) {
- uint32_t mipsize = decode_uint32(data);
- data += 4;
- data_size -= 4;
- ERR_FAIL_COND(mipsize < data_size);
- Ref<Image> img = memnew(Image(data, data_size));
- ERR_FAIL_COND(img->is_empty());
- if (img->get_format() != format) { // May happen due to webp/png in the tiny mipmaps.
- img->convert(format);
- }
- image_data.append_array(img->get_data());
-
- data += mipsize;
- data_size -= mipsize;
- }
-
- image = Ref<Image>(memnew(Image(size.width, size.height, mipmap_count > 1, format, image_data)));
-
- } break;
- case COMPRESSION_MODE_BASIS_UNIVERSAL: {
- ERR_FAIL_NULL(Image::basis_universal_unpacker_ptr);
- image = Image::basis_universal_unpacker_ptr(data, data_size);
-
- } break;
- case COMPRESSION_MODE_S3TC:
- case COMPRESSION_MODE_ETC2:
- case COMPRESSION_MODE_BPTC: {
- image = Ref<Image>(memnew(Image(size.width, size.height, mipmap_count > 1, format, p_data.slice(20))));
- } break;
- }
- ERR_FAIL_COND(image.is_null());
-
- if (texture.is_null()) {
- texture = RenderingServer::get_singleton()->texture_2d_create(image);
- } else {
- RID new_texture = RenderingServer::get_singleton()->texture_2d_create(image);
- RenderingServer::get_singleton()->texture_replace(texture, new_texture);
- }
-
- image_stored = true;
- RenderingServer::get_singleton()->texture_set_size_override(texture, size_override.width, size_override.height);
- alpha_cache.unref();
-
- if (keep_all_compressed_buffers || keep_compressed_buffer) {
- compressed_buffer = p_data;
- } else {
- compressed_buffer.clear();
- }
-}
-
-PortableCompressedTexture2D::CompressionMode PortableCompressedTexture2D::get_compression_mode() const {
- return compression_mode;
-}
-Vector<uint8_t> PortableCompressedTexture2D::_get_data() const {
- return compressed_buffer;
-}
-
-void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, CompressionMode p_compression_mode, bool p_normal_map, float p_lossy_quality) {
- ERR_FAIL_COND(p_image.is_null() || p_image->is_empty());
-
- Vector<uint8_t> buffer;
-
- buffer.resize(20);
- encode_uint32(p_compression_mode, buffer.ptrw());
- encode_uint32(p_image->get_format(), buffer.ptrw() + 4);
- encode_uint32(p_image->get_mipmap_count() + 1, buffer.ptrw() + 8);
- encode_uint32(p_image->get_width(), buffer.ptrw() + 12);
- encode_uint32(p_image->get_height(), buffer.ptrw() + 16);
-
- switch (p_compression_mode) {
- case COMPRESSION_MODE_LOSSLESS:
- case COMPRESSION_MODE_LOSSY: {
- for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
- Vector<uint8_t> data;
- if (p_compression_mode == COMPRESSION_MODE_LOSSY) {
- data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
- } else {
- data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
- }
- int data_len = data.size();
- buffer.resize(buffer.size() + 4);
- encode_uint32(data_len, buffer.ptrw() + buffer.size() - 4);
- buffer.append_array(data);
- }
- } break;
- case COMPRESSION_MODE_BASIS_UNIVERSAL: {
- Image::UsedChannels uc = p_image->detect_used_channels(p_normal_map ? Image::COMPRESS_SOURCE_NORMAL : Image::COMPRESS_SOURCE_GENERIC);
- Vector<uint8_t> budata = Image::basis_universal_packer(p_image, uc);
- buffer.append_array(budata);
-
- } break;
- case COMPRESSION_MODE_S3TC:
- case COMPRESSION_MODE_ETC2:
- case COMPRESSION_MODE_BPTC: {
- Ref<Image> copy = p_image->duplicate();
- switch (p_compression_mode) {
- case COMPRESSION_MODE_S3TC:
- copy->compress(Image::COMPRESS_S3TC);
- break;
- case COMPRESSION_MODE_ETC2:
- copy->compress(Image::COMPRESS_ETC2);
- break;
- case COMPRESSION_MODE_BPTC:
- copy->compress(Image::COMPRESS_BPTC);
- break;
- default: {
- };
- }
-
- buffer.append_array(copy->get_data());
-
- } break;
- }
-
- _set_data(buffer);
-}
-
-Image::Format PortableCompressedTexture2D::get_format() const {
- return format;
-}
-
-Ref<Image> PortableCompressedTexture2D::get_image() const {
- if (image_stored) {
- return RenderingServer::get_singleton()->texture_2d_get(texture);
- } else {
- return Ref<Image>();
- }
-}
-
-int PortableCompressedTexture2D::get_width() const {
- return size.width;
-}
-
-int PortableCompressedTexture2D::get_height() const {
- return size.height;
-}
-
-RID PortableCompressedTexture2D::get_rid() const {
- if (texture.is_null()) {
- //we are in trouble, create something temporary
- texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
- }
- return texture;
-}
-
-bool PortableCompressedTexture2D::has_alpha() const {
- return (format == Image::FORMAT_LA8 || format == Image::FORMAT_RGBA8);
-}
-
-void PortableCompressedTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
- if (size.width == 0 || size.height == 0) {
- return;
- }
- RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, size), texture, false, p_modulate, p_transpose);
-}
-
-void PortableCompressedTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
- if (size.width == 0 || size.height == 0) {
- return;
- }
- RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);
-}
-
-void PortableCompressedTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
- if (size.width == 0 || size.height == 0) {
- return;
- }
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv);
-}
-
-bool PortableCompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {
- if (!alpha_cache.is_valid()) {
- Ref<Image> img = get_image();
- if (img.is_valid()) {
- if (img->is_compressed()) { //must decompress, if compressed
- Ref<Image> decom = img->duplicate();
- decom->decompress();
- img = decom;
- }
- alpha_cache.instantiate();
- alpha_cache->create_from_image_alpha(img);
- }
- }
-
- if (alpha_cache.is_valid()) {
- int aw = int(alpha_cache->get_size().width);
- int ah = int(alpha_cache->get_size().height);
- if (aw == 0 || ah == 0) {
- return true;
- }
-
- int x = p_x * aw / size.width;
- int y = p_y * ah / size.height;
-
- x = CLAMP(x, 0, aw);
- y = CLAMP(y, 0, ah);
-
- return alpha_cache->get_bit(x, y);
- }
-
- return true;
-}
-
-void PortableCompressedTexture2D::set_size_override(const Size2 &p_size) {
- size_override = p_size;
- RenderingServer::get_singleton()->texture_set_size_override(texture, size_override.width, size_override.height);
-}
-
-Size2 PortableCompressedTexture2D::get_size_override() const {
- return size_override;
-}
-
-void PortableCompressedTexture2D::set_path(const String &p_path, bool p_take_over) {
- if (texture.is_valid()) {
- RenderingServer::get_singleton()->texture_set_path(texture, p_path);
- }
-
- Resource::set_path(p_path, p_take_over);
-}
-
-bool PortableCompressedTexture2D::keep_all_compressed_buffers = false;
-
-void PortableCompressedTexture2D::set_keep_all_compressed_buffers(bool p_keep) {
- keep_all_compressed_buffers = p_keep;
-}
-
-bool PortableCompressedTexture2D::is_keeping_all_compressed_buffers() {
- return keep_all_compressed_buffers;
-}
-
-void PortableCompressedTexture2D::set_keep_compressed_buffer(bool p_keep) {
- keep_compressed_buffer = p_keep;
- if (!p_keep) {
- compressed_buffer.clear();
- }
-}
-
-bool PortableCompressedTexture2D::is_keeping_compressed_buffer() const {
- return keep_compressed_buffer;
-}
-
-void PortableCompressedTexture2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_from_image", "image", "compression_mode", "normal_map", "lossy_quality"), &PortableCompressedTexture2D::create_from_image, DEFVAL(false), DEFVAL(0.8));
- ClassDB::bind_method(D_METHOD("get_format"), &PortableCompressedTexture2D::get_format);
- ClassDB::bind_method(D_METHOD("get_compression_mode"), &PortableCompressedTexture2D::get_compression_mode);
-
- ClassDB::bind_method(D_METHOD("set_size_override", "size"), &PortableCompressedTexture2D::set_size_override);
- ClassDB::bind_method(D_METHOD("get_size_override"), &PortableCompressedTexture2D::get_size_override);
-
- ClassDB::bind_method(D_METHOD("set_keep_compressed_buffer", "keep"), &PortableCompressedTexture2D::set_keep_compressed_buffer);
- ClassDB::bind_method(D_METHOD("is_keeping_compressed_buffer"), &PortableCompressedTexture2D::is_keeping_compressed_buffer);
-
- ClassDB::bind_method(D_METHOD("_set_data", "data"), &PortableCompressedTexture2D::_set_data);
- ClassDB::bind_method(D_METHOD("_get_data"), &PortableCompressedTexture2D::_get_data);
-
- ClassDB::bind_static_method("PortableCompressedTexture2D", D_METHOD("set_keep_all_compressed_buffers", "keep"), &PortableCompressedTexture2D::set_keep_all_compressed_buffers);
- ClassDB::bind_static_method("PortableCompressedTexture2D", D_METHOD("is_keeping_all_compressed_buffers"), &PortableCompressedTexture2D::is_keeping_all_compressed_buffers);
-
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_data", "_get_data");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_override", PROPERTY_HINT_NONE, "suffix:px"), "set_size_override", "get_size_override");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_compressed_buffer"), "set_keep_compressed_buffer", "is_keeping_compressed_buffer");
-
- BIND_ENUM_CONSTANT(COMPRESSION_MODE_LOSSLESS);
- BIND_ENUM_CONSTANT(COMPRESSION_MODE_LOSSY);
- BIND_ENUM_CONSTANT(COMPRESSION_MODE_BASIS_UNIVERSAL);
- BIND_ENUM_CONSTANT(COMPRESSION_MODE_S3TC);
- BIND_ENUM_CONSTANT(COMPRESSION_MODE_ETC2);
- BIND_ENUM_CONSTANT(COMPRESSION_MODE_BPTC);
-}
-
-PortableCompressedTexture2D::PortableCompressedTexture2D() {}
-
-PortableCompressedTexture2D::~PortableCompressedTexture2D() {
- if (texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RenderingServer::get_singleton()->free(texture);
- }
-}
-
-//////////////////////////////////////////
-
-Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_size_limit) {
- uint32_t data_format = f->get_32();
- uint32_t w = f->get_16();
- uint32_t h = f->get_16();
- uint32_t mipmaps = f->get_32();
- Image::Format format = Image::Format(f->get_32());
-
- if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP) {
- //look for a PNG or WebP file inside
-
- int sw = w;
- int sh = h;
-
- //mipmaps need to be read independently, they will be later combined
- Vector<Ref<Image>> mipmap_images;
- uint64_t total_size = 0;
-
- bool first = true;
-
- for (uint32_t i = 0; i < mipmaps + 1; i++) {
- uint32_t size = f->get_32();
-
- if (p_size_limit > 0 && i < (mipmaps - 1) && (sw > p_size_limit || sh > p_size_limit)) {
- //can't load this due to size limit
- sw = MAX(sw >> 1, 1);
- sh = MAX(sh >> 1, 1);
- f->seek(f->get_position() + size);
- continue;
- }
-
- Vector<uint8_t> pv;
- pv.resize(size);
- {
- uint8_t *wr = pv.ptrw();
- f->get_buffer(wr, size);
- }
-
- Ref<Image> img;
- if (data_format == DATA_FORMAT_PNG && Image::png_unpacker) {
- img = Image::png_unpacker(pv);
- } else if (data_format == DATA_FORMAT_WEBP && Image::webp_unpacker) {
- img = Image::webp_unpacker(pv);
- }
-
- if (img.is_null() || img->is_empty()) {
- ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref<Image>());
- }
-
- if (first) {
- //format will actually be the format of the first image,
- //as it may have changed on compression
- format = img->get_format();
- first = false;
- } else if (img->get_format() != format) {
- img->convert(format); //all needs to be the same format
- }
-
- total_size += img->get_data().size();
-
- mipmap_images.push_back(img);
-
- sw = MAX(sw >> 1, 1);
- sh = MAX(sh >> 1, 1);
- }
-
- //print_line("mipmap read total: " + itos(mipmap_images.size()));
-
- Ref<Image> image;
- image.instantiate();
-
- if (mipmap_images.size() == 1) {
- //only one image (which will most likely be the case anyway for this format)
- image = mipmap_images[0];
- return image;
-
- } else {
- //rarer use case, but needs to be supported
- Vector<uint8_t> img_data;
- img_data.resize(total_size);
-
- {
- uint8_t *wr = img_data.ptrw();
-
- int ofs = 0;
- for (int i = 0; i < mipmap_images.size(); i++) {
- Vector<uint8_t> id = mipmap_images[i]->get_data();
- int len = id.size();
- const uint8_t *r = id.ptr();
- memcpy(&wr[ofs], r, len);
- ofs += len;
- }
- }
-
- image->set_data(w, h, true, mipmap_images[0]->get_format(), img_data);
- return image;
- }
-
- } else if (data_format == DATA_FORMAT_BASIS_UNIVERSAL) {
- int sw = w;
- int sh = h;
- uint32_t size = f->get_32();
- if (p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) {
- //can't load this due to size limit
- sw = MAX(sw >> 1, 1);
- sh = MAX(sh >> 1, 1);
- f->seek(f->get_position() + size);
- return Ref<Image>();
- }
- Vector<uint8_t> pv;
- pv.resize(size);
- {
- uint8_t *wr = pv.ptrw();
- f->get_buffer(wr, size);
- }
- Ref<Image> img;
- img = Image::basis_universal_unpacker(pv);
- if (img.is_null() || img->is_empty()) {
- ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref<Image>());
- }
- format = img->get_format();
- sw = MAX(sw >> 1, 1);
- sh = MAX(sh >> 1, 1);
- return img;
- } else if (data_format == DATA_FORMAT_IMAGE) {
- int size = Image::get_image_data_size(w, h, format, mipmaps ? true : false);
-
- for (uint32_t i = 0; i < mipmaps + 1; i++) {
- int tw, th;
- int ofs = Image::get_image_mipmap_offset_and_dimensions(w, h, format, i, tw, th);
-
- if (p_size_limit > 0 && i < mipmaps && (p_size_limit > tw || p_size_limit > th)) {
- if (ofs) {
- f->seek(f->get_position() + ofs);
- }
- continue; //oops, size limit enforced, go to next
- }
-
- Vector<uint8_t> data;
- data.resize(size - ofs);
-
- {
- uint8_t *wr = data.ptrw();
- f->get_buffer(wr, data.size());
- }
-
- Ref<Image> image = Image::create_from_data(tw, th, mipmaps - i ? true : false, format, data);
-
- return image;
- }
- }
-
- return Ref<Image>();
-}
-
-void CompressedTexture2D::set_path(const String &p_path, bool p_take_over) {
- if (texture.is_valid()) {
- RenderingServer::get_singleton()->texture_set_path(texture, p_path);
- }
-
- Resource::set_path(p_path, p_take_over);
-}
-
-void CompressedTexture2D::_requested_3d(void *p_ud) {
- CompressedTexture2D *ct = (CompressedTexture2D *)p_ud;
- Ref<CompressedTexture2D> ctex(ct);
- ERR_FAIL_NULL(request_3d_callback);
- request_3d_callback(ctex);
-}
-
-void CompressedTexture2D::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) {
- CompressedTexture2D *ct = (CompressedTexture2D *)p_ud;
- Ref<CompressedTexture2D> ctex(ct);
- ERR_FAIL_NULL(request_roughness_callback);
- request_roughness_callback(ctex, p_normal_path, p_roughness_channel);
-}
-
-void CompressedTexture2D::_requested_normal(void *p_ud) {
- CompressedTexture2D *ct = (CompressedTexture2D *)p_ud;
- Ref<CompressedTexture2D> ctex(ct);
- ERR_FAIL_NULL(request_normal_callback);
- request_normal_callback(ctex);
-}
-
-CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_3d_callback = nullptr;
-CompressedTexture2D::TextureFormatRoughnessRequestCallback CompressedTexture2D::request_roughness_callback = nullptr;
-CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_normal_callback = nullptr;
-
-Image::Format CompressedTexture2D::get_format() const {
- return format;
-}
-
-Error CompressedTexture2D::_load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) {
- alpha_cache.unref();
-
- ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER);
-
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));
-
- uint8_t header[4];
- f->get_buffer(header, 4);
- if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != '2') {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is corrupt (Bad header).");
- }
-
- uint32_t version = f->get_32();
-
- if (version > FORMAT_VERSION) {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new.");
- }
- r_width = f->get_32();
- r_height = f->get_32();
- uint32_t df = f->get_32(); //data format
-
- //skip reserved
- mipmap_limit = int(f->get_32());
- //reserved
- f->get_32();
- f->get_32();
- f->get_32();
-
-#ifdef TOOLS_ENABLED
-
- r_request_3d = request_3d_callback && df & FORMAT_BIT_DETECT_3D;
- r_request_roughness = request_roughness_callback && df & FORMAT_BIT_DETECT_ROUGNESS;
- r_request_normal = request_normal_callback && df & FORMAT_BIT_DETECT_NORMAL;
-
-#else
-
- r_request_3d = false;
- r_request_roughness = false;
- r_request_normal = false;
-
-#endif
- if (!(df & FORMAT_BIT_STREAM)) {
- p_size_limit = 0;
- }
-
- image = load_image_from_file(f, p_size_limit);
-
- if (image.is_null() || image->is_empty()) {
- return ERR_CANT_OPEN;
- }
-
- return OK;
-}
-
-Error CompressedTexture2D::load(const String &p_path) {
- int lw, lh;
- Ref<Image> image;
- image.instantiate();
-
- bool request_3d;
- bool request_normal;
- bool request_roughness;
- int mipmap_limit;
-
- Error err = _load_data(p_path, lw, lh, image, request_3d, request_normal, request_roughness, mipmap_limit);
- if (err) {
- return err;
- }
-
- if (texture.is_valid()) {
- RID new_texture = RS::get_singleton()->texture_2d_create(image);
- RS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = RS::get_singleton()->texture_2d_create(image);
- }
- if (lw || lh) {
- RS::get_singleton()->texture_set_size_override(texture, lw, lh);
- }
-
- w = lw;
- h = lh;
- path_to_file = p_path;
- format = image->get_format();
-
- if (get_path().is_empty()) {
- //temporarily set path if no path set for resource, helps find errors
- RenderingServer::get_singleton()->texture_set_path(texture, p_path);
- }
-
-#ifdef TOOLS_ENABLED
-
- if (request_3d) {
- //print_line("request detect 3D at " + p_path);
- RS::get_singleton()->texture_set_detect_3d_callback(texture, _requested_3d, this);
- } else {
- //print_line("not requesting detect 3D at " + p_path);
- RS::get_singleton()->texture_set_detect_3d_callback(texture, nullptr, nullptr);
- }
-
- if (request_roughness) {
- //print_line("request detect srgb at " + p_path);
- RS::get_singleton()->texture_set_detect_roughness_callback(texture, _requested_roughness, this);
- } else {
- //print_line("not requesting detect srgb at " + p_path);
- RS::get_singleton()->texture_set_detect_roughness_callback(texture, nullptr, nullptr);
- }
-
- if (request_normal) {
- //print_line("request detect srgb at " + p_path);
- RS::get_singleton()->texture_set_detect_normal_callback(texture, _requested_normal, this);
- } else {
- //print_line("not requesting detect normal at " + p_path);
- RS::get_singleton()->texture_set_detect_normal_callback(texture, nullptr, nullptr);
- }
-
-#endif
- notify_property_list_changed();
- emit_changed();
- return OK;
-}
-
-String CompressedTexture2D::get_load_path() const {
- return path_to_file;
-}
-
-int CompressedTexture2D::get_width() const {
- return w;
-}
-
-int CompressedTexture2D::get_height() const {
- return h;
-}
-
-RID CompressedTexture2D::get_rid() const {
- if (!texture.is_valid()) {
- texture = RS::get_singleton()->texture_2d_placeholder_create();
- }
- return texture;
-}
-
-void CompressedTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
- if ((w | h) == 0) {
- return;
- }
- RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose);
-}
-
-void CompressedTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
- if ((w | h) == 0) {
- return;
- }
- RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);
-}
-
-void CompressedTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
- if ((w | h) == 0) {
- return;
- }
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv);
-}
-
-bool CompressedTexture2D::has_alpha() const {
- return false;
-}
-
-Ref<Image> CompressedTexture2D::get_image() const {
- if (texture.is_valid()) {
- return RS::get_singleton()->texture_2d_get(texture);
- } else {
- return Ref<Image>();
- }
-}
-
-bool CompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {
- if (!alpha_cache.is_valid()) {
- Ref<Image> img = get_image();
- if (img.is_valid()) {
- if (img->is_compressed()) { //must decompress, if compressed
- Ref<Image> decom = img->duplicate();
- decom->decompress();
- img = decom;
- }
-
- alpha_cache.instantiate();
- alpha_cache->create_from_image_alpha(img);
- }
- }
-
- if (alpha_cache.is_valid()) {
- int aw = int(alpha_cache->get_size().width);
- int ah = int(alpha_cache->get_size().height);
- if (aw == 0 || ah == 0) {
- return true;
- }
-
- int x = p_x * aw / w;
- int y = p_y * ah / h;
-
- x = CLAMP(x, 0, aw);
- y = CLAMP(y, 0, ah);
-
- return alpha_cache->get_bit(x, y);
- }
-
- return true;
-}
-
-void CompressedTexture2D::reload_from_file() {
- String path = get_path();
- if (!path.is_resource_file()) {
- return;
- }
-
- path = ResourceLoader::path_remap(path); //remap for translation
- path = ResourceLoader::import_remap(path); //remap for import
- if (!path.is_resource_file()) {
- return;
- }
-
- load(path);
-}
-
-void CompressedTexture2D::_validate_property(PropertyInfo &p_property) const {
-}
-
-void CompressedTexture2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture2D::load);
- ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture2D::get_load_path);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");
-}
-
-CompressedTexture2D::CompressedTexture2D() {}
-
-CompressedTexture2D::~CompressedTexture2D() {
- if (texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(texture);
- }
-}
-
-Ref<Resource> ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- Ref<CompressedTexture2D> st;
- st.instantiate();
- Error err = st->load(p_path);
- if (r_error) {
- *r_error = err;
- }
- if (err != OK) {
- return Ref<Resource>();
- }
-
- return st;
-}
-
-void ResourceFormatLoaderCompressedTexture2D::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("ctex");
-}
-
-bool ResourceFormatLoaderCompressedTexture2D::handles_type(const String &p_type) const {
- return p_type == "CompressedTexture2D";
-}
-
-String ResourceFormatLoaderCompressedTexture2D::get_resource_type(const String &p_path) const {
- if (p_path.get_extension().to_lower() == "ctex") {
- return "CompressedTexture2D";
- }
- return "";
-}
-
-////////////////////////////////////
-
TypedArray<Image> Texture3D::_get_datai() const {
Vector<Ref<Image>> data = get_data();
@@ -1163,6 +171,7 @@ Vector<Ref<Image>> Texture3D::get_data() const {
}
return data;
}
+
void Texture3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_format"), &Texture3D::get_format);
ClassDB::bind_method(D_METHOD("get_width"), &Texture3D::get_width);
@@ -1187,1652 +196,6 @@ Ref<Resource> Texture3D::create_placeholder() const {
return placeholder;
}
-//////////////////////////////////////////
-
-Image::Format ImageTexture3D::get_format() const {
- return format;
-}
-int ImageTexture3D::get_width() const {
- return width;
-}
-int ImageTexture3D::get_height() const {
- return height;
-}
-int ImageTexture3D::get_depth() const {
- return depth;
-}
-bool ImageTexture3D::has_mipmaps() const {
- return mipmaps;
-}
-
-Error ImageTexture3D::_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data) {
- Vector<Ref<Image>> images;
- images.resize(p_data.size());
- for (int i = 0; i < images.size(); i++) {
- images.write[i] = p_data[i];
- }
- return create(p_format, p_width, p_height, p_depth, p_mipmaps, images);
-}
-
-void ImageTexture3D::_update(const TypedArray<Image> &p_data) {
- Vector<Ref<Image>> images;
- images.resize(p_data.size());
- for (int i = 0; i < images.size(); i++) {
- images.write[i] = p_data[i];
- }
- return update(images);
-}
-
-Error ImageTexture3D::create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) {
- RID tex = RenderingServer::get_singleton()->texture_3d_create(p_format, p_width, p_height, p_depth, p_mipmaps, p_data);
- ERR_FAIL_COND_V(tex.is_null(), ERR_CANT_CREATE);
-
- if (texture.is_valid()) {
- RenderingServer::get_singleton()->texture_replace(texture, tex);
- } else {
- texture = tex;
- }
-
- format = p_format;
- width = p_width;
- height = p_height;
- depth = p_depth;
- mipmaps = p_mipmaps;
-
- return OK;
-}
-
-void ImageTexture3D::update(const Vector<Ref<Image>> &p_data) {
- ERR_FAIL_COND(!texture.is_valid());
- RenderingServer::get_singleton()->texture_3d_update(texture, p_data);
-}
-
-Vector<Ref<Image>> ImageTexture3D::get_data() const {
- ERR_FAIL_COND_V(!texture.is_valid(), Vector<Ref<Image>>());
- return RS::get_singleton()->texture_3d_get(texture);
-}
-
-RID ImageTexture3D::get_rid() const {
- if (!texture.is_valid()) {
- texture = RS::get_singleton()->texture_3d_placeholder_create();
- }
- return texture;
-}
-void ImageTexture3D::set_path(const String &p_path, bool p_take_over) {
- if (texture.is_valid()) {
- RenderingServer::get_singleton()->texture_set_path(texture, p_path);
- }
-
- Resource::set_path(p_path, p_take_over);
-}
-
-void ImageTexture3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create", "format", "width", "height", "depth", "use_mipmaps", "data"), &ImageTexture3D::_create);
- ClassDB::bind_method(D_METHOD("update", "data"), &ImageTexture3D::_update);
-}
-
-ImageTexture3D::ImageTexture3D() {
-}
-
-ImageTexture3D::~ImageTexture3D() {
- if (texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(texture);
- }
-}
-
-////////////////////////////////////////////
-
-void CompressedTexture3D::set_path(const String &p_path, bool p_take_over) {
- if (texture.is_valid()) {
- RenderingServer::get_singleton()->texture_set_path(texture, p_path);
- }
-
- Resource::set_path(p_path, p_take_over);
-}
-
-Image::Format CompressedTexture3D::get_format() const {
- return format;
-}
-
-Error CompressedTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) {
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));
-
- uint8_t header[4];
- f->get_buffer(header, 4);
- ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L', ERR_FILE_UNRECOGNIZED);
-
- //stored as compressed textures (used for lossless and lossy compression)
- uint32_t version = f->get_32();
-
- if (version > FORMAT_VERSION) {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new.");
- }
-
- r_depth = f->get_32(); //depth
- f->get_32(); //ignored (mode)
- f->get_32(); // ignored (data format)
-
- f->get_32(); //ignored
- int mipmap_count = f->get_32();
- f->get_32(); //ignored
- f->get_32(); //ignored
-
- r_mipmaps = mipmap_count != 0;
-
- r_data.clear();
-
- for (int i = 0; i < (r_depth + mipmap_count); i++) {
- Ref<Image> image = CompressedTexture2D::load_image_from_file(f, 0);
- ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);
- if (i == 0) {
- r_format = image->get_format();
- r_width = image->get_width();
- r_height = image->get_height();
- }
- r_data.push_back(image);
- }
-
- return OK;
-}
-
-Error CompressedTexture3D::load(const String &p_path) {
- Vector<Ref<Image>> data;
-
- int tw, th, td;
- Image::Format tfmt;
- bool tmm;
-
- Error err = _load_data(p_path, data, tfmt, tw, th, td, tmm);
- if (err) {
- return err;
- }
-
- if (texture.is_valid()) {
- RID new_texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data);
- RS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data);
- }
-
- w = tw;
- h = th;
- d = td;
- mipmaps = tmm;
- format = tfmt;
-
- path_to_file = p_path;
-
- if (get_path().is_empty()) {
- //temporarily set path if no path set for resource, helps find errors
- RenderingServer::get_singleton()->texture_set_path(texture, p_path);
- }
-
- notify_property_list_changed();
- emit_changed();
- return OK;
-}
-
-String CompressedTexture3D::get_load_path() const {
- return path_to_file;
-}
-
-int CompressedTexture3D::get_width() const {
- return w;
-}
-
-int CompressedTexture3D::get_height() const {
- return h;
-}
-
-int CompressedTexture3D::get_depth() const {
- return d;
-}
-
-bool CompressedTexture3D::has_mipmaps() const {
- return mipmaps;
-}
-
-RID CompressedTexture3D::get_rid() const {
- if (!texture.is_valid()) {
- texture = RS::get_singleton()->texture_3d_placeholder_create();
- }
- return texture;
-}
-
-Vector<Ref<Image>> CompressedTexture3D::get_data() const {
- if (texture.is_valid()) {
- return RS::get_singleton()->texture_3d_get(texture);
- } else {
- return Vector<Ref<Image>>();
- }
-}
-
-void CompressedTexture3D::reload_from_file() {
- String path = get_path();
- if (!path.is_resource_file()) {
- return;
- }
-
- path = ResourceLoader::path_remap(path); //remap for translation
- path = ResourceLoader::import_remap(path); //remap for import
- if (!path.is_resource_file()) {
- return;
- }
-
- load(path);
-}
-
-void CompressedTexture3D::_validate_property(PropertyInfo &p_property) const {
-}
-
-void CompressedTexture3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture3D::load);
- ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture3D::get_load_path);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");
-}
-
-CompressedTexture3D::CompressedTexture3D() {}
-
-CompressedTexture3D::~CompressedTexture3D() {
- if (texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(texture);
- }
-}
-
-/////////////////////////////
-
-Ref<Resource> ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- Ref<CompressedTexture3D> st;
- st.instantiate();
- Error err = st->load(p_path);
- if (r_error) {
- *r_error = err;
- }
- if (err != OK) {
- return Ref<Resource>();
- }
-
- return st;
-}
-
-void ResourceFormatLoaderCompressedTexture3D::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("ctex3d");
-}
-
-bool ResourceFormatLoaderCompressedTexture3D::handles_type(const String &p_type) const {
- return p_type == "CompressedTexture3D";
-}
-
-String ResourceFormatLoaderCompressedTexture3D::get_resource_type(const String &p_path) const {
- if (p_path.get_extension().to_lower() == "ctex3d") {
- return "CompressedTexture3D";
- }
- return "";
-}
-
-////////////////////////////////////////////
-
-int AtlasTexture::get_width() const {
- if (region.size.width == 0) {
- if (atlas.is_valid()) {
- return atlas->get_width();
- }
- return 1;
- } else {
- return region.size.width + margin.size.width;
- }
-}
-
-int AtlasTexture::get_height() const {
- if (region.size.height == 0) {
- if (atlas.is_valid()) {
- return atlas->get_height();
- }
- return 1;
- } else {
- return region.size.height + margin.size.height;
- }
-}
-
-RID AtlasTexture::get_rid() const {
- if (atlas.is_valid()) {
- return atlas->get_rid();
- }
-
- return RID();
-}
-
-bool AtlasTexture::has_alpha() const {
- if (atlas.is_valid()) {
- return atlas->has_alpha();
- }
-
- return false;
-}
-
-void AtlasTexture::set_atlas(const Ref<Texture2D> &p_atlas) {
- ERR_FAIL_COND(p_atlas == this);
- if (atlas == p_atlas) {
- return;
- }
- // Support recursive AtlasTextures.
- if (Ref<AtlasTexture>(atlas).is_valid()) {
- atlas->disconnect(CoreStringNames::get_singleton()->changed, callable_mp((Resource *)this, &AtlasTexture::emit_changed));
- }
- atlas = p_atlas;
- if (Ref<AtlasTexture>(atlas).is_valid()) {
- atlas->connect(CoreStringNames::get_singleton()->changed, callable_mp((Resource *)this, &AtlasTexture::emit_changed));
- }
-
- emit_changed();
-}
-
-Ref<Texture2D> AtlasTexture::get_atlas() const {
- return atlas;
-}
-
-void AtlasTexture::set_region(const Rect2 &p_region) {
- if (region == p_region) {
- return;
- }
- region = p_region;
- emit_changed();
-}
-
-Rect2 AtlasTexture::get_region() const {
- return region;
-}
-
-void AtlasTexture::set_margin(const Rect2 &p_margin) {
- if (margin == p_margin) {
- return;
- }
- margin = p_margin;
- emit_changed();
-}
-
-Rect2 AtlasTexture::get_margin() const {
- return margin;
-}
-
-void AtlasTexture::set_filter_clip(const bool p_enable) {
- filter_clip = p_enable;
- emit_changed();
-}
-
-bool AtlasTexture::has_filter_clip() const {
- return filter_clip;
-}
-
-void AtlasTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_atlas", "atlas"), &AtlasTexture::set_atlas);
- ClassDB::bind_method(D_METHOD("get_atlas"), &AtlasTexture::get_atlas);
-
- ClassDB::bind_method(D_METHOD("set_region", "region"), &AtlasTexture::set_region);
- ClassDB::bind_method(D_METHOD("get_region"), &AtlasTexture::get_region);
-
- ClassDB::bind_method(D_METHOD("set_margin", "margin"), &AtlasTexture::set_margin);
- ClassDB::bind_method(D_METHOD("get_margin"), &AtlasTexture::get_margin);
-
- ClassDB::bind_method(D_METHOD("set_filter_clip", "enable"), &AtlasTexture::set_filter_clip);
- ClassDB::bind_method(D_METHOD("has_filter_clip"), &AtlasTexture::has_filter_clip);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_atlas", "get_atlas");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region", PROPERTY_HINT_NONE, "suffix:px"), "set_region", "get_region");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin", PROPERTY_HINT_NONE, "suffix:px"), "set_margin", "get_margin");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_clip"), "set_filter_clip", "has_filter_clip");
-}
-
-void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
- if (!atlas.is_valid()) {
- return;
- }
-
- Rect2 rc = region;
-
- if (rc.size.width == 0) {
- rc.size.width = atlas->get_width();
- }
-
- if (rc.size.height == 0) {
- rc.size.height = atlas->get_height();
- }
-
- atlas->draw_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), rc, p_modulate, p_transpose, filter_clip);
-}
-
-void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
- if (!atlas.is_valid()) {
- return;
- }
-
- Rect2 rc = region;
-
- if (rc.size.width == 0) {
- rc.size.width = atlas->get_width();
- }
-
- if (rc.size.height == 0) {
- rc.size.height = atlas->get_height();
- }
-
- Vector2 scale = p_rect.size / (region.size + margin.size);
- Rect2 dr(p_rect.position + margin.position * scale, rc.size * scale);
-
- atlas->draw_rect_region(p_canvas_item, dr, rc, p_modulate, p_transpose, filter_clip);
-}
-
-void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
- //this might not necessarily work well if using a rect, needs to be fixed properly
- if (!atlas.is_valid()) {
- return;
- }
-
- Rect2 dr;
- Rect2 src_c;
- get_rect_region(p_rect, p_src_rect, dr, src_c);
-
- atlas->draw_rect_region(p_canvas_item, dr, src_c, p_modulate, p_transpose, filter_clip);
-}
-
-bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
- if (!atlas.is_valid()) {
- return false;
- }
-
- Rect2 src = p_src_rect;
- if (src.size == Size2()) {
- src.size = region.size;
- }
- Vector2 scale = p_rect.size / src.size;
-
- src.position += (region.position - margin.position);
- Rect2 src_clipped = region.intersection(src);
- if (src_clipped.size == Size2()) {
- return false;
- }
-
- Vector2 ofs = (src_clipped.position - src.position);
- if (scale.x < 0) {
- ofs.x += (src_clipped.size.x - src.size.x);
- }
- if (scale.y < 0) {
- ofs.y += (src_clipped.size.y - src.size.y);
- }
-
- r_rect = Rect2(p_rect.position + ofs * scale, src_clipped.size * scale);
- r_src_rect = src_clipped;
- return true;
-}
-
-bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const {
- if (!atlas.is_valid()) {
- return true;
- }
-
- int x = p_x + region.position.x - margin.position.x;
- int y = p_y + region.position.y - margin.position.y;
-
- // margin edge may outside of atlas
- if (x < 0 || x >= atlas->get_width()) {
- return false;
- }
- if (y < 0 || y >= atlas->get_height()) {
- return false;
- }
-
- return atlas->is_pixel_opaque(x, y);
-}
-
-Ref<Image> AtlasTexture::get_image() const {
- if (!atlas.is_valid() || !atlas->get_image().is_valid()) {
- return Ref<Image>();
- }
-
- return atlas->get_image()->get_region(region);
-}
-
-AtlasTexture::AtlasTexture() {}
-
-/////////////////////////////////////////
-
-int MeshTexture::get_width() const {
- return size.width;
-}
-
-int MeshTexture::get_height() const {
- return size.height;
-}
-
-RID MeshTexture::get_rid() const {
- return RID();
-}
-
-bool MeshTexture::has_alpha() const {
- return false;
-}
-
-void MeshTexture::set_mesh(const Ref<Mesh> &p_mesh) {
- mesh = p_mesh;
-}
-
-Ref<Mesh> MeshTexture::get_mesh() const {
- return mesh;
-}
-
-void MeshTexture::set_image_size(const Size2 &p_size) {
- size = p_size;
-}
-
-Size2 MeshTexture::get_image_size() const {
- return size;
-}
-
-void MeshTexture::set_base_texture(const Ref<Texture2D> &p_texture) {
- base_texture = p_texture;
-}
-
-Ref<Texture2D> MeshTexture::get_base_texture() const {
- return base_texture;
-}
-
-void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
- if (mesh.is_null() || base_texture.is_null()) {
- return;
- }
- Transform2D xform;
- xform.set_origin(p_pos);
- if (p_transpose) {
- SWAP(xform.columns[0][1], xform.columns[1][0]);
- SWAP(xform.columns[0][0], xform.columns[1][1]);
- }
- RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid());
-}
-
-void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
- if (mesh.is_null() || base_texture.is_null()) {
- return;
- }
- Transform2D xform;
- Vector2 origin = p_rect.position;
- if (p_rect.size.x < 0) {
- origin.x += size.x;
- }
- if (p_rect.size.y < 0) {
- origin.y += size.y;
- }
- xform.set_origin(origin);
- xform.set_scale(p_rect.size / size);
-
- if (p_transpose) {
- SWAP(xform.columns[0][1], xform.columns[1][0]);
- SWAP(xform.columns[0][0], xform.columns[1][1]);
- }
- RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid());
-}
-
-void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
- if (mesh.is_null() || base_texture.is_null()) {
- return;
- }
- Transform2D xform;
- Vector2 origin = p_rect.position;
- if (p_rect.size.x < 0) {
- origin.x += size.x;
- }
- if (p_rect.size.y < 0) {
- origin.y += size.y;
- }
- xform.set_origin(origin);
- xform.set_scale(p_rect.size / size);
-
- if (p_transpose) {
- SWAP(xform.columns[0][1], xform.columns[1][0]);
- SWAP(xform.columns[0][0], xform.columns[1][1]);
- }
- RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid());
-}
-
-bool MeshTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
- r_rect = p_rect;
- r_src_rect = p_src_rect;
- return true;
-}
-
-bool MeshTexture::is_pixel_opaque(int p_x, int p_y) const {
- return true;
-}
-
-void MeshTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshTexture::set_mesh);
- ClassDB::bind_method(D_METHOD("get_mesh"), &MeshTexture::get_mesh);
- ClassDB::bind_method(D_METHOD("set_image_size", "size"), &MeshTexture::set_image_size);
- ClassDB::bind_method(D_METHOD("get_image_size"), &MeshTexture::get_image_size);
- ClassDB::bind_method(D_METHOD("set_base_texture", "texture"), &MeshTexture::set_base_texture);
- ClassDB::bind_method(D_METHOD("get_base_texture"), &MeshTexture::get_base_texture);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_base_texture", "get_base_texture");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1,suffix:px"), "set_image_size", "get_image_size");
-}
-
-MeshTexture::MeshTexture() {
-}
-
-//////////////////////////////////////////
-
-void CurveTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
-
- ClassDB::bind_method(D_METHOD("set_curve", "curve"), &CurveTexture::set_curve);
- ClassDB::bind_method(D_METHOD("get_curve"), &CurveTexture::get_curve);
-
- ClassDB::bind_method(D_METHOD("set_texture_mode", "texture_mode"), &CurveTexture::set_texture_mode);
- ClassDB::bind_method(D_METHOD("get_texture_mode"), &CurveTexture::get_texture_mode);
-
- ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
-
- BIND_ENUM_CONSTANT(TEXTURE_MODE_RGB);
- BIND_ENUM_CONSTANT(TEXTURE_MODE_RED);
-}
-
-void CurveTexture::set_width(int p_width) {
- ERR_FAIL_COND(p_width < 32 || p_width > 4096);
-
- if (_width == p_width) {
- return;
- }
-
- _width = p_width;
- _update();
-}
-
-int CurveTexture::get_width() const {
- return _width;
-}
-
-void CurveTexture::ensure_default_setup(float p_min, float p_max) {
- if (_curve.is_null()) {
- Ref<Curve> curve = Ref<Curve>(memnew(Curve));
- curve->add_point(Vector2(0, 1));
- curve->add_point(Vector2(1, 1));
- curve->set_min_value(p_min);
- curve->set_max_value(p_max);
- set_curve(curve);
- // Min and max is 0..1 by default
- }
-}
-
-void CurveTexture::set_curve(Ref<Curve> p_curve) {
- if (_curve != p_curve) {
- if (_curve.is_valid()) {
- _curve->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveTexture::_update));
- }
- _curve = p_curve;
- if (_curve.is_valid()) {
- _curve->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveTexture::_update));
- }
- _update();
- }
-}
-
-void CurveTexture::_update() {
- Vector<uint8_t> data;
- data.resize(_width * sizeof(float) * (texture_mode == TEXTURE_MODE_RGB ? 3 : 1));
-
- // The array is locked in that scope
- {
- uint8_t *wd8 = data.ptrw();
- float *wd = (float *)wd8;
-
- if (_curve.is_valid()) {
- Curve &curve = **_curve;
- for (int i = 0; i < _width; ++i) {
- float t = i / static_cast<float>(_width);
- if (texture_mode == TEXTURE_MODE_RGB) {
- wd[i * 3 + 0] = curve.sample_baked(t);
- wd[i * 3 + 1] = wd[i * 3 + 0];
- wd[i * 3 + 2] = wd[i * 3 + 0];
- } else {
- wd[i] = curve.sample_baked(t);
- }
- }
-
- } else {
- for (int i = 0; i < _width; ++i) {
- if (texture_mode == TEXTURE_MODE_RGB) {
- wd[i * 3 + 0] = 0;
- wd[i * 3 + 1] = 0;
- wd[i * 3 + 2] = 0;
- } else {
- wd[i] = 0;
- }
- }
- }
- }
-
- Ref<Image> image = memnew(Image(_width, 1, false, texture_mode == TEXTURE_MODE_RGB ? Image::FORMAT_RGBF : Image::FORMAT_RF, data));
-
- if (_texture.is_valid()) {
- if (_current_texture_mode != texture_mode || _current_width != _width) {
- RID new_texture = RS::get_singleton()->texture_2d_create(image);
- RS::get_singleton()->texture_replace(_texture, new_texture);
- } else {
- RS::get_singleton()->texture_2d_update(_texture, image);
- }
- } else {
- _texture = RS::get_singleton()->texture_2d_create(image);
- }
- _current_texture_mode = texture_mode;
- _current_width = _width;
-
- emit_changed();
-}
-
-Ref<Curve> CurveTexture::get_curve() const {
- return _curve;
-}
-
-void CurveTexture::set_texture_mode(TextureMode p_mode) {
- ERR_FAIL_COND(p_mode < TEXTURE_MODE_RGB || p_mode > TEXTURE_MODE_RED);
- if (texture_mode == p_mode) {
- return;
- }
- texture_mode = p_mode;
- _update();
-}
-CurveTexture::TextureMode CurveTexture::get_texture_mode() const {
- return texture_mode;
-}
-
-RID CurveTexture::get_rid() const {
- if (!_texture.is_valid()) {
- _texture = RS::get_singleton()->texture_2d_placeholder_create();
- }
- return _texture;
-}
-
-CurveTexture::CurveTexture() {}
-
-CurveTexture::~CurveTexture() {
- if (_texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(_texture);
- }
-}
-
-//////////////////
-
-void CurveXYZTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveXYZTexture::set_width);
-
- ClassDB::bind_method(D_METHOD("set_curve_x", "curve"), &CurveXYZTexture::set_curve_x);
- ClassDB::bind_method(D_METHOD("get_curve_x"), &CurveXYZTexture::get_curve_x);
-
- ClassDB::bind_method(D_METHOD("set_curve_y", "curve"), &CurveXYZTexture::set_curve_y);
- ClassDB::bind_method(D_METHOD("get_curve_y"), &CurveXYZTexture::get_curve_y);
-
- ClassDB::bind_method(D_METHOD("set_curve_z", "curve"), &CurveXYZTexture::set_curve_z);
- ClassDB::bind_method(D_METHOD("get_curve_z"), &CurveXYZTexture::get_curve_z);
-
- ClassDB::bind_method(D_METHOD("_update"), &CurveXYZTexture::_update);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_z", "get_curve_z");
-}
-
-void CurveXYZTexture::set_width(int p_width) {
- ERR_FAIL_COND(p_width < 32 || p_width > 4096);
-
- if (_width == p_width) {
- return;
- }
-
- _width = p_width;
- _update();
-}
-
-int CurveXYZTexture::get_width() const {
- return _width;
-}
-
-void CurveXYZTexture::ensure_default_setup(float p_min, float p_max) {
- if (_curve_x.is_null()) {
- Ref<Curve> curve = Ref<Curve>(memnew(Curve));
- curve->add_point(Vector2(0, 1));
- curve->add_point(Vector2(1, 1));
- curve->set_min_value(p_min);
- curve->set_max_value(p_max);
- set_curve_x(curve);
- }
-
- if (_curve_y.is_null()) {
- Ref<Curve> curve = Ref<Curve>(memnew(Curve));
- curve->add_point(Vector2(0, 1));
- curve->add_point(Vector2(1, 1));
- curve->set_min_value(p_min);
- curve->set_max_value(p_max);
- set_curve_y(curve);
- }
-
- if (_curve_z.is_null()) {
- Ref<Curve> curve = Ref<Curve>(memnew(Curve));
- curve->add_point(Vector2(0, 1));
- curve->add_point(Vector2(1, 1));
- curve->set_min_value(p_min);
- curve->set_max_value(p_max);
- set_curve_z(curve);
- }
-}
-
-void CurveXYZTexture::set_curve_x(Ref<Curve> p_curve) {
- if (_curve_x != p_curve) {
- if (_curve_x.is_valid()) {
- _curve_x->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update));
- }
- _curve_x = p_curve;
- if (_curve_x.is_valid()) {
- _curve_x->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
- }
- _update();
- }
-}
-
-void CurveXYZTexture::set_curve_y(Ref<Curve> p_curve) {
- if (_curve_y != p_curve) {
- if (_curve_y.is_valid()) {
- _curve_y->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update));
- }
- _curve_y = p_curve;
- if (_curve_y.is_valid()) {
- _curve_y->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
- }
- _update();
- }
-}
-
-void CurveXYZTexture::set_curve_z(Ref<Curve> p_curve) {
- if (_curve_z != p_curve) {
- if (_curve_z.is_valid()) {
- _curve_z->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update));
- }
- _curve_z = p_curve;
- if (_curve_z.is_valid()) {
- _curve_z->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
- }
- _update();
- }
-}
-
-void CurveXYZTexture::_update() {
- Vector<uint8_t> data;
- data.resize(_width * sizeof(float) * 3);
-
- // The array is locked in that scope
- {
- uint8_t *wd8 = data.ptrw();
- float *wd = (float *)wd8;
-
- if (_curve_x.is_valid()) {
- Curve &curve_x = **_curve_x;
- for (int i = 0; i < _width; ++i) {
- float t = i / static_cast<float>(_width);
- wd[i * 3 + 0] = curve_x.sample_baked(t);
- }
-
- } else {
- for (int i = 0; i < _width; ++i) {
- wd[i * 3 + 0] = 0;
- }
- }
-
- if (_curve_y.is_valid()) {
- Curve &curve_y = **_curve_y;
- for (int i = 0; i < _width; ++i) {
- float t = i / static_cast<float>(_width);
- wd[i * 3 + 1] = curve_y.sample_baked(t);
- }
-
- } else {
- for (int i = 0; i < _width; ++i) {
- wd[i * 3 + 1] = 0;
- }
- }
-
- if (_curve_z.is_valid()) {
- Curve &curve_z = **_curve_z;
- for (int i = 0; i < _width; ++i) {
- float t = i / static_cast<float>(_width);
- wd[i * 3 + 2] = curve_z.sample_baked(t);
- }
-
- } else {
- for (int i = 0; i < _width; ++i) {
- wd[i * 3 + 2] = 0;
- }
- }
- }
-
- Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RGBF, data));
-
- if (_texture.is_valid()) {
- if (_current_width != _width) {
- RID new_texture = RS::get_singleton()->texture_2d_create(image);
- RS::get_singleton()->texture_replace(_texture, new_texture);
- } else {
- RS::get_singleton()->texture_2d_update(_texture, image);
- }
- } else {
- _texture = RS::get_singleton()->texture_2d_create(image);
- }
- _current_width = _width;
-
- emit_changed();
-}
-
-Ref<Curve> CurveXYZTexture::get_curve_x() const {
- return _curve_x;
-}
-
-Ref<Curve> CurveXYZTexture::get_curve_y() const {
- return _curve_y;
-}
-
-Ref<Curve> CurveXYZTexture::get_curve_z() const {
- return _curve_z;
-}
-
-RID CurveXYZTexture::get_rid() const {
- if (!_texture.is_valid()) {
- _texture = RS::get_singleton()->texture_2d_placeholder_create();
- }
- return _texture;
-}
-
-CurveXYZTexture::CurveXYZTexture() {}
-
-CurveXYZTexture::~CurveXYZTexture() {
- if (_texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(_texture);
- }
-}
-
-//////////////////
-
-GradientTexture1D::GradientTexture1D() {
- _queue_update();
-}
-
-GradientTexture1D::~GradientTexture1D() {
- if (texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(texture);
- }
-}
-
-void GradientTexture1D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_gradient", "gradient"), &GradientTexture1D::set_gradient);
- ClassDB::bind_method(D_METHOD("get_gradient"), &GradientTexture1D::get_gradient);
-
- ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture1D::set_width);
- // The `get_width()` method is already exposed by the parent class Texture2D.
-
- ClassDB::bind_method(D_METHOD("set_use_hdr", "enabled"), &GradientTexture1D::set_use_hdr);
- ClassDB::bind_method(D_METHOD("is_using_hdr"), &GradientTexture1D::is_using_hdr);
-
- ClassDB::bind_method(D_METHOD("_update"), &GradientTexture1D::_update);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,16384,suffix:px"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
-}
-
-void GradientTexture1D::set_gradient(Ref<Gradient> p_gradient) {
- if (p_gradient == gradient) {
- return;
- }
- if (gradient.is_valid()) {
- gradient->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GradientTexture1D::_update));
- }
- gradient = p_gradient;
- if (gradient.is_valid()) {
- gradient->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GradientTexture1D::_update));
- }
- _update();
- emit_changed();
-}
-
-Ref<Gradient> GradientTexture1D::get_gradient() const {
- return gradient;
-}
-
-void GradientTexture1D::_queue_update() {
- if (update_pending) {
- return;
- }
-
- update_pending = true;
- call_deferred(SNAME("_update"));
-}
-
-void GradientTexture1D::_update() {
- update_pending = false;
-
- if (gradient.is_null()) {
- return;
- }
-
- if (use_hdr) {
- // High dynamic range.
- Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBAF));
- Gradient &g = **gradient;
- // `create()` isn't available for non-uint8_t data, so fill in the data manually.
- for (int i = 0; i < width; i++) {
- float ofs = float(i) / (width - 1);
- image->set_pixel(i, 0, g.get_color_at_offset(ofs));
- }
-
- if (texture.is_valid()) {
- RID new_texture = RS::get_singleton()->texture_2d_create(image);
- RS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = RS::get_singleton()->texture_2d_create(image);
- }
- } else {
- // Low dynamic range. "Overbright" colors will be clamped.
- Vector<uint8_t> data;
- data.resize(width * 4);
- {
- uint8_t *wd8 = data.ptrw();
- Gradient &g = **gradient;
-
- for (int i = 0; i < width; i++) {
- float ofs = float(i) / (width - 1);
- Color color = g.get_color_at_offset(ofs);
-
- wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255));
- wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255));
- wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255));
- wd8[i * 4 + 3] = uint8_t(CLAMP(color.a * 255.0, 0, 255));
- }
- }
-
- Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
-
- if (texture.is_valid()) {
- RID new_texture = RS::get_singleton()->texture_2d_create(image);
- RS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = RS::get_singleton()->texture_2d_create(image);
- }
- }
-
- emit_changed();
-}
-
-void GradientTexture1D::set_width(int p_width) {
- ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
- width = p_width;
- _queue_update();
-}
-
-int GradientTexture1D::get_width() const {
- return width;
-}
-
-void GradientTexture1D::set_use_hdr(bool p_enabled) {
- if (p_enabled == use_hdr) {
- return;
- }
-
- use_hdr = p_enabled;
- _queue_update();
-}
-
-bool GradientTexture1D::is_using_hdr() const {
- return use_hdr;
-}
-
-Ref<Image> GradientTexture1D::get_image() const {
- if (!texture.is_valid()) {
- return Ref<Image>();
- }
- return RenderingServer::get_singleton()->texture_2d_get(texture);
-}
-
-//////////////////
-
-GradientTexture2D::GradientTexture2D() {
- _queue_update();
-}
-
-GradientTexture2D::~GradientTexture2D() {
- if (texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(texture);
- }
-}
-
-void GradientTexture2D::set_gradient(Ref<Gradient> p_gradient) {
- if (gradient == p_gradient) {
- return;
- }
- if (gradient.is_valid()) {
- gradient->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GradientTexture2D::_queue_update));
- }
- gradient = p_gradient;
- if (gradient.is_valid()) {
- gradient->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GradientTexture2D::_queue_update));
- }
- _update();
- emit_changed();
-}
-
-Ref<Gradient> GradientTexture2D::get_gradient() const {
- return gradient;
-}
-
-void GradientTexture2D::_queue_update() {
- if (update_pending) {
- return;
- }
- update_pending = true;
- call_deferred(SNAME("_update"));
-}
-
-void GradientTexture2D::_update() {
- update_pending = false;
-
- if (gradient.is_null()) {
- return;
- }
- Ref<Image> image;
- image.instantiate();
-
- if (gradient->get_point_count() <= 1) { // No need to interpolate.
- image->initialize_data(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8);
- image->fill((gradient->get_point_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1));
- } else {
- if (use_hdr) {
- image->initialize_data(width, height, false, Image::FORMAT_RGBAF);
- Gradient &g = **gradient;
- // `create()` isn't available for non-uint8_t data, so fill in the data manually.
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- float ofs = _get_gradient_offset_at(x, y);
- image->set_pixel(x, y, g.get_color_at_offset(ofs));
- }
- }
- } else {
- Vector<uint8_t> data;
- data.resize(width * height * 4);
- {
- uint8_t *wd8 = data.ptrw();
- Gradient &g = **gradient;
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- float ofs = _get_gradient_offset_at(x, y);
- const Color &c = g.get_color_at_offset(ofs);
-
- wd8[(x + (y * width)) * 4 + 0] = uint8_t(CLAMP(c.r * 255.0, 0, 255));
- wd8[(x + (y * width)) * 4 + 1] = uint8_t(CLAMP(c.g * 255.0, 0, 255));
- wd8[(x + (y * width)) * 4 + 2] = uint8_t(CLAMP(c.b * 255.0, 0, 255));
- wd8[(x + (y * width)) * 4 + 3] = uint8_t(CLAMP(c.a * 255.0, 0, 255));
- }
- }
- }
- image->set_data(width, height, false, Image::FORMAT_RGBA8, data);
- }
- }
-
- if (texture.is_valid()) {
- RID new_texture = RS::get_singleton()->texture_2d_create(image);
- RS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = RS::get_singleton()->texture_2d_create(image);
- }
- emit_changed();
-}
-
-float GradientTexture2D::_get_gradient_offset_at(int x, int y) const {
- if (fill_to == fill_from) {
- return 0;
- }
- float ofs = 0;
- Vector2 pos;
- if (width > 1) {
- pos.x = static_cast<float>(x) / (width - 1);
- }
- if (height > 1) {
- pos.y = static_cast<float>(y) / (height - 1);
- }
- if (fill == Fill::FILL_LINEAR) {
- Vector2 segment[2];
- segment[0] = fill_from;
- segment[1] = fill_to;
- Vector2 closest = Geometry2D::get_closest_point_to_segment_uncapped(pos, &segment[0]);
- ofs = (closest - fill_from).length() / (fill_to - fill_from).length();
- if ((closest - fill_from).dot(fill_to - fill_from) < 0) {
- ofs *= -1;
- }
- } else if (fill == Fill::FILL_RADIAL) {
- ofs = (pos - fill_from).length() / (fill_to - fill_from).length();
- } else if (fill == Fill::FILL_SQUARE) {
- ofs = MAX(Math::abs(pos.x - fill_from.x), Math::abs(pos.y - fill_from.y)) / MAX(Math::abs(fill_to.x - fill_from.x), Math::abs(fill_to.y - fill_from.y));
- }
- if (repeat == Repeat::REPEAT_NONE) {
- ofs = CLAMP(ofs, 0.0, 1.0);
- } else if (repeat == Repeat::REPEAT) {
- ofs = Math::fmod(ofs, 1.0f);
- if (ofs < 0) {
- ofs = 1 + ofs;
- }
- } else if (repeat == Repeat::REPEAT_MIRROR) {
- ofs = Math::abs(ofs);
- ofs = Math::fmod(ofs, 2.0f);
- if (ofs > 1.0) {
- ofs = 2.0 - ofs;
- }
- }
- return ofs;
-}
-
-void GradientTexture2D::set_width(int p_width) {
- ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
- width = p_width;
- _queue_update();
-}
-
-int GradientTexture2D::get_width() const {
- return width;
-}
-
-void GradientTexture2D::set_height(int p_height) {
- ERR_FAIL_COND_MSG(p_height <= 0 || p_height > 16384, "Texture dimensions have to be within 1 to 16384 range.");
- height = p_height;
- _queue_update();
-}
-int GradientTexture2D::get_height() const {
- return height;
-}
-
-void GradientTexture2D::set_use_hdr(bool p_enabled) {
- if (p_enabled == use_hdr) {
- return;
- }
-
- use_hdr = p_enabled;
- _queue_update();
-}
-
-bool GradientTexture2D::is_using_hdr() const {
- return use_hdr;
-}
-
-void GradientTexture2D::set_fill_from(Vector2 p_fill_from) {
- fill_from = p_fill_from;
- _queue_update();
-}
-
-Vector2 GradientTexture2D::get_fill_from() const {
- return fill_from;
-}
-
-void GradientTexture2D::set_fill_to(Vector2 p_fill_to) {
- fill_to = p_fill_to;
- _queue_update();
-}
-
-Vector2 GradientTexture2D::get_fill_to() const {
- return fill_to;
-}
-
-void GradientTexture2D::set_fill(Fill p_fill) {
- fill = p_fill;
- _queue_update();
-}
-
-GradientTexture2D::Fill GradientTexture2D::get_fill() const {
- return fill;
-}
-
-void GradientTexture2D::set_repeat(Repeat p_repeat) {
- repeat = p_repeat;
- _queue_update();
-}
-
-GradientTexture2D::Repeat GradientTexture2D::get_repeat() const {
- return repeat;
-}
-
-RID GradientTexture2D::get_rid() const {
- if (!texture.is_valid()) {
- texture = RS::get_singleton()->texture_2d_placeholder_create();
- }
- return texture;
-}
-
-Ref<Image> GradientTexture2D::get_image() const {
- if (!texture.is_valid()) {
- return Ref<Image>();
- }
- return RenderingServer::get_singleton()->texture_2d_get(texture);
-}
-
-void GradientTexture2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_gradient", "gradient"), &GradientTexture2D::set_gradient);
- ClassDB::bind_method(D_METHOD("get_gradient"), &GradientTexture2D::get_gradient);
-
- ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture2D::set_width);
- ClassDB::bind_method(D_METHOD("set_height", "height"), &GradientTexture2D::set_height);
-
- ClassDB::bind_method(D_METHOD("set_use_hdr", "enabled"), &GradientTexture2D::set_use_hdr);
- ClassDB::bind_method(D_METHOD("is_using_hdr"), &GradientTexture2D::is_using_hdr);
-
- ClassDB::bind_method(D_METHOD("set_fill", "fill"), &GradientTexture2D::set_fill);
- ClassDB::bind_method(D_METHOD("get_fill"), &GradientTexture2D::get_fill);
- ClassDB::bind_method(D_METHOD("set_fill_from", "fill_from"), &GradientTexture2D::set_fill_from);
- ClassDB::bind_method(D_METHOD("get_fill_from"), &GradientTexture2D::get_fill_from);
- ClassDB::bind_method(D_METHOD("set_fill_to", "fill_to"), &GradientTexture2D::set_fill_to);
- ClassDB::bind_method(D_METHOD("get_fill_to"), &GradientTexture2D::get_fill_to);
-
- ClassDB::bind_method(D_METHOD("set_repeat", "repeat"), &GradientTexture2D::set_repeat);
- ClassDB::bind_method(D_METHOD("get_repeat"), &GradientTexture2D::get_repeat);
-
- ClassDB::bind_method(D_METHOD("_update"), &GradientTexture2D::_update);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,or_greater,suffix:px"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,or_greater,suffix:px"), "set_height", "get_height");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
-
- ADD_GROUP("Fill", "fill_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fill", PROPERTY_HINT_ENUM, "Linear,Radial,Square"), "set_fill", "get_fill");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "fill_from"), "set_fill_from", "get_fill_from");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "fill_to"), "set_fill_to", "get_fill_to");
-
- ADD_GROUP("Repeat", "repeat_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "repeat", PROPERTY_HINT_ENUM, "No Repeat,Repeat,Mirror Repeat"), "set_repeat", "get_repeat");
-
- BIND_ENUM_CONSTANT(FILL_LINEAR);
- BIND_ENUM_CONSTANT(FILL_RADIAL);
- BIND_ENUM_CONSTANT(FILL_SQUARE);
-
- BIND_ENUM_CONSTANT(REPEAT_NONE);
- BIND_ENUM_CONSTANT(REPEAT);
- BIND_ENUM_CONSTANT(REPEAT_MIRROR);
-}
-
-//////////////////////////////////////
-
-void AnimatedTexture::_update_proxy() {
- RWLockRead r(rw_lock);
-
- float delta;
- if (prev_ticks == 0) {
- delta = 0;
- prev_ticks = OS::get_singleton()->get_ticks_usec();
- } else {
- uint64_t ticks = OS::get_singleton()->get_ticks_usec();
- delta = float(double(ticks - prev_ticks) / 1000000.0);
- prev_ticks = ticks;
- }
-
- time += delta;
-
- float speed = speed_scale == 0 ? 0 : abs(1.0 / speed_scale);
-
- int iter_max = frame_count;
- while (iter_max && !pause) {
- float frame_limit = frames[current_frame].duration * speed;
-
- if (time > frame_limit) {
- if (speed_scale > 0.0) {
- current_frame++;
- } else {
- current_frame--;
- }
- if (current_frame >= frame_count) {
- if (one_shot) {
- current_frame = frame_count - 1;
- } else {
- current_frame = 0;
- }
- } else if (current_frame < 0) {
- if (one_shot) {
- current_frame = 0;
- } else {
- current_frame = frame_count - 1;
- }
- }
- time -= frame_limit;
-
- } else {
- break;
- }
- iter_max--;
- }
-
- if (frames[current_frame].texture.is_valid()) {
- RenderingServer::get_singleton()->texture_proxy_update(proxy, frames[current_frame].texture->get_rid());
- }
-}
-
-void AnimatedTexture::set_frames(int p_frames) {
- ERR_FAIL_COND(p_frames < 1 || p_frames > MAX_FRAMES);
-
- RWLockWrite r(rw_lock);
-
- frame_count = p_frames;
-}
-
-int AnimatedTexture::get_frames() const {
- return frame_count;
-}
-
-void AnimatedTexture::set_current_frame(int p_frame) {
- ERR_FAIL_COND(p_frame < 0 || p_frame >= frame_count);
-
- RWLockWrite r(rw_lock);
-
- current_frame = p_frame;
- time = 0;
-}
-
-int AnimatedTexture::get_current_frame() const {
- return current_frame;
-}
-
-void AnimatedTexture::set_pause(bool p_pause) {
- RWLockWrite r(rw_lock);
- pause = p_pause;
-}
-
-bool AnimatedTexture::get_pause() const {
- return pause;
-}
-
-void AnimatedTexture::set_one_shot(bool p_one_shot) {
- RWLockWrite r(rw_lock);
- one_shot = p_one_shot;
-}
-
-bool AnimatedTexture::get_one_shot() const {
- return one_shot;
-}
-
-void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture) {
- ERR_FAIL_COND(p_texture == this);
- ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
-
- RWLockWrite w(rw_lock);
-
- frames[p_frame].texture = p_texture;
-}
-
-Ref<Texture2D> AnimatedTexture::get_frame_texture(int p_frame) const {
- ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, Ref<Texture2D>());
-
- RWLockRead r(rw_lock);
-
- return frames[p_frame].texture;
-}
-
-void AnimatedTexture::set_frame_duration(int p_frame, float p_duration) {
- ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
-
- RWLockWrite r(rw_lock);
-
- frames[p_frame].duration = p_duration;
-}
-
-float AnimatedTexture::get_frame_duration(int p_frame) const {
- ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0);
-
- RWLockRead r(rw_lock);
-
- return frames[p_frame].duration;
-}
-
-void AnimatedTexture::set_speed_scale(float p_scale) {
- ERR_FAIL_COND(p_scale < -1000 || p_scale >= 1000);
-
- RWLockWrite r(rw_lock);
-
- speed_scale = p_scale;
-}
-
-float AnimatedTexture::get_speed_scale() const {
- return speed_scale;
-}
-
-int AnimatedTexture::get_width() const {
- RWLockRead r(rw_lock);
-
- if (!frames[current_frame].texture.is_valid()) {
- return 1;
- }
-
- return frames[current_frame].texture->get_width();
-}
-
-int AnimatedTexture::get_height() const {
- RWLockRead r(rw_lock);
-
- if (!frames[current_frame].texture.is_valid()) {
- return 1;
- }
-
- return frames[current_frame].texture->get_height();
-}
-
-RID AnimatedTexture::get_rid() const {
- return proxy;
-}
-
-bool AnimatedTexture::has_alpha() const {
- RWLockRead r(rw_lock);
-
- if (!frames[current_frame].texture.is_valid()) {
- return false;
- }
-
- return frames[current_frame].texture->has_alpha();
-}
-
-Ref<Image> AnimatedTexture::get_image() const {
- RWLockRead r(rw_lock);
-
- if (!frames[current_frame].texture.is_valid()) {
- return Ref<Image>();
- }
-
- return frames[current_frame].texture->get_image();
-}
-
-bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
- RWLockRead r(rw_lock);
-
- if (frames[current_frame].texture.is_valid()) {
- return frames[current_frame].texture->is_pixel_opaque(p_x, p_y);
- }
- return true;
-}
-
-void AnimatedTexture::_validate_property(PropertyInfo &p_property) const {
- String prop = p_property.name;
- if (prop.begins_with("frame_")) {
- int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int();
- if (frame >= frame_count) {
- p_property.usage = PROPERTY_USAGE_NONE;
- }
- }
-}
-
-void AnimatedTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_frames", "frames"), &AnimatedTexture::set_frames);
- ClassDB::bind_method(D_METHOD("get_frames"), &AnimatedTexture::get_frames);
-
- ClassDB::bind_method(D_METHOD("set_current_frame", "frame"), &AnimatedTexture::set_current_frame);
- ClassDB::bind_method(D_METHOD("get_current_frame"), &AnimatedTexture::get_current_frame);
-
- ClassDB::bind_method(D_METHOD("set_pause", "pause"), &AnimatedTexture::set_pause);
- ClassDB::bind_method(D_METHOD("get_pause"), &AnimatedTexture::get_pause);
-
- ClassDB::bind_method(D_METHOD("set_one_shot", "one_shot"), &AnimatedTexture::set_one_shot);
- ClassDB::bind_method(D_METHOD("get_one_shot"), &AnimatedTexture::get_one_shot);
-
- ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &AnimatedTexture::set_speed_scale);
- ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedTexture::get_speed_scale);
-
- ClassDB::bind_method(D_METHOD("set_frame_texture", "frame", "texture"), &AnimatedTexture::set_frame_texture);
- ClassDB::bind_method(D_METHOD("get_frame_texture", "frame"), &AnimatedTexture::get_frame_texture);
-
- ClassDB::bind_method(D_METHOD("set_frame_duration", "frame", "duration"), &AnimatedTexture::set_frame_duration);
- ClassDB::bind_method(D_METHOD("get_frame_duration", "frame"), &AnimatedTexture::get_frame_duration);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_frame", "get_current_frame");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-60,60,0.1,or_less,or_greater"), "set_speed_scale", "get_speed_scale");
-
- for (int i = 0; i < MAX_FRAMES; i++) {
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/duration", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_duration", "get_frame_duration", i);
- }
-
- BIND_CONSTANT(MAX_FRAMES);
-}
-
-AnimatedTexture::AnimatedTexture() {
- //proxy = RS::get_singleton()->texture_create();
- proxy_ph = RS::get_singleton()->texture_2d_placeholder_create();
- proxy = RS::get_singleton()->texture_proxy_create(proxy_ph);
-
- RenderingServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true);
- RenderingServer::get_singleton()->connect("frame_pre_draw", callable_mp(this, &AnimatedTexture::_update_proxy));
-}
-
-AnimatedTexture::~AnimatedTexture() {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(proxy);
- RS::get_singleton()->free(proxy_ph);
-}
-
-///////////////////////////////
-
Image::Format TextureLayered::get_format() const {
Image::Format ret = Image::FORMAT_MAX;
GDVIRTUAL_REQUIRED_CALL(_get_format, ret);
@@ -2896,654 +259,3 @@ void TextureLayered::_bind_methods() {
GDVIRTUAL_BIND(_has_mipmaps);
GDVIRTUAL_BIND(_get_layer_data, "layer_index");
}
-
-///////////////////////////////
-Image::Format ImageTextureLayered::get_format() const {
- return format;
-}
-
-int ImageTextureLayered::get_width() const {
- return width;
-}
-
-int ImageTextureLayered::get_height() const {
- return height;
-}
-
-int ImageTextureLayered::get_layers() const {
- return layers;
-}
-
-bool ImageTextureLayered::has_mipmaps() const {
- return mipmaps;
-}
-
-ImageTextureLayered::LayeredType ImageTextureLayered::get_layered_type() const {
- return layered_type;
-}
-
-Error ImageTextureLayered::_create_from_images(const TypedArray<Image> &p_images) {
- Vector<Ref<Image>> images;
- for (int i = 0; i < p_images.size(); i++) {
- Ref<Image> img = p_images[i];
- ERR_FAIL_COND_V(img.is_null(), ERR_INVALID_PARAMETER);
- images.push_back(img);
- }
-
- return create_from_images(images);
-}
-
-TypedArray<Image> ImageTextureLayered::_get_images() const {
- TypedArray<Image> images;
- for (int i = 0; i < layers; i++) {
- images.push_back(get_layer_data(i));
- }
- return images;
-}
-
-void ImageTextureLayered::_set_images(const TypedArray<Image> &p_images) {
- ERR_FAIL_COND(_create_from_images(p_images) != OK);
-}
-
-Error ImageTextureLayered::create_from_images(Vector<Ref<Image>> p_images) {
- int new_layers = p_images.size();
- ERR_FAIL_COND_V(new_layers == 0, ERR_INVALID_PARAMETER);
- if (layered_type == LAYERED_TYPE_CUBEMAP) {
- ERR_FAIL_COND_V_MSG(new_layers != 6, ERR_INVALID_PARAMETER,
- "Cubemaps require exactly 6 layers");
- } else if (layered_type == LAYERED_TYPE_CUBEMAP_ARRAY) {
- ERR_FAIL_COND_V_MSG((new_layers % 6) != 0, ERR_INVALID_PARAMETER,
- "Cubemap array layers must be a multiple of 6");
- }
-
- ERR_FAIL_COND_V(p_images[0].is_null() || p_images[0]->is_empty(), ERR_INVALID_PARAMETER);
-
- Image::Format new_format = p_images[0]->get_format();
- int new_width = p_images[0]->get_width();
- int new_height = p_images[0]->get_height();
- bool new_mipmaps = p_images[0]->has_mipmaps();
-
- for (int i = 1; i < p_images.size(); i++) {
- ERR_FAIL_COND_V_MSG(p_images[i]->get_format() != new_format, ERR_INVALID_PARAMETER,
- "All images must share the same format");
- ERR_FAIL_COND_V_MSG(p_images[i]->get_width() != new_width || p_images[i]->get_height() != new_height, ERR_INVALID_PARAMETER,
- "All images must share the same dimensions");
- ERR_FAIL_COND_V_MSG(p_images[i]->has_mipmaps() != new_mipmaps, ERR_INVALID_PARAMETER,
- "All images must share the usage of mipmaps");
- }
-
- if (texture.is_valid()) {
- RID new_texture = RS::get_singleton()->texture_2d_layered_create(p_images, RS::TextureLayeredType(layered_type));
- ERR_FAIL_COND_V(!new_texture.is_valid(), ERR_CANT_CREATE);
- RS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = RS::get_singleton()->texture_2d_layered_create(p_images, RS::TextureLayeredType(layered_type));
- ERR_FAIL_COND_V(!texture.is_valid(), ERR_CANT_CREATE);
- }
-
- format = new_format;
- width = new_width;
- height = new_height;
- layers = new_layers;
- mipmaps = new_mipmaps;
- return OK;
-}
-
-void ImageTextureLayered::update_layer(const Ref<Image> &p_image, int p_layer) {
- ERR_FAIL_COND_MSG(texture.is_null(), "Texture is not initialized.");
- ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image.");
- ERR_FAIL_COND_MSG(p_image->get_format() != format, "Image format must match texture's image format.");
- ERR_FAIL_COND_MSG(p_image->get_width() != width || p_image->get_height() != height, "Image size must match texture's image size.");
- ERR_FAIL_COND_MSG(p_image->has_mipmaps() != mipmaps, "Image mipmap configuration must match texture's image mipmap configuration.");
- ERR_FAIL_INDEX_MSG(p_layer, layers, "Layer index is out of bounds.");
- RS::get_singleton()->texture_2d_update(texture, p_image, p_layer);
-}
-
-Ref<Image> ImageTextureLayered::get_layer_data(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, layers, Ref<Image>());
- return RS::get_singleton()->texture_2d_layer_get(texture, p_layer);
-}
-
-RID ImageTextureLayered::get_rid() const {
- if (texture.is_null()) {
- texture = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));
- }
- return texture;
-}
-
-void ImageTextureLayered::set_path(const String &p_path, bool p_take_over) {
- if (texture.is_valid()) {
- RS::get_singleton()->texture_set_path(texture, p_path);
- }
-
- Resource::set_path(p_path, p_take_over);
-}
-
-void ImageTextureLayered::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_from_images", "images"), &ImageTextureLayered::_create_from_images);
- ClassDB::bind_method(D_METHOD("update_layer", "image", "layer"), &ImageTextureLayered::update_layer);
-
- ClassDB::bind_method(D_METHOD("_get_images"), &ImageTextureLayered::_get_images);
- ClassDB::bind_method(D_METHOD("_set_images", "images"), &ImageTextureLayered::_set_images);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_ARRAY_TYPE, "Image", PROPERTY_USAGE_INTERNAL), "_set_images", "_get_images");
-}
-
-ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) {
- layered_type = p_layered_type;
-}
-
-ImageTextureLayered::~ImageTextureLayered() {
- if (texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(texture);
- }
-}
-
-void Texture2DArray::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_placeholder"), &Texture2DArray::create_placeholder);
-}
-
-Ref<Resource> Texture2DArray::create_placeholder() const {
- Ref<PlaceholderTexture2DArray> placeholder;
- placeholder.instantiate();
- placeholder->set_size(Size2i(get_width(), get_height()));
- placeholder->set_layers(get_layers());
- return placeholder;
-}
-
-void Cubemap::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_placeholder"), &Cubemap::create_placeholder);
-}
-
-Ref<Resource> Cubemap::create_placeholder() const {
- Ref<PlaceholderCubemap> placeholder;
- placeholder.instantiate();
- placeholder->set_size(Size2i(get_width(), get_height()));
- placeholder->set_layers(get_layers());
- return placeholder;
-}
-
-void CubemapArray::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_placeholder"), &CubemapArray::create_placeholder);
-}
-
-Ref<Resource> CubemapArray::create_placeholder() const {
- Ref<PlaceholderCubemapArray> placeholder;
- placeholder.instantiate();
- placeholder->set_size(Size2i(get_width(), get_height()));
- placeholder->set_layers(get_layers());
- return placeholder;
-}
-
-///////////////////////////////////////////
-
-void CompressedTextureLayered::set_path(const String &p_path, bool p_take_over) {
- if (texture.is_valid()) {
- RenderingServer::get_singleton()->texture_set_path(texture, p_path);
- }
-
- Resource::set_path(p_path, p_take_over);
-}
-
-Image::Format CompressedTextureLayered::get_format() const {
- return format;
-}
-
-Error CompressedTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit) {
- ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER);
-
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));
-
- uint8_t header[4];
- f->get_buffer(header, 4);
- if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L') {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture layered file is corrupt (Bad header).");
- }
-
- uint32_t version = f->get_32();
-
- if (version > FORMAT_VERSION) {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new.");
- }
-
- uint32_t layer_count = f->get_32(); //layer count
- uint32_t type = f->get_32(); //layer count
- ERR_FAIL_COND_V((int)type != layered_type, ERR_INVALID_DATA);
-
- uint32_t df = f->get_32(); //data format
- mipmap_limit = int(f->get_32());
- //reserved
- f->get_32();
- f->get_32();
- f->get_32();
-
- if (!(df & FORMAT_BIT_STREAM)) {
- p_size_limit = 0;
- }
-
- images.resize(layer_count);
-
- for (uint32_t i = 0; i < layer_count; i++) {
- Ref<Image> image = CompressedTexture2D::load_image_from_file(f, p_size_limit);
- ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);
- images.write[i] = image;
- }
-
- return OK;
-}
-
-Error CompressedTextureLayered::load(const String &p_path) {
- Vector<Ref<Image>> images;
-
- int mipmap_limit;
-
- Error err = _load_data(p_path, images, mipmap_limit);
- if (err) {
- return err;
- }
-
- if (texture.is_valid()) {
- RID new_texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TextureLayeredType(layered_type));
- RS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TextureLayeredType(layered_type));
- }
-
- w = images[0]->get_width();
- h = images[0]->get_height();
- mipmaps = images[0]->has_mipmaps();
- format = images[0]->get_format();
- layers = images.size();
-
- path_to_file = p_path;
-
- if (get_path().is_empty()) {
- //temporarily set path if no path set for resource, helps find errors
- RenderingServer::get_singleton()->texture_set_path(texture, p_path);
- }
-
- notify_property_list_changed();
- emit_changed();
- return OK;
-}
-
-String CompressedTextureLayered::get_load_path() const {
- return path_to_file;
-}
-
-int CompressedTextureLayered::get_width() const {
- return w;
-}
-
-int CompressedTextureLayered::get_height() const {
- return h;
-}
-
-int CompressedTextureLayered::get_layers() const {
- return layers;
-}
-
-bool CompressedTextureLayered::has_mipmaps() const {
- return mipmaps;
-}
-
-TextureLayered::LayeredType CompressedTextureLayered::get_layered_type() const {
- return layered_type;
-}
-
-RID CompressedTextureLayered::get_rid() const {
- if (!texture.is_valid()) {
- texture = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));
- }
- return texture;
-}
-
-Ref<Image> CompressedTextureLayered::get_layer_data(int p_layer) const {
- if (texture.is_valid()) {
- return RS::get_singleton()->texture_2d_layer_get(texture, p_layer);
- } else {
- return Ref<Image>();
- }
-}
-
-void CompressedTextureLayered::reload_from_file() {
- String path = get_path();
- if (!path.is_resource_file()) {
- return;
- }
-
- path = ResourceLoader::path_remap(path); //remap for translation
- path = ResourceLoader::import_remap(path); //remap for import
- if (!path.is_resource_file()) {
- return;
- }
-
- load(path);
-}
-
-void CompressedTextureLayered::_validate_property(PropertyInfo &p_property) const {
-}
-
-void CompressedTextureLayered::_bind_methods() {
- ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTextureLayered::load);
- ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTextureLayered::get_load_path);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");
-}
-
-CompressedTextureLayered::CompressedTextureLayered(LayeredType p_type) {
- layered_type = p_type;
-}
-
-CompressedTextureLayered::~CompressedTextureLayered() {
- if (texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(texture);
- }
-}
-
-/////////////////////////////////////////////////
-
-Ref<Resource> ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- Ref<CompressedTextureLayered> ct;
- if (p_path.get_extension().to_lower() == "ctexarray") {
- Ref<CompressedTexture2DArray> c;
- c.instantiate();
- ct = c;
- } else if (p_path.get_extension().to_lower() == "ccube") {
- Ref<CompressedCubemap> c;
- c.instantiate();
- ct = c;
- } else if (p_path.get_extension().to_lower() == "ccubearray") {
- Ref<CompressedCubemapArray> c;
- c.instantiate();
- ct = c;
- } else {
- if (r_error) {
- *r_error = ERR_FILE_UNRECOGNIZED;
- }
- return Ref<Resource>();
- }
- Error err = ct->load(p_path);
- if (r_error) {
- *r_error = err;
- }
- if (err != OK) {
- return Ref<Resource>();
- }
-
- return ct;
-}
-
-void ResourceFormatLoaderCompressedTextureLayered::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("ctexarray");
- p_extensions->push_back("ccube");
- p_extensions->push_back("ccubearray");
-}
-
-bool ResourceFormatLoaderCompressedTextureLayered::handles_type(const String &p_type) const {
- return p_type == "CompressedTexture2DArray" || p_type == "CompressedCubemap" || p_type == "CompressedCubemapArray";
-}
-
-String ResourceFormatLoaderCompressedTextureLayered::get_resource_type(const String &p_path) const {
- if (p_path.get_extension().to_lower() == "ctexarray") {
- return "CompressedTexture2DArray";
- }
- if (p_path.get_extension().to_lower() == "ccube") {
- return "CompressedCubemap";
- }
- if (p_path.get_extension().to_lower() == "ccubearray") {
- return "CompressedCubemapArray";
- }
- return "";
-}
-
-///////////////////////////////
-
-void CameraTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_camera_feed_id", "feed_id"), &CameraTexture::set_camera_feed_id);
- ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &CameraTexture::get_camera_feed_id);
-
- ClassDB::bind_method(D_METHOD("set_which_feed", "which_feed"), &CameraTexture::set_which_feed);
- ClassDB::bind_method(D_METHOD("get_which_feed"), &CameraTexture::get_which_feed);
-
- ClassDB::bind_method(D_METHOD("set_camera_active", "active"), &CameraTexture::set_camera_active);
- ClassDB::bind_method(D_METHOD("get_camera_active"), &CameraTexture::get_camera_active);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "camera_feed_id"), "set_camera_feed_id", "get_camera_feed_id");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "which_feed"), "set_which_feed", "get_which_feed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "camera_is_active"), "set_camera_active", "get_camera_active");
-}
-
-int CameraTexture::get_width() const {
- Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
- if (feed.is_valid()) {
- return feed->get_base_width();
- } else {
- return 0;
- }
-}
-
-int CameraTexture::get_height() const {
- Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
- if (feed.is_valid()) {
- return feed->get_base_height();
- } else {
- return 0;
- }
-}
-
-bool CameraTexture::has_alpha() const {
- return false;
-}
-
-RID CameraTexture::get_rid() const {
- Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
- if (feed.is_valid()) {
- return feed->get_texture(which_feed);
- } else {
- if (_texture.is_null()) {
- _texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
- }
- return _texture;
- }
-}
-
-Ref<Image> CameraTexture::get_image() const {
- // not (yet) supported
- return Ref<Image>();
-}
-
-void CameraTexture::set_camera_feed_id(int p_new_id) {
- camera_feed_id = p_new_id;
- notify_property_list_changed();
-}
-
-int CameraTexture::get_camera_feed_id() const {
- return camera_feed_id;
-}
-
-void CameraTexture::set_which_feed(CameraServer::FeedImage p_which) {
- which_feed = p_which;
- notify_property_list_changed();
-}
-
-CameraServer::FeedImage CameraTexture::get_which_feed() const {
- return which_feed;
-}
-
-void CameraTexture::set_camera_active(bool p_active) {
- Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
- if (feed.is_valid()) {
- feed->set_active(p_active);
- notify_property_list_changed();
- }
-}
-
-bool CameraTexture::get_camera_active() const {
- Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
- if (feed.is_valid()) {
- return feed->is_active();
- } else {
- return false;
- }
-}
-
-CameraTexture::CameraTexture() {}
-
-CameraTexture::~CameraTexture() {
- if (_texture.is_valid()) {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RenderingServer::get_singleton()->free(_texture);
- }
-}
-
-///////////////////////////
-
-void PlaceholderTexture2D::set_size(Size2 p_size) {
- size = p_size;
-}
-
-int PlaceholderTexture2D::get_width() const {
- return size.width;
-}
-
-int PlaceholderTexture2D::get_height() const {
- return size.height;
-}
-
-bool PlaceholderTexture2D::has_alpha() const {
- return false;
-}
-
-Ref<Image> PlaceholderTexture2D::get_image() const {
- return Ref<Image>();
-}
-
-RID PlaceholderTexture2D::get_rid() const {
- return rid;
-}
-
-void PlaceholderTexture2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture2D::set_size);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
-}
-
-PlaceholderTexture2D::PlaceholderTexture2D() {
- rid = RS::get_singleton()->texture_2d_placeholder_create();
-}
-
-PlaceholderTexture2D::~PlaceholderTexture2D() {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(rid);
-}
-
-///////////////////////////////////////////////
-
-void PlaceholderTexture3D::set_size(const Vector3i &p_size) {
- size = p_size;
-}
-
-Vector3i PlaceholderTexture3D::get_size() const {
- return size;
-}
-
-Image::Format PlaceholderTexture3D::get_format() const {
- return Image::FORMAT_RGB8;
-}
-
-int PlaceholderTexture3D::get_width() const {
- return size.x;
-}
-
-int PlaceholderTexture3D::get_height() const {
- return size.y;
-}
-
-int PlaceholderTexture3D::get_depth() const {
- return size.z;
-}
-
-bool PlaceholderTexture3D::has_mipmaps() const {
- return false;
-}
-
-Vector<Ref<Image>> PlaceholderTexture3D::get_data() const {
- return Vector<Ref<Image>>();
-}
-
-void PlaceholderTexture3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture3D::set_size);
- ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTexture3D::get_size);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
-}
-
-PlaceholderTexture3D::PlaceholderTexture3D() {
- rid = RS::get_singleton()->texture_3d_placeholder_create();
-}
-PlaceholderTexture3D::~PlaceholderTexture3D() {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(rid);
-}
-
-/////////////////////////////////////////////////
-
-void PlaceholderTextureLayered::set_size(const Size2i &p_size) {
- size = p_size;
-}
-
-Size2i PlaceholderTextureLayered::get_size() const {
- return size;
-}
-
-void PlaceholderTextureLayered::set_layers(int p_layers) {
- layers = p_layers;
-}
-
-Image::Format PlaceholderTextureLayered::get_format() const {
- return Image::FORMAT_RGB8;
-}
-
-TextureLayered::LayeredType PlaceholderTextureLayered::get_layered_type() const {
- return layered_type;
-}
-
-int PlaceholderTextureLayered::get_width() const {
- return size.x;
-}
-
-int PlaceholderTextureLayered::get_height() const {
- return size.y;
-}
-
-int PlaceholderTextureLayered::get_layers() const {
- return layers;
-}
-
-bool PlaceholderTextureLayered::has_mipmaps() const {
- return false;
-}
-
-Ref<Image> PlaceholderTextureLayered::get_layer_data(int p_layer) const {
- return Ref<Image>();
-}
-
-void PlaceholderTextureLayered::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTextureLayered::set_size);
- ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTextureLayered::get_size);
- ClassDB::bind_method(D_METHOD("set_layers", "layers"), &PlaceholderTextureLayered::set_layers);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_RANGE, "1,4096"), "set_layers", "get_layers");
-}
-
-PlaceholderTextureLayered::PlaceholderTextureLayered(LayeredType p_type) {
- layered_type = p_type;
- rid = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));
-}
-PlaceholderTextureLayered::~PlaceholderTextureLayered() {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RS::get_singleton()->free(rid);
-}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 6b5e87ae21..e7840804bf 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -87,297 +87,6 @@ public:
Texture2D();
};
-class BitMap;
-
-class ImageTexture : public Texture2D {
- GDCLASS(ImageTexture, Texture2D);
- RES_BASE_EXTENSION("tex");
-
- mutable RID texture;
- Image::Format format = Image::FORMAT_L8;
- bool mipmaps = false;
- int w = 0;
- int h = 0;
- Size2 size_override;
- mutable Ref<BitMap> alpha_cache;
- bool image_stored = false;
-
-protected:
- virtual void reload_from_file() 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;
-
- static void _bind_methods();
-
-public:
- void set_image(const Ref<Image> &p_image);
- static Ref<ImageTexture> create_from_image(const Ref<Image> &p_image);
-
- Image::Format get_format() const;
-
- void update(const Ref<Image> &p_image);
- Ref<Image> get_image() const override;
-
- int get_width() const override;
- int get_height() const override;
-
- virtual RID get_rid() const override;
-
- bool has_alpha() const override;
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
-
- bool is_pixel_opaque(int p_x, int p_y) const override;
-
- void set_size_override(const Size2i &p_size);
-
- virtual void set_path(const String &p_path, bool p_take_over = false) override;
-
- ImageTexture();
- ~ImageTexture();
-};
-
-class PortableCompressedTexture2D : public Texture2D {
- GDCLASS(PortableCompressedTexture2D, Texture2D);
-
-public:
- enum CompressionMode {
- COMPRESSION_MODE_LOSSLESS,
- COMPRESSION_MODE_LOSSY,
- COMPRESSION_MODE_BASIS_UNIVERSAL,
- COMPRESSION_MODE_S3TC,
- COMPRESSION_MODE_ETC2,
- COMPRESSION_MODE_BPTC,
- };
-
-private:
- CompressionMode compression_mode = COMPRESSION_MODE_LOSSLESS;
- static bool keep_all_compressed_buffers;
- bool keep_compressed_buffer = false;
- Vector<uint8_t> compressed_buffer;
- Size2 size;
- Size2 size_override;
- bool mipmaps = false;
- Image::Format format = Image::FORMAT_L8;
-
- mutable RID texture;
- mutable Ref<BitMap> alpha_cache;
-
- bool image_stored = false;
-
-protected:
- Vector<uint8_t> _get_data() const;
- void _set_data(const Vector<uint8_t> &p_data);
-
- static void _bind_methods();
-
-public:
- CompressionMode get_compression_mode() const;
- void create_from_image(const Ref<Image> &p_image, CompressionMode p_compression_mode, bool p_normal_map = false, float p_lossy_quality = 0.8);
-
- Image::Format get_format() const;
-
- void update(const Ref<Image> &p_image);
- Ref<Image> get_image() const override;
-
- int get_width() const override;
- int get_height() const override;
-
- virtual RID get_rid() const override;
-
- bool has_alpha() const override;
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
-
- bool is_pixel_opaque(int p_x, int p_y) const override;
-
- virtual void set_path(const String &p_path, bool p_take_over = false) override;
-
- void set_size_override(const Size2 &p_size);
- Size2 get_size_override() const;
-
- void set_keep_compressed_buffer(bool p_keep);
- bool is_keeping_compressed_buffer() const;
-
- static void set_keep_all_compressed_buffers(bool p_keep);
- static bool is_keeping_all_compressed_buffers();
-
- PortableCompressedTexture2D();
- ~PortableCompressedTexture2D();
-};
-
-VARIANT_ENUM_CAST(PortableCompressedTexture2D::CompressionMode)
-
-class CompressedTexture2D : public Texture2D {
- GDCLASS(CompressedTexture2D, Texture2D);
-
-public:
- enum DataFormat {
- DATA_FORMAT_IMAGE,
- DATA_FORMAT_PNG,
- DATA_FORMAT_WEBP,
- DATA_FORMAT_BASIS_UNIVERSAL,
- };
-
- enum {
- FORMAT_VERSION = 1
- };
-
- enum FormatBits {
- FORMAT_BIT_STREAM = 1 << 22,
- FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
- FORMAT_BIT_DETECT_3D = 1 << 24,
- //FORMAT_BIT_DETECT_SRGB = 1 << 25,
- FORMAT_BIT_DETECT_NORMAL = 1 << 26,
- FORMAT_BIT_DETECT_ROUGNESS = 1 << 27,
- };
-
-private:
- Error _load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0);
- String path_to_file;
- mutable RID texture;
- Image::Format format = Image::FORMAT_L8;
- int w = 0;
- int h = 0;
- mutable Ref<BitMap> alpha_cache;
-
- virtual void reload_from_file() override;
-
- static void _requested_3d(void *p_ud);
- static void _requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel);
- static void _requested_normal(void *p_ud);
-
-protected:
- static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const;
-
-public:
- static Ref<Image> load_image_from_file(Ref<FileAccess> p_file, int p_size_limit);
-
- typedef void (*TextureFormatRequestCallback)(const Ref<CompressedTexture2D> &);
- typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<CompressedTexture2D> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel);
-
- static TextureFormatRequestCallback request_3d_callback;
- static TextureFormatRoughnessRequestCallback request_roughness_callback;
- static TextureFormatRequestCallback request_normal_callback;
-
- Image::Format get_format() const;
- Error load(const String &p_path);
- String get_load_path() const;
-
- int get_width() const override;
- int get_height() const override;
- virtual RID get_rid() const override;
-
- virtual void set_path(const String &p_path, bool p_take_over) override;
-
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
-
- virtual bool has_alpha() const override;
- bool is_pixel_opaque(int p_x, int p_y) const override;
-
- virtual Ref<Image> get_image() const override;
-
- CompressedTexture2D();
- ~CompressedTexture2D();
-};
-
-class ResourceFormatLoaderCompressedTexture2D : public ResourceFormatLoader {
-public:
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-};
-
-class AtlasTexture : public Texture2D {
- GDCLASS(AtlasTexture, Texture2D);
- RES_BASE_EXTENSION("atlastex");
-
-protected:
- Ref<Texture2D> atlas;
- Rect2 region;
- Rect2 margin;
- bool filter_clip = false;
-
- static void _bind_methods();
-
-public:
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual RID get_rid() const override;
-
- virtual bool has_alpha() const override;
-
- void set_atlas(const Ref<Texture2D> &p_atlas);
- Ref<Texture2D> get_atlas() const;
-
- void set_region(const Rect2 &p_region);
- Rect2 get_region() const;
-
- void set_margin(const Rect2 &p_margin);
- Rect2 get_margin() const;
-
- void set_filter_clip(const bool p_enable);
- bool has_filter_clip() const;
-
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
- virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const override;
-
- bool is_pixel_opaque(int p_x, int p_y) const override;
-
- virtual Ref<Image> get_image() const override;
-
- AtlasTexture();
-};
-
-class Mesh;
-
-class MeshTexture : public Texture2D {
- GDCLASS(MeshTexture, Texture2D);
- RES_BASE_EXTENSION("meshtex");
-
- Ref<Texture2D> base_texture;
- Ref<Mesh> mesh;
- Size2i size;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual RID get_rid() const override;
-
- virtual bool has_alpha() const override;
-
- void set_mesh(const Ref<Mesh> &p_mesh);
- Ref<Mesh> get_mesh() const;
-
- void set_image_size(const Size2 &p_size);
- Size2 get_image_size() const;
-
- void set_base_texture(const Ref<Texture2D> &p_texture);
- Ref<Texture2D> get_base_texture() const;
-
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
- virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const override;
-
- bool is_pixel_opaque(int p_x, int p_y) const override;
-
- MeshTexture();
-};
-
class TextureLayered : public Texture {
GDCLASS(TextureLayered, Texture);
@@ -411,173 +120,6 @@ public:
VARIANT_ENUM_CAST(TextureLayered::LayeredType)
-class ImageTextureLayered : public TextureLayered {
- GDCLASS(ImageTextureLayered, TextureLayered);
-
- LayeredType layered_type;
-
- mutable RID texture;
- Image::Format format = Image::FORMAT_L8;
-
- int width = 0;
- int height = 0;
- int layers = 0;
- bool mipmaps = false;
-
- Error _create_from_images(const TypedArray<Image> &p_images);
-
- TypedArray<Image> _get_images() const;
- void _set_images(const TypedArray<Image> &p_images);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual Image::Format get_format() const override;
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual int get_layers() const override;
- virtual bool has_mipmaps() const override;
- virtual LayeredType get_layered_type() const override;
-
- Error create_from_images(Vector<Ref<Image>> p_images);
- void update_layer(const Ref<Image> &p_image, int p_layer);
- virtual Ref<Image> get_layer_data(int p_layer) const override;
-
- virtual RID get_rid() const override;
- virtual void set_path(const String &p_path, bool p_take_over = false) override;
-
- ImageTextureLayered(LayeredType p_layered_type);
- ~ImageTextureLayered();
-};
-
-class Texture2DArray : public ImageTextureLayered {
- GDCLASS(Texture2DArray, ImageTextureLayered)
-
-protected:
- static void _bind_methods();
-
-public:
- Texture2DArray() :
- ImageTextureLayered(LAYERED_TYPE_2D_ARRAY) {}
-
- virtual Ref<Resource> create_placeholder() const;
-};
-
-class Cubemap : public ImageTextureLayered {
- GDCLASS(Cubemap, ImageTextureLayered);
-
-protected:
- static void _bind_methods();
-
-public:
- Cubemap() :
- ImageTextureLayered(LAYERED_TYPE_CUBEMAP) {}
-
- virtual Ref<Resource> create_placeholder() const;
-};
-
-class CubemapArray : public ImageTextureLayered {
- GDCLASS(CubemapArray, ImageTextureLayered);
-
-protected:
- static void _bind_methods();
-
-public:
- CubemapArray() :
- ImageTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
-
- virtual Ref<Resource> create_placeholder() const;
-};
-
-class CompressedTextureLayered : public TextureLayered {
- GDCLASS(CompressedTextureLayered, TextureLayered);
-
-public:
- enum DataFormat {
- DATA_FORMAT_IMAGE,
- DATA_FORMAT_PNG,
- DATA_FORMAT_WEBP,
- DATA_FORMAT_BASIS_UNIVERSAL,
- };
-
- enum {
- FORMAT_VERSION = 1
- };
-
- enum FormatBits {
- FORMAT_BIT_STREAM = 1 << 22,
- FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
- };
-
-private:
- Error _load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit = 0);
- String path_to_file;
- mutable RID texture;
- Image::Format format = Image::FORMAT_L8;
- int w = 0;
- int h = 0;
- int layers = 0;
- bool mipmaps = false;
- LayeredType layered_type = LayeredType::LAYERED_TYPE_2D_ARRAY;
-
- virtual void reload_from_file() override;
-
-protected:
- static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const;
-
-public:
- Image::Format get_format() const override;
- Error load(const String &p_path);
- String get_load_path() const;
- virtual LayeredType get_layered_type() const override;
-
- int get_width() const override;
- int get_height() const override;
- int get_layers() const override;
- virtual bool has_mipmaps() const override;
- virtual RID get_rid() const override;
-
- virtual void set_path(const String &p_path, bool p_take_over) override;
-
- virtual Ref<Image> get_layer_data(int p_layer) const override;
-
- CompressedTextureLayered(LayeredType p_layered_type);
- ~CompressedTextureLayered();
-};
-
-class CompressedTexture2DArray : public CompressedTextureLayered {
- GDCLASS(CompressedTexture2DArray, CompressedTextureLayered)
-public:
- CompressedTexture2DArray() :
- CompressedTextureLayered(LAYERED_TYPE_2D_ARRAY) {}
-};
-
-class CompressedCubemap : public CompressedTextureLayered {
- GDCLASS(CompressedCubemap, CompressedTextureLayered);
-
-public:
- CompressedCubemap() :
- CompressedTextureLayered(LAYERED_TYPE_CUBEMAP) {}
-};
-
-class CompressedCubemapArray : public CompressedTextureLayered {
- GDCLASS(CompressedCubemapArray, CompressedTextureLayered);
-
-public:
- CompressedCubemapArray() :
- CompressedTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
-};
-
-class ResourceFormatLoaderCompressedTextureLayered : public ResourceFormatLoader {
-public:
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-};
-
class Texture3D : public Texture {
GDCLASS(Texture3D, Texture);
@@ -602,495 +144,4 @@ public:
virtual Ref<Resource> create_placeholder() const;
};
-class ImageTexture3D : public Texture3D {
- GDCLASS(ImageTexture3D, Texture3D);
-
- mutable RID texture;
-
- Image::Format format = Image::FORMAT_L8;
- int width = 1;
- int height = 1;
- int depth = 1;
- bool mipmaps = false;
-
-protected:
- static void _bind_methods();
-
- Error _create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data);
- void _update(const TypedArray<Image> &p_data);
-
-public:
- virtual Image::Format get_format() const override;
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual int get_depth() const override;
- virtual bool has_mipmaps() const override;
-
- Error create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data);
- void update(const Vector<Ref<Image>> &p_data);
- virtual Vector<Ref<Image>> get_data() const override;
-
- virtual RID get_rid() const override;
- virtual void set_path(const String &p_path, bool p_take_over = false) override;
-
- ImageTexture3D();
- ~ImageTexture3D();
-};
-
-class CompressedTexture3D : public Texture3D {
- GDCLASS(CompressedTexture3D, Texture3D);
-
-public:
- enum DataFormat {
- DATA_FORMAT_IMAGE,
- DATA_FORMAT_PNG,
- DATA_FORMAT_WEBP,
- DATA_FORMAT_BASIS_UNIVERSAL,
- };
-
- enum {
- FORMAT_VERSION = 1
- };
-
- enum FormatBits {
- FORMAT_BIT_STREAM = 1 << 22,
- FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
- };
-
-private:
- Error _load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps);
- String path_to_file;
- mutable RID texture;
- Image::Format format = Image::FORMAT_L8;
- int w = 0;
- int h = 0;
- int d = 0;
- bool mipmaps = false;
-
- virtual void reload_from_file() override;
-
-protected:
- static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const;
-
-public:
- Image::Format get_format() const override;
- Error load(const String &p_path);
- String get_load_path() const;
-
- int get_width() const override;
- int get_height() const override;
- int get_depth() const override;
- virtual bool has_mipmaps() const override;
- virtual RID get_rid() const override;
-
- virtual void set_path(const String &p_path, bool p_take_over) override;
-
- virtual Vector<Ref<Image>> get_data() const override;
-
- CompressedTexture3D();
- ~CompressedTexture3D();
-};
-
-class ResourceFormatLoaderCompressedTexture3D : public ResourceFormatLoader {
-public:
- virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-};
-
-class CurveTexture : public Texture2D {
- GDCLASS(CurveTexture, Texture2D);
- RES_BASE_EXTENSION("curvetex")
-public:
- enum TextureMode {
- TEXTURE_MODE_RGB,
- TEXTURE_MODE_RED,
- };
-
-private:
- mutable RID _texture;
- Ref<Curve> _curve;
- int _width = 256;
- int _current_width = 0;
- TextureMode texture_mode = TEXTURE_MODE_RGB;
- TextureMode _current_texture_mode = TEXTURE_MODE_RGB;
-
- void _update();
-
-protected:
- static void _bind_methods();
-
-public:
- void set_width(int p_width);
- int get_width() const override;
-
- void set_texture_mode(TextureMode p_mode);
- TextureMode get_texture_mode() const;
-
- void ensure_default_setup(float p_min = 0, float p_max = 1);
-
- void set_curve(Ref<Curve> p_curve);
- Ref<Curve> get_curve() const;
-
- virtual RID get_rid() const override;
-
- virtual int get_height() const override { return 1; }
- virtual bool has_alpha() const override { return false; }
-
- CurveTexture();
- ~CurveTexture();
-};
-
-VARIANT_ENUM_CAST(CurveTexture::TextureMode)
-
-class CurveXYZTexture : public Texture2D {
- GDCLASS(CurveXYZTexture, Texture2D);
- RES_BASE_EXTENSION("curvetex")
-
-private:
- mutable RID _texture;
- Ref<Curve> _curve_x;
- Ref<Curve> _curve_y;
- Ref<Curve> _curve_z;
- int _width = 256;
- int _current_width = 0;
-
- void _update();
-
-protected:
- static void _bind_methods();
-
-public:
- void set_width(int p_width);
- int get_width() const override;
-
- void ensure_default_setup(float p_min = 0, float p_max = 1);
-
- void set_curve_x(Ref<Curve> p_curve);
- Ref<Curve> get_curve_x() const;
-
- void set_curve_y(Ref<Curve> p_curve);
- Ref<Curve> get_curve_y() const;
-
- void set_curve_z(Ref<Curve> p_curve);
- Ref<Curve> get_curve_z() const;
-
- virtual RID get_rid() const override;
-
- virtual int get_height() const override { return 1; }
- virtual bool has_alpha() const override { return false; }
-
- CurveXYZTexture();
- ~CurveXYZTexture();
-};
-
-class GradientTexture1D : public Texture2D {
- GDCLASS(GradientTexture1D, Texture2D);
-
-private:
- Ref<Gradient> gradient;
- bool update_pending = false;
- RID texture;
- int width = 256;
- bool use_hdr = false;
-
- void _queue_update();
- void _update();
-
-protected:
- static void _bind_methods();
-
-public:
- void set_gradient(Ref<Gradient> p_gradient);
- Ref<Gradient> get_gradient() const;
-
- void set_width(int p_width);
- int get_width() const override;
-
- void set_use_hdr(bool p_enabled);
- bool is_using_hdr() const;
-
- virtual RID get_rid() const override { return texture; }
- virtual int get_height() const override { return 1; }
- virtual bool has_alpha() const override { return true; }
-
- virtual Ref<Image> get_image() const override;
-
- GradientTexture1D();
- virtual ~GradientTexture1D();
-};
-
-class GradientTexture2D : public Texture2D {
- GDCLASS(GradientTexture2D, Texture2D);
-
-public:
- enum Fill {
- FILL_LINEAR,
- FILL_RADIAL,
- FILL_SQUARE,
- };
- enum Repeat {
- REPEAT_NONE,
- REPEAT,
- REPEAT_MIRROR,
- };
-
-private:
- Ref<Gradient> gradient;
- mutable RID texture;
-
- int width = 64;
- int height = 64;
-
- bool use_hdr = false;
-
- Vector2 fill_from;
- Vector2 fill_to = Vector2(1, 0);
-
- Fill fill = FILL_LINEAR;
- Repeat repeat = REPEAT_NONE;
-
- float _get_gradient_offset_at(int x, int y) const;
-
- bool update_pending = false;
- void _queue_update();
- void _update();
-
-protected:
- static void _bind_methods();
-
-public:
- void set_gradient(Ref<Gradient> p_gradient);
- Ref<Gradient> get_gradient() const;
-
- void set_width(int p_width);
- virtual int get_width() const override;
- void set_height(int p_height);
- virtual int get_height() const override;
-
- void set_use_hdr(bool p_enabled);
- bool is_using_hdr() const;
-
- void set_fill(Fill p_fill);
- Fill get_fill() const;
- void set_fill_from(Vector2 p_fill_from);
- Vector2 get_fill_from() const;
- void set_fill_to(Vector2 p_fill_to);
- Vector2 get_fill_to() const;
-
- void set_repeat(Repeat p_repeat);
- Repeat get_repeat() const;
-
- virtual RID get_rid() const override;
- virtual bool has_alpha() const override { return true; }
- virtual Ref<Image> get_image() const override;
-
- GradientTexture2D();
- virtual ~GradientTexture2D();
-};
-
-VARIANT_ENUM_CAST(GradientTexture2D::Fill);
-VARIANT_ENUM_CAST(GradientTexture2D::Repeat);
-
-class AnimatedTexture : public Texture2D {
- GDCLASS(AnimatedTexture, Texture2D);
-
- //use readers writers lock for this, since its far more times read than written to
- RWLock rw_lock;
-
-public:
- enum {
- MAX_FRAMES = 256
- };
-
-private:
- RID proxy_ph;
- RID proxy;
-
- struct Frame {
- Ref<Texture2D> texture;
- float duration = 1.0;
- };
-
- Frame frames[MAX_FRAMES];
- int frame_count = 1.0;
- int current_frame = 0;
- bool pause = false;
- bool one_shot = false;
- float speed_scale = 1.0;
-
- float time = 0.0;
-
- uint64_t prev_ticks = 0;
-
- void _update_proxy();
-
-protected:
- static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const;
-
-public:
- void set_frames(int p_frames);
- int get_frames() const;
-
- void set_current_frame(int p_frame);
- int get_current_frame() const;
-
- void set_pause(bool p_pause);
- bool get_pause() const;
-
- void set_one_shot(bool p_one_shot);
- bool get_one_shot() const;
-
- void set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture);
- Ref<Texture2D> get_frame_texture(int p_frame) const;
-
- void set_frame_duration(int p_frame, float p_duration);
- float get_frame_duration(int p_frame) const;
-
- void set_speed_scale(float p_scale);
- float get_speed_scale() const;
-
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual RID get_rid() const override;
-
- virtual bool has_alpha() const override;
-
- virtual Ref<Image> get_image() const override;
-
- bool is_pixel_opaque(int p_x, int p_y) const override;
-
- AnimatedTexture();
- ~AnimatedTexture();
-};
-
-class CameraTexture : public Texture2D {
- GDCLASS(CameraTexture, Texture2D);
-
-private:
- mutable RID _texture;
- int camera_feed_id = 0;
- CameraServer::FeedImage which_feed = CameraServer::FEED_RGBA_IMAGE;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual RID get_rid() const override;
- virtual bool has_alpha() const override;
-
- virtual Ref<Image> get_image() const override;
-
- void set_camera_feed_id(int p_new_id);
- int get_camera_feed_id() const;
-
- void set_which_feed(CameraServer::FeedImage p_which);
- CameraServer::FeedImage get_which_feed() const;
-
- void set_camera_active(bool p_active);
- bool get_camera_active() const;
-
- CameraTexture();
- ~CameraTexture();
-};
-
-class PlaceholderTexture2D : public Texture2D {
- GDCLASS(PlaceholderTexture2D, Texture2D)
-
- RID rid;
- Size2 size = Size2(1, 1);
-
-protected:
- static void _bind_methods();
-
-public:
- void set_size(Size2 p_size);
-
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual RID get_rid() const override;
- virtual bool has_alpha() const override;
-
- virtual Ref<Image> get_image() const override;
-
- PlaceholderTexture2D();
- ~PlaceholderTexture2D();
-};
-
-class PlaceholderTexture3D : public Texture3D {
- GDCLASS(PlaceholderTexture3D, Texture3D)
-
- RID rid;
- Vector3i size = Vector3i(1, 1, 1);
-
-protected:
- static void _bind_methods();
-
-public:
- void set_size(const Vector3i &p_size);
- Vector3i get_size() const;
- virtual Image::Format get_format() const override;
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual int get_depth() const override;
- virtual bool has_mipmaps() const override;
- virtual Vector<Ref<Image>> get_data() const override;
-
- PlaceholderTexture3D();
- ~PlaceholderTexture3D();
-};
-
-class PlaceholderTextureLayered : public TextureLayered {
- GDCLASS(PlaceholderTextureLayered, TextureLayered)
-
- RID rid;
- Size2i size = Size2i(1, 1);
- int layers = 1;
- LayeredType layered_type = LAYERED_TYPE_2D_ARRAY;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_size(const Size2i &p_size);
- Size2i get_size() const;
- void set_layers(int p_layers);
- virtual Image::Format get_format() const override;
- virtual LayeredType get_layered_type() const override;
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual int get_layers() const override;
- virtual bool has_mipmaps() const override;
- virtual Ref<Image> get_layer_data(int p_layer) const override;
-
- PlaceholderTextureLayered(LayeredType p_type);
- ~PlaceholderTextureLayered();
-};
-
-class PlaceholderTexture2DArray : public PlaceholderTextureLayered {
- GDCLASS(PlaceholderTexture2DArray, PlaceholderTextureLayered)
-public:
- PlaceholderTexture2DArray() :
- PlaceholderTextureLayered(LAYERED_TYPE_2D_ARRAY) {}
-};
-
-class PlaceholderCubemap : public PlaceholderTextureLayered {
- GDCLASS(PlaceholderCubemap, PlaceholderTextureLayered)
-public:
- PlaceholderCubemap() :
- PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP) {}
-};
-
-class PlaceholderCubemapArray : public PlaceholderTextureLayered {
- GDCLASS(PlaceholderCubemapArray, PlaceholderTextureLayered)
-public:
- PlaceholderCubemapArray() :
- PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
-};
-
#endif // TEXTURE_H
diff --git a/scene/resources/texture_rd.cpp b/scene/resources/texture_rd.cpp
new file mode 100644
index 0000000000..6f25af6863
--- /dev/null
+++ b/scene/resources/texture_rd.cpp
@@ -0,0 +1,346 @@
+/**************************************************************************/
+/* texture_rd.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 "texture_rd.h"
+
+////////////////////////////////////////////////////////////////////////////
+// Texture2DRD
+
+void Texture2DRD::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_texture_rd_rid", "texture_rd_rid"), &Texture2DRD::set_texture_rd_rid);
+ ClassDB::bind_method(D_METHOD("get_texture_rd_rid"), &Texture2DRD::get_texture_rd_rid);
+
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid"), "set_texture_rd_rid", "get_texture_rd_rid");
+}
+
+int Texture2DRD::get_width() const {
+ return size.width;
+}
+
+int Texture2DRD::get_height() const {
+ return size.height;
+}
+
+RID Texture2DRD::get_rid() const {
+ if (texture_rid.is_null()) {
+ // We are in trouble, create something temporary.
+ texture_rid = RenderingServer::get_singleton()->texture_2d_placeholder_create();
+ }
+
+ return texture_rid;
+}
+
+bool Texture2DRD::has_alpha() const {
+ return false;
+}
+
+Ref<Image> Texture2DRD::get_image() const {
+ ERR_FAIL_NULL_V(RS::get_singleton(), Ref<Image>());
+ if (texture_rid.is_valid()) {
+ return RS::get_singleton()->texture_2d_get(texture_rid);
+ } else {
+ return Ref<Image>();
+ }
+}
+
+void Texture2DRD::set_texture_rd_rid(RID p_texture_rd_rid) {
+ ERR_FAIL_NULL(RS::get_singleton());
+
+ if (p_texture_rd_rid.is_valid()) {
+ ERR_FAIL_NULL(RD::get_singleton());
+ ERR_FAIL_COND(!RD::get_singleton()->texture_is_valid(p_texture_rd_rid));
+
+ RD::TextureFormat tf = RD::get_singleton()->texture_get_format(p_texture_rd_rid);
+ ERR_FAIL_COND(tf.texture_type != RD::TEXTURE_TYPE_2D);
+ ERR_FAIL_COND(tf.depth > 1);
+ ERR_FAIL_COND(tf.array_layers > 1);
+
+ size.width = tf.width;
+ size.height = tf.height;
+
+ texture_rd_rid = p_texture_rd_rid;
+
+ if (texture_rid.is_valid()) {
+ RS::get_singleton()->texture_replace(texture_rid, RS::get_singleton()->texture_rd_create(p_texture_rd_rid));
+ } else {
+ texture_rid = RS::get_singleton()->texture_rd_create(p_texture_rd_rid);
+ }
+
+ notify_property_list_changed();
+ emit_changed();
+ } else if (texture_rid.is_valid()) {
+ RS::get_singleton()->free(texture_rid);
+ texture_rid = RID();
+ size = Size2i();
+
+ notify_property_list_changed();
+ emit_changed();
+ }
+}
+
+RID Texture2DRD::get_texture_rd_rid() const {
+ return texture_rd_rid;
+}
+
+Texture2DRD::Texture2DRD() {
+ size = Size2i();
+}
+
+Texture2DRD::~Texture2DRD() {
+ if (texture_rid.is_valid()) {
+ ERR_FAIL_NULL(RS::get_singleton());
+ RS::get_singleton()->free(texture_rid);
+ texture_rid = RID();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+// TextureLayeredRD
+
+void TextureLayeredRD::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_texture_rd_rid", "texture_rd_rid"), &TextureLayeredRD::set_texture_rd_rid);
+ ClassDB::bind_method(D_METHOD("get_texture_rd_rid"), &TextureLayeredRD::get_texture_rd_rid);
+
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid"), "set_texture_rd_rid", "get_texture_rd_rid");
+}
+
+TextureLayered::LayeredType TextureLayeredRD::get_layered_type() const {
+ return layer_type;
+}
+
+Image::Format TextureLayeredRD::get_format() const {
+ return image_format;
+}
+
+int TextureLayeredRD::get_width() const {
+ return size.width;
+}
+
+int TextureLayeredRD::get_height() const {
+ return size.height;
+}
+
+int TextureLayeredRD::get_layers() const {
+ return (int)layers;
+}
+
+bool TextureLayeredRD::has_mipmaps() const {
+ return mipmaps > 1;
+}
+
+RID TextureLayeredRD::get_rid() const {
+ if (texture_rid.is_null()) {
+ // We are in trouble, create something temporary.
+ texture_rid = RenderingServer::get_singleton()->texture_2d_placeholder_create();
+ }
+
+ return texture_rid;
+}
+
+Ref<Image> TextureLayeredRD::get_layer_data(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, (int)layers, Ref<Image>());
+ return RS::get_singleton()->texture_2d_layer_get(texture_rid, p_layer);
+}
+
+void TextureLayeredRD::set_texture_rd_rid(RID p_texture_rd_rid) {
+ ERR_FAIL_NULL(RS::get_singleton());
+
+ if (p_texture_rd_rid.is_valid()) {
+ ERR_FAIL_NULL(RD::get_singleton());
+ ERR_FAIL_COND(!RD::get_singleton()->texture_is_valid(p_texture_rd_rid));
+
+ RS::TextureLayeredType rs_layer_type;
+ RD::TextureFormat tf = RD::get_singleton()->texture_get_format(p_texture_rd_rid);
+ ERR_FAIL_COND(tf.texture_type != RD::TEXTURE_TYPE_2D_ARRAY);
+ ERR_FAIL_COND(tf.depth > 1);
+ switch (layer_type) {
+ case LAYERED_TYPE_2D_ARRAY: {
+ ERR_FAIL_COND(tf.array_layers <= 1);
+ rs_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY;
+ } break;
+ case LAYERED_TYPE_CUBEMAP: {
+ ERR_FAIL_COND(tf.array_layers != 6);
+ rs_layer_type = RS::TEXTURE_LAYERED_CUBEMAP;
+ } break;
+ case LAYERED_TYPE_CUBEMAP_ARRAY: {
+ ERR_FAIL_COND((tf.array_layers == 0) || ((tf.array_layers % 6) != 0));
+ rs_layer_type = RS::TEXTURE_LAYERED_CUBEMAP_ARRAY;
+ } break;
+ default: {
+ ERR_FAIL_MSG("Unknown layer type selected");
+ } break;
+ }
+
+ size.width = tf.width;
+ size.height = tf.height;
+ layers = tf.array_layers;
+ mipmaps = tf.mipmaps;
+
+ texture_rd_rid = p_texture_rd_rid;
+
+ if (texture_rid.is_valid()) {
+ RS::get_singleton()->texture_replace(texture_rid, RS::get_singleton()->texture_rd_create(p_texture_rd_rid, rs_layer_type));
+ } else {
+ texture_rid = RS::get_singleton()->texture_rd_create(p_texture_rd_rid, rs_layer_type);
+ }
+
+ image_format = RS::get_singleton()->texture_get_format(texture_rid);
+
+ notify_property_list_changed();
+ emit_changed();
+ } else if (texture_rid.is_valid()) {
+ RS::get_singleton()->free(texture_rid);
+ texture_rid = RID();
+ image_format = Image::FORMAT_MAX;
+ size = Size2i();
+ layers = 0;
+ mipmaps = 0;
+
+ notify_property_list_changed();
+ emit_changed();
+ }
+}
+
+RID TextureLayeredRD::get_texture_rd_rid() const {
+ return texture_rd_rid;
+}
+
+TextureLayeredRD::TextureLayeredRD(LayeredType p_layer_type) {
+ layer_type = p_layer_type;
+ size = Size2i();
+ image_format = Image::FORMAT_MAX;
+ layers = 0;
+ mipmaps = 0;
+}
+
+TextureLayeredRD::~TextureLayeredRD() {
+ if (texture_rid.is_valid()) {
+ ERR_FAIL_NULL(RS::get_singleton());
+ RS::get_singleton()->free(texture_rid);
+ texture_rid = RID();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Texture3DRD
+
+void Texture3DRD::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_texture_rd_rid", "texture_rd_rid"), &Texture3DRD::set_texture_rd_rid);
+ ClassDB::bind_method(D_METHOD("get_texture_rd_rid"), &Texture3DRD::get_texture_rd_rid);
+
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid"), "set_texture_rd_rid", "get_texture_rd_rid");
+}
+
+Image::Format Texture3DRD::get_format() const {
+ return image_format;
+}
+
+int Texture3DRD::get_width() const {
+ return size.x;
+}
+
+int Texture3DRD::get_height() const {
+ return size.y;
+}
+
+int Texture3DRD::get_depth() const {
+ return size.z;
+}
+
+bool Texture3DRD::has_mipmaps() const {
+ return mipmaps > 1;
+}
+
+RID Texture3DRD::get_rid() const {
+ if (texture_rid.is_null()) {
+ // We are in trouble, create something temporary.
+ texture_rid = RenderingServer::get_singleton()->texture_2d_placeholder_create();
+ }
+
+ return texture_rid;
+}
+
+void Texture3DRD::set_texture_rd_rid(RID p_texture_rd_rid) {
+ ERR_FAIL_NULL(RS::get_singleton());
+
+ if (p_texture_rd_rid.is_valid()) {
+ ERR_FAIL_NULL(RD::get_singleton());
+ ERR_FAIL_COND(!RD::get_singleton()->texture_is_valid(p_texture_rd_rid));
+
+ RD::TextureFormat tf = RD::get_singleton()->texture_get_format(p_texture_rd_rid);
+ ERR_FAIL_COND(tf.texture_type != RD::TEXTURE_TYPE_3D);
+ ERR_FAIL_COND(tf.array_layers > 1);
+
+ size.x = tf.width;
+ size.y = tf.height;
+ size.z = tf.depth;
+ mipmaps = tf.mipmaps;
+
+ texture_rd_rid = p_texture_rd_rid;
+
+ if (texture_rid.is_valid()) {
+ RS::get_singleton()->texture_replace(texture_rid, RS::get_singleton()->texture_rd_create(p_texture_rd_rid));
+ } else {
+ texture_rid = RS::get_singleton()->texture_rd_create(p_texture_rd_rid);
+ }
+
+ image_format = RS::get_singleton()->texture_get_format(texture_rid);
+
+ notify_property_list_changed();
+ emit_changed();
+ } else if (texture_rid.is_valid()) {
+ RS::get_singleton()->free(texture_rid);
+ texture_rid = RID();
+ image_format = Image::FORMAT_MAX;
+ size = Vector3i();
+ mipmaps = 0;
+
+ notify_property_list_changed();
+ emit_changed();
+ }
+}
+
+RID Texture3DRD::get_texture_rd_rid() const {
+ return texture_rd_rid;
+}
+
+Texture3DRD::Texture3DRD() {
+ image_format = Image::FORMAT_MAX;
+ size = Vector3i();
+ mipmaps = 0;
+}
+
+Texture3DRD::~Texture3DRD() {
+ if (texture_rid.is_valid()) {
+ ERR_FAIL_NULL(RS::get_singleton());
+ RS::get_singleton()->free(texture_rid);
+ texture_rid = RID();
+ }
+}
diff --git a/scene/resources/texture_rd.h b/scene/resources/texture_rd.h
new file mode 100644
index 0000000000..f88d6c5155
--- /dev/null
+++ b/scene/resources/texture_rd.h
@@ -0,0 +1,153 @@
+/**************************************************************************/
+/* texture_rd.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 TEXTURE_RD_H
+#define TEXTURE_RD_H
+
+// Note, these classes are part of the Rendering Device based renderer.
+// They are included here to ensure the correct order of registration
+// is performed.
+// Once the renderer has been moved into a module, these classes should
+// be moved as well.
+
+#include "scene/resources/texture.h"
+
+class Texture2DRD : public Texture2D {
+ GDCLASS(Texture2DRD, Texture2D)
+
+ mutable RID texture_rid;
+ RID texture_rd_rid;
+ Size2i size;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual RID get_rid() const override;
+ virtual bool has_alpha() const override;
+
+ virtual Ref<Image> get_image() const override;
+
+ void set_texture_rd_rid(RID p_texture_rd_rid);
+ RID get_texture_rd_rid() const;
+
+ Texture2DRD();
+ ~Texture2DRD();
+};
+
+class TextureLayeredRD : public TextureLayered {
+ GDCLASS(TextureLayeredRD, TextureLayered)
+
+ LayeredType layer_type;
+
+ mutable RID texture_rid;
+ RID texture_rd_rid;
+
+ Image::Format image_format;
+ Size2i size;
+ uint32_t layers = 0;
+ uint32_t mipmaps = 0;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Image::Format get_format() const override;
+ virtual LayeredType get_layered_type() const override;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual int get_layers() const override;
+ virtual bool has_mipmaps() const override;
+ virtual RID get_rid() const override;
+
+ virtual Ref<Image> get_layer_data(int p_layer) const override;
+
+ void set_texture_rd_rid(RID p_texture_rd_rid);
+ RID get_texture_rd_rid() const;
+
+ TextureLayeredRD(LayeredType p_layer_type);
+ ~TextureLayeredRD();
+};
+
+class Texture2DArrayRD : public TextureLayeredRD {
+ GDCLASS(Texture2DArrayRD, TextureLayeredRD)
+
+public:
+ Texture2DArrayRD() :
+ TextureLayeredRD(LAYERED_TYPE_2D_ARRAY) {}
+};
+
+class TextureCubemapRD : public TextureLayeredRD {
+ GDCLASS(TextureCubemapRD, TextureLayeredRD)
+
+public:
+ TextureCubemapRD() :
+ TextureLayeredRD(LAYERED_TYPE_CUBEMAP) {}
+};
+
+class TextureCubemapArrayRD : public TextureLayeredRD {
+ GDCLASS(TextureCubemapArrayRD, TextureLayeredRD)
+
+public:
+ TextureCubemapArrayRD() :
+ TextureLayeredRD(LAYERED_TYPE_CUBEMAP_ARRAY) {}
+};
+
+class Texture3DRD : public Texture3D {
+ GDCLASS(Texture3DRD, Texture3D)
+
+ mutable RID texture_rid;
+ RID texture_rd_rid;
+
+ Image::Format image_format;
+ Vector3i size;
+ uint32_t mipmaps = 0;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Image::Format get_format() const override;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual int get_depth() const override;
+ virtual bool has_mipmaps() const override;
+ virtual RID get_rid() const override;
+
+ void set_texture_rd_rid(RID p_texture_rd_rid);
+ RID get_texture_rd_rid() const;
+
+ Texture3DRD();
+ ~Texture3DRD();
+};
+
+#endif // TEXTURE_RD_H
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index bcbc8b94e7..799a8471b9 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -222,13 +222,13 @@ void Theme::set_default_font(const Ref<Font> &p_default_font) {
}
if (default_font.is_valid()) {
- default_font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ default_font->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
default_font = p_default_font;
if (default_font.is_valid()) {
- default_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
+ default_font->connect_changed(callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
}
_emit_theme_changed();
@@ -268,13 +268,13 @@ void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, c
bool existing = false;
if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) {
existing = true;
- icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ icon_map[p_theme_type][p_name]->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
icon_map[p_theme_type][p_name] = p_icon;
if (p_icon.is_valid()) {
- icon_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
+ icon_map[p_theme_type][p_name]->connect_changed(callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
}
_emit_theme_changed(!existing);
@@ -314,7 +314,7 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type)
ERR_FAIL_COND_MSG(!icon_map[p_theme_type].has(p_name), "Cannot clear the icon '" + String(p_name) + "' because it does not exist.");
if (icon_map[p_theme_type][p_name].is_valid()) {
- icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ icon_map[p_theme_type][p_name]->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
icon_map[p_theme_type].erase(p_name);
@@ -353,7 +353,7 @@ void Theme::remove_icon_type(const StringName &p_theme_type) {
for (const KeyValue<StringName, Ref<Texture2D>> &E : icon_map[p_theme_type]) {
Ref<Texture2D> icon = E.value;
if (icon.is_valid()) {
- icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ icon->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
}
@@ -378,13 +378,13 @@ void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_typ
bool existing = false;
if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) {
existing = true;
- style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ style_map[p_theme_type][p_name]->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
style_map[p_theme_type][p_name] = p_style;
if (p_style.is_valid()) {
- style_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
+ style_map[p_theme_type][p_name]->connect_changed(callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
}
_emit_theme_changed(!existing);
@@ -424,7 +424,7 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_t
ERR_FAIL_COND_MSG(!style_map[p_theme_type].has(p_name), "Cannot clear the stylebox '" + String(p_name) + "' because it does not exist.");
if (style_map[p_theme_type][p_name].is_valid()) {
- style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ style_map[p_theme_type][p_name]->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
style_map[p_theme_type].erase(p_name);
@@ -463,7 +463,7 @@ void Theme::remove_stylebox_type(const StringName &p_theme_type) {
for (const KeyValue<StringName, Ref<StyleBox>> &E : style_map[p_theme_type]) {
Ref<StyleBox> style = E.value;
if (style.is_valid()) {
- style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ style->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
}
@@ -488,13 +488,13 @@ void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, c
bool existing = false;
if (font_map[p_theme_type][p_name].is_valid()) {
existing = true;
- font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ font_map[p_theme_type][p_name]->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
font_map[p_theme_type][p_name] = p_font;
if (p_font.is_valid()) {
- font_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
+ font_map[p_theme_type][p_name]->connect_changed(callable_mp(this, &Theme::_emit_theme_changed).bind(false), CONNECT_REFERENCE_COUNTED);
}
_emit_theme_changed(!existing);
@@ -536,7 +536,7 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type)
ERR_FAIL_COND_MSG(!font_map[p_theme_type].has(p_name), "Cannot clear the font '" + String(p_name) + "' because it does not exist.");
if (font_map[p_theme_type][p_name].is_valid()) {
- font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ font_map[p_theme_type][p_name]->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
font_map[p_theme_type].erase(p_name);
@@ -575,7 +575,7 @@ void Theme::remove_font_type(const StringName &p_theme_type) {
for (const KeyValue<StringName, Ref<Font>> &E : font_map[p_theme_type]) {
Ref<Font> font = E.value;
if (font.is_valid()) {
- font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ font->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
}
@@ -1622,7 +1622,7 @@ void Theme::clear() {
for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
if (F.value.is_valid()) {
Ref<Texture2D> icon = F.value;
- icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ icon->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
}
}
@@ -1633,7 +1633,7 @@ void Theme::clear() {
for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
if (F.value.is_valid()) {
Ref<StyleBox> style = F.value;
- style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ style->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
}
}
@@ -1644,7 +1644,7 @@ void Theme::clear() {
for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
if (F.value.is_valid()) {
Ref<Font> font = F.value;
- font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ font->disconnect_changed(callable_mp(this, &Theme::_emit_theme_changed));
}
}
}
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index d74809a512..f340573c6a 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -30,13 +30,13 @@
#include "tile_set.h"
-#include "core/core_string_names.h"
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/templates/local_vector.h"
#include "core/templates/rb_set.h"
#include "scene/gui/control.h"
#include "scene/resources/convex_polygon_shape_2d.h"
+#include "scene/resources/image_texture.h"
#include "servers/navigation_server_2d.h"
/////////////////////////////// TileMapPattern //////////////////////////////////////
@@ -487,7 +487,7 @@ int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source
p_tile_set_source->set_tile_set(this);
_compute_next_source_id();
- sources[new_source_id]->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileSet::_source_changed));
+ sources[new_source_id]->connect_changed(callable_mp(this, &TileSet::_source_changed));
terrains_cache_dirty = true;
emit_changed();
@@ -498,7 +498,7 @@ int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source
void TileSet::remove_source(int p_source_id) {
ERR_FAIL_COND_MSG(!sources.has(p_source_id), vformat("Cannot remove TileSet atlas source. No tileset atlas source with id %d.", p_source_id));
- sources[p_source_id]->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileSet::_source_changed));
+ sources[p_source_id]->disconnect_changed(callable_mp(this, &TileSet::_source_changed));
sources[p_source_id]->set_tile_set(nullptr);
sources.erase(p_source_id);
@@ -3814,13 +3814,13 @@ void TileSetAtlasSource::reset_state() {
void TileSetAtlasSource::set_texture(Ref<Texture2D> p_texture) {
if (texture.is_valid()) {
- texture->disconnect(SNAME("changed"), callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
+ texture->disconnect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
}
texture = p_texture;
if (texture.is_valid()) {
- texture->connect(SNAME("changed"), callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
+ texture->connect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
}
_clear_tiles_outside_texture();
@@ -3948,6 +3948,9 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value)
} else if (components[1] == "animation_speed") {
set_tile_animation_speed(coords, p_value);
return true;
+ } else if (components[1] == "animation_mode") {
+ set_tile_animation_mode(coords, VariantCaster<TileSetAtlasSource::TileAnimationMode>::cast(p_value));
+ return true;
} else if (components[1] == "animation_frames_count") {
set_tile_animation_frames_count(coords, p_value);
return true;
@@ -4015,6 +4018,9 @@ bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const {
} else if (components[1] == "animation_speed") {
r_ret = get_tile_animation_speed(coords);
return true;
+ } else if (components[1] == "animation_mode") {
+ r_ret = get_tile_animation_mode(coords);
+ return true;
} else if (components[1] == "animation_frames_count") {
r_ret = get_tile_animation_frames_count(coords);
return true;
@@ -4090,6 +4096,13 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
}
tile_property_list.push_back(property_info);
+ // animation_mode.
+ property_info = PropertyInfo(Variant::INT, "animation_mode", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
+ if (E_tile.value.animation_mode == TILE_ANIMATION_MODE_DEFAULT) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+
// animation_frames_count.
tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
@@ -4252,6 +4265,20 @@ real_t TileSetAtlasSource::get_tile_animation_speed(const Vector2i p_atlas_coord
return tiles[p_atlas_coords].animation_speed;
}
+void TileSetAtlasSource::set_tile_animation_mode(const Vector2i p_atlas_coords, TileSetAtlasSource::TileAnimationMode p_mode) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+
+ tiles[p_atlas_coords].animation_mode = p_mode;
+
+ emit_signal(SNAME("changed"));
+}
+
+TileSetAtlasSource::TileAnimationMode TileSetAtlasSource::get_tile_animation_mode(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TILE_ANIMATION_MODE_DEFAULT, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+
+ return tiles[p_atlas_coords].animation_mode;
+}
+
void TileSetAtlasSource::set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count) {
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
ERR_FAIL_COND(p_frames_count < 1);
@@ -4577,6 +4604,8 @@ void TileSetAtlasSource::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tile_animation_separation", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_separation);
ClassDB::bind_method(D_METHOD("set_tile_animation_speed", "atlas_coords", "speed"), &TileSetAtlasSource::set_tile_animation_speed);
ClassDB::bind_method(D_METHOD("get_tile_animation_speed", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_speed);
+ ClassDB::bind_method(D_METHOD("set_tile_animation_mode", "atlas_coords", "mode"), &TileSetAtlasSource::set_tile_animation_mode);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_mode", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_mode);
ClassDB::bind_method(D_METHOD("set_tile_animation_frames_count", "atlas_coords", "frames_count"), &TileSetAtlasSource::set_tile_animation_frames_count);
ClassDB::bind_method(D_METHOD("get_tile_animation_frames_count", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_frames_count);
ClassDB::bind_method(D_METHOD("set_tile_animation_frame_duration", "atlas_coords", "frame_index", "duration"), &TileSetAtlasSource::set_tile_animation_frame_duration);
@@ -4599,6 +4628,10 @@ void TileSetAtlasSource::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_padded_texture"), &TileSetAtlasSource::_update_padded_texture);
ClassDB::bind_method(D_METHOD("get_runtime_texture"), &TileSetAtlasSource::get_runtime_texture);
ClassDB::bind_method(D_METHOD("get_runtime_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_runtime_tile_texture_region);
+
+ BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_DEFAULT)
+ BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_RANDOM_START_TIMES)
+ BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_MAX)
}
TileSetAtlasSource::~TileSetAtlasSource() {
@@ -5083,6 +5116,8 @@ void TileData::remove_terrain(int p_terrain_set, int p_index) {
if (terrain_set == p_terrain_set) {
if (terrain == p_index) {
terrain = -1;
+ } else if (terrain > p_index) {
+ terrain -= 1;
}
for (int i = 0; i < 16; i++) {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 337a945e7b..4150da53db 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -39,6 +39,7 @@
#include "scene/main/canvas_item.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
+#include "scene/resources/image_texture.h"
#include "scene/resources/navigation_polygon.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/physics_material.h"
@@ -46,7 +47,6 @@
#ifndef DISABLE_DEPRECATED
#include "scene/resources/shader.h"
-#include "scene/resources/texture.h"
#endif
class TileMap;
@@ -592,6 +592,13 @@ public:
class TileSetAtlasSource : public TileSetSource {
GDCLASS(TileSetAtlasSource, TileSetSource);
+public:
+ enum TileAnimationMode {
+ TILE_ANIMATION_MODE_DEFAULT,
+ TILE_ANIMATION_MODE_RANDOM_START_TIMES,
+ TILE_ANIMATION_MODE_MAX,
+ };
+
private:
struct TileAlternativesData {
Vector2i size_in_atlas = Vector2i(1, 1);
@@ -601,6 +608,7 @@ private:
int animation_columns = 0;
Vector2i animation_separation;
real_t animation_speed = 1.0;
+ TileSetAtlasSource::TileAnimationMode animation_mode = TILE_ANIMATION_MODE_DEFAULT;
LocalVector<real_t> animation_frames_durations;
// Alternatives
@@ -701,6 +709,8 @@ public:
Vector2i get_tile_animation_separation(const Vector2i p_atlas_coords) const;
void set_tile_animation_speed(const Vector2i p_atlas_coords, real_t p_speed);
real_t get_tile_animation_speed(const Vector2i p_atlas_coords) const;
+ void set_tile_animation_mode(const Vector2i p_atlas_coords, const TileSetAtlasSource::TileAnimationMode p_mode);
+ TileSetAtlasSource::TileAnimationMode get_tile_animation_mode(const Vector2i p_atlas_coords) const;
void set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count);
int get_tile_animation_frames_count(const Vector2i p_atlas_coords) const;
void set_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index, real_t p_duration);
@@ -932,4 +942,6 @@ VARIANT_ENUM_CAST(TileSet::TileShape);
VARIANT_ENUM_CAST(TileSet::TileLayout);
VARIANT_ENUM_CAST(TileSet::TileOffsetAxis);
+VARIANT_ENUM_CAST(TileSetAtlasSource::TileAnimationMode);
+
#endif // TILE_SET_H
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index a361b7584a..7f1c322c8f 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -46,6 +46,10 @@ bool VisualShaderNode::is_simple_decl() const {
return simple_decl;
}
+int VisualShaderNode::get_default_input_port(PortType p_type) const {
+ return 0;
+}
+
void VisualShaderNode::set_output_port_for_preview(int p_index) {
port_preview = p_index;
}
@@ -378,6 +382,8 @@ bool VisualShaderNode::is_input_port_default(int p_port, Shader::Mode p_mode) co
}
void VisualShaderNode::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_default_input_port", "type"), &VisualShaderNode::get_default_input_port);
+
ClassDB::bind_method(D_METHOD("set_output_port_for_preview", "port"), &VisualShaderNode::set_output_port_for_preview);
ClassDB::bind_method(D_METHOD("get_output_port_for_preview"), &VisualShaderNode::get_output_port_for_preview);
@@ -481,6 +487,12 @@ String VisualShaderNodeCustom::get_input_port_name(int p_port) const {
return input_ports[p_port].name;
}
+int VisualShaderNodeCustom::get_default_input_port(PortType p_type) const {
+ int ret = 0;
+ GDVIRTUAL_CALL(_get_default_input_port, p_type, ret);
+ return ret;
+}
+
int VisualShaderNodeCustom::get_output_port_count() const {
return output_ports.size();
}
@@ -649,6 +661,7 @@ void VisualShaderNodeCustom::_bind_methods() {
GDVIRTUAL_BIND(_get_input_port_count);
GDVIRTUAL_BIND(_get_input_port_type, "port");
GDVIRTUAL_BIND(_get_input_port_name, "port");
+ GDVIRTUAL_BIND(_get_default_input_port, "type");
GDVIRTUAL_BIND(_get_output_port_count);
GDVIRTUAL_BIND(_get_output_port_type, "port");
GDVIRTUAL_BIND(_get_output_port_name, "port");
@@ -767,7 +780,7 @@ void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, co
input->shader_type = p_type;
}
- n.node->connect("changed", callable_mp(this, &VisualShader::_queue_update));
+ n.node->connect_changed(callable_mp(this, &VisualShader::_queue_update));
Ref<VisualShaderNodeCustom> custom = n.node;
if (custom.is_valid()) {
@@ -834,7 +847,7 @@ void VisualShader::remove_node(Type p_type, int p_id) {
Graph *g = &graph[p_type];
ERR_FAIL_COND(!g->nodes.has(p_id));
- g->nodes[p_id].node->disconnect("changed", callable_mp(this, &VisualShader::_queue_update));
+ g->nodes[p_id].node->disconnect_changed(callable_mp(this, &VisualShader::_queue_update));
g->nodes.erase(p_id);
@@ -907,7 +920,7 @@ void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_c
}
}
- vsn->connect("changed", callable_mp(this, &VisualShader::_queue_update));
+ vsn->connect_changed(callable_mp(this, &VisualShader::_queue_update));
g->nodes[p_id].node = Ref<VisualShaderNode>(vsn);
_queue_update();
@@ -3645,6 +3658,8 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha AA Edge", "ALPHA_ANTIALIASING_EDGE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Alpha UV", "ALPHA_TEXTURE_COORDINATE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Depth", "DEPTH" },
+
////////////////////////////////////////////////////////////////////////
// Node3D, Light.
////////////////////////////////////////////////////////////////////////
@@ -3768,7 +3783,7 @@ bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
}
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
String port_name = get_input_port_name(p_index);
- return bool(port_name == "AO" || port_name == "Normal" || port_name == "Rim" || port_name == "Clearcoat" || port_name == "Anisotropy" || port_name == "Subsurf Scatter" || port_name == "Alpha Scissor Threshold");
+ return bool(port_name == "AO" || port_name == "Normal" || port_name == "Rim" || port_name == "Clearcoat" || port_name == "Anisotropy" || port_name == "Subsurf Scatter" || port_name == "Alpha Scissor Threshold" || port_name == "Depth");
}
return false;
}
@@ -4854,7 +4869,7 @@ VisualShaderNodeVarying::VisualShaderNodeVarying() {
////////////// Varying Setter
String VisualShaderNodeVaryingSetter::get_caption() const {
- return vformat("VaryingSetter");
+ return "VaryingSetter";
}
int VisualShaderNodeVaryingSetter::get_input_port_count() const {
@@ -4896,7 +4911,7 @@ VisualShaderNodeVaryingSetter::VisualShaderNodeVaryingSetter() {
////////////// Varying Getter
String VisualShaderNodeVaryingGetter::get_caption() const {
- return vformat("VaryingGetter");
+ return "VaryingGetter";
}
int VisualShaderNodeVaryingGetter::get_input_port_count() const {
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 61418b680e..d3657eae07 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -289,6 +289,7 @@ public:
virtual int get_input_port_count() const = 0;
virtual PortType get_input_port_type(int p_port) const = 0;
virtual String get_input_port_name(int p_port) const = 0;
+ virtual int get_default_input_port(PortType p_type) const;
virtual void set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value = Variant());
Variant get_input_port_default_value(int p_port) const; // if NIL (default if node does not set anything) is returned, it means no default value is wanted if disconnected, thus no input var must be supplied (empty string will be supplied)
@@ -367,6 +368,7 @@ protected:
virtual int get_input_port_count() const override;
virtual PortType get_input_port_type(int p_port) const override;
virtual String get_input_port_name(int p_port) const override;
+ virtual int get_default_input_port(PortType p_type) const override;
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
@@ -384,6 +386,7 @@ protected:
GDVIRTUAL0RC(int, _get_input_port_count)
GDVIRTUAL1RC(PortType, _get_input_port_type, int)
GDVIRTUAL1RC(String, _get_input_port_name, int)
+ GDVIRTUAL1RC(int, _get_default_input_port, PortType)
GDVIRTUAL0RC(int, _get_output_port_count)
GDVIRTUAL1RC(PortType, _get_output_port_type, int)
GDVIRTUAL1RC(String, _get_output_port_name, int)
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 7fdad8e930..4023de9023 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -30,6 +30,8 @@
#include "visual_shader_nodes.h"
+#include "scene/resources/image_texture.h"
+
////////////// Vector Base
VisualShaderNodeVectorBase::PortType VisualShaderNodeVectorBase::get_input_port_type(int p_port) const {
@@ -1725,6 +1727,135 @@ VisualShaderNodeLinearSceneDepth::VisualShaderNodeLinearSceneDepth() {
simple_decl = false;
}
+////////////// World Position from Depth
+
+String VisualShaderNodeWorldPositionFromDepth::get_caption() const {
+ return "WorldPositionFromDepth";
+}
+
+int VisualShaderNodeWorldPositionFromDepth::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeWorldPositionFromDepth::PortType VisualShaderNodeWorldPositionFromDepth::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_2D;
+}
+
+String VisualShaderNodeWorldPositionFromDepth::get_input_port_name(int p_port) const {
+ return "screen uv";
+}
+
+bool VisualShaderNodeWorldPositionFromDepth::is_input_port_default(int p_port, Shader::Mode p_mode) const {
+ if (p_port == 0) {
+ return true;
+ }
+ return false;
+}
+
+int VisualShaderNodeWorldPositionFromDepth::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeWorldPositionFromDepth::PortType VisualShaderNodeWorldPositionFromDepth::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_3D;
+}
+
+String VisualShaderNodeWorldPositionFromDepth::get_output_port_name(int p_port) const {
+ return "world position";
+}
+
+bool VisualShaderNodeWorldPositionFromDepth::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+String VisualShaderNodeWorldPositionFromDepth::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, "depth_tex") + " : hint_depth_texture, repeat_disable, filter_nearest;\n";
+}
+
+String VisualShaderNodeWorldPositionFromDepth::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ String uv = p_input_vars[0].is_empty() ? "SCREEN_UV" : p_input_vars[0];
+ code += " {\n";
+
+ code += " float __log_depth = textureLod(" + make_unique_id(p_type, p_id, "depth_tex") + ", " + uv + ", 0.0).x;\n";
+ if (!RenderingServer::get_singleton()->is_low_end()) {
+ code += " vec4 __depth_view = INV_PROJECTION_MATRIX * vec4(" + uv + " * 2.0 - 1.0, __log_depth, 1.0);\n";
+ } else {
+ code += " vec4 __depth_view = INV_PROJECTION_MATRIX * vec4(vec3(" + uv + ", __log_depth) * 2.0 - 1.0, 1.0);\n";
+ }
+ code += " __depth_view.xyz /= __depth_view.w;\n";
+ code += vformat(" %s = (INV_VIEW_MATRIX * __depth_view).xyz;\n", p_output_vars[0]);
+
+ code += " }\n";
+ return code;
+}
+
+VisualShaderNodeWorldPositionFromDepth::VisualShaderNodeWorldPositionFromDepth() {
+ simple_decl = false;
+}
+
+////////////// Unpack Normals in World Space
+
+String VisualShaderNodeScreenNormalWorldSpace::get_caption() const {
+ return "ScreenNormalWorldSpace";
+}
+
+int VisualShaderNodeScreenNormalWorldSpace::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeScreenNormalWorldSpace::PortType VisualShaderNodeScreenNormalWorldSpace::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_2D;
+}
+
+String VisualShaderNodeScreenNormalWorldSpace::get_input_port_name(int p_port) const {
+ return "screen uv";
+}
+
+bool VisualShaderNodeScreenNormalWorldSpace::is_input_port_default(int p_port, Shader::Mode p_mode) const {
+ if (p_port == 0) {
+ return true;
+ }
+ return false;
+}
+
+int VisualShaderNodeScreenNormalWorldSpace::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeScreenNormalWorldSpace::PortType VisualShaderNodeScreenNormalWorldSpace::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_3D;
+}
+
+String VisualShaderNodeScreenNormalWorldSpace::get_output_port_name(int p_port) const {
+ return "screen normal";
+}
+
+bool VisualShaderNodeScreenNormalWorldSpace::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+String VisualShaderNodeScreenNormalWorldSpace::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, "normal_rough_tex") + " : hint_normal_roughness_texture, repeat_disable, filter_nearest;\n";
+}
+
+String VisualShaderNodeScreenNormalWorldSpace::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ String uv = p_input_vars[0].is_empty() ? "SCREEN_UV" : p_input_vars[0];
+ code += " {\n";
+
+ code += " vec3 __normals = textureLod(" + make_unique_id(p_type, p_id, "normal_rough_tex") + ", " + uv + ", 0.0).xyz;\n";
+ code += " __normals = __normals * 2.0 - 1.0;\n";
+ code += vformat(" %s = mat3(INV_VIEW_MATRIX) * __normals;\n", p_output_vars[0]);
+
+ code += " }\n";
+ return code;
+}
+
+VisualShaderNodeScreenNormalWorldSpace::VisualShaderNodeScreenNormalWorldSpace() {
+ simple_decl = false;
+}
+
////////////// Float Op
String VisualShaderNodeFloatOp::get_caption() const {
@@ -4135,6 +4266,10 @@ String VisualShaderNodeStep::get_input_port_name(int p_port) const {
return String();
}
+int VisualShaderNodeStep::get_default_input_port(PortType p_type) const {
+ return 1;
+}
+
int VisualShaderNodeStep::get_output_port_count() const {
return 1;
}
@@ -4290,6 +4425,10 @@ String VisualShaderNodeSmoothStep::get_input_port_name(int p_port) const {
return String();
}
+int VisualShaderNodeSmoothStep::get_default_input_port(PortType p_type) const {
+ return 2;
+}
+
int VisualShaderNodeSmoothStep::get_output_port_count() const {
return 1;
}
@@ -7961,3 +8100,100 @@ VisualShaderNodeRemap::VisualShaderNodeRemap() {
simple_decl = false;
}
+
+////////////// RotationByAxis
+
+String VisualShaderNodeRotationByAxis::get_caption() const {
+ return "RotationByAxis";
+}
+
+int VisualShaderNodeRotationByAxis::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeRotationByAxis::PortType VisualShaderNodeRotationByAxis::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_3D;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_VECTOR_3D;
+ default:
+ break;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRotationByAxis::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "input";
+ case 1:
+ return "angle";
+ case 2:
+ return "axis";
+ default:
+ break;
+ }
+
+ return "";
+}
+
+int VisualShaderNodeRotationByAxis::get_output_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeRotationByAxis::PortType VisualShaderNodeRotationByAxis::get_output_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_3D;
+ case 1:
+ return PORT_TYPE_TRANSFORM;
+ default:
+ break;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRotationByAxis::get_output_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "output";
+ case 1:
+ return "rotationMat";
+ default:
+ break;
+ }
+
+ return "";
+}
+
+bool VisualShaderNodeRotationByAxis::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+String VisualShaderNodeRotationByAxis::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ code += " {\n";
+ code += vformat(" float __angle = %s;\n", p_input_vars[1]);
+ code += vformat(" vec3 __axis = normalize(%s);\n", p_input_vars[2]);
+ code += vformat(" mat3 __rot_matrix = mat3(\n");
+ code += vformat(" vec3( cos(__angle)+__axis.x*__axis.x*(1.0 - cos(__angle)), __axis.x*__axis.y*(1.0-cos(__angle))-__axis.z*sin(__angle), __axis.x*__axis.z*(1.0-cos(__angle))+__axis.y*sin(__angle) ),\n");
+ code += vformat(" vec3( __axis.y*__axis.x*(1.0-cos(__angle))+__axis.z*sin(__angle), cos(__angle)+__axis.y*__axis.y*(1.0-cos(__angle)), __axis.y*__axis.z*(1.0-cos(__angle))-__axis.x*sin(__angle) ),\n");
+ code += vformat(" vec3( __axis.z*__axis.x*(1.0-cos(__angle))-__axis.y*sin(__angle), __axis.z*__axis.y*(1.0-cos(__angle))+__axis.x*sin(__angle), cos(__angle)+__axis.z*__axis.z*(1.0-cos(__angle)) )\n");
+ code += vformat(" );\n");
+ code += vformat(" %s = %s * __rot_matrix;\n", p_output_vars[0], p_input_vars[0]);
+ code += vformat(" %s = mat4(__rot_matrix);\n", p_output_vars[1]);
+ code += " }\n";
+ return code;
+}
+
+VisualShaderNodeRotationByAxis::VisualShaderNodeRotationByAxis() {
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0));
+
+ simple_decl = false;
+}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index fa6b134526..97d8df3c0b 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -31,8 +31,12 @@
#ifndef VISUAL_SHADER_NODES_H
#define VISUAL_SHADER_NODES_H
+#include "scene/resources/curve_texture.h"
#include "scene/resources/visual_shader.h"
+class Cubemap;
+class Texture2DArray;
+
///////////////////////////////////////
/// Vector Base Node
///////////////////////////////////////
@@ -676,6 +680,50 @@ public:
VisualShaderNodeLinearSceneDepth();
};
+class VisualShaderNodeWorldPositionFromDepth : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeWorldPositionFromDepth, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+ virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeWorldPositionFromDepth();
+};
+
+class VisualShaderNodeScreenNormalWorldSpace : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeScreenNormalWorldSpace, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+ virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeScreenNormalWorldSpace();
+};
+
///////////////////////////////////////
/// OPS
///////////////////////////////////////
@@ -1657,6 +1705,7 @@ public:
virtual int get_input_port_count() const override;
virtual PortType get_input_port_type(int p_port) const override;
virtual String get_input_port_name(int p_port) const override;
+ virtual int get_default_input_port(PortType p_type) const override;
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
@@ -1703,6 +1752,7 @@ public:
virtual int get_input_port_count() const override;
virtual PortType get_input_port_type(int p_port) const override;
virtual String get_input_port_name(int p_port) const override;
+ virtual int get_default_input_port(PortType p_type) const override;
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
@@ -2907,4 +2957,24 @@ public:
VisualShaderNodeRemap();
};
+class VisualShaderNodeRotationByAxis : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeRotationByAxis, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeRotationByAxis();
+};
+
#endif // VISUAL_SHADER_NODES_H
diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp
index 9cf42b681c..cfea6e21ee 100644
--- a/scene/resources/visual_shader_particle_nodes.cpp
+++ b/scene/resources/visual_shader_particle_nodes.cpp
@@ -30,7 +30,7 @@
#include "visual_shader_particle_nodes.h"
-#include "core/core_string_names.h"
+#include "scene/resources/image_texture.h"
// VisualShaderNodeParticleEmitter
@@ -637,21 +637,13 @@ void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref<Mesh> p_mesh) {
}
if (mesh.is_valid()) {
- Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures);
-
- if (mesh->is_connected(CoreStringNames::get_singleton()->changed, callable)) {
- mesh->disconnect(CoreStringNames::get_singleton()->changed, callable);
- }
+ mesh->disconnect_changed(callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures));
}
mesh = p_mesh;
if (mesh.is_valid()) {
- Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures);
-
- if (!mesh->is_connected(CoreStringNames::get_singleton()->changed, callable)) {
- mesh->connect(CoreStringNames::get_singleton()->changed, callable);
- }
+ mesh->connect_changed(callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures));
}
emit_changed();
@@ -732,7 +724,7 @@ void VisualShaderNodeParticleMeshEmitter::_bind_methods() {
}
VisualShaderNodeParticleMeshEmitter::VisualShaderNodeParticleMeshEmitter() {
- connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures));
+ connect_changed(callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures));
position_texture.instantiate();
normal_texture.instantiate();
diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h
index 08fb059534..652b5dff03 100644
--- a/scene/resources/visual_shader_particle_nodes.h
+++ b/scene/resources/visual_shader_particle_nodes.h
@@ -33,6 +33,8 @@
#include "scene/resources/visual_shader.h"
+class ImageTexture;
+
// Emit nodes
class VisualShaderNodeParticleEmitter : public VisualShaderNode {
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index 297d219caf..b8646c5387 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -68,6 +68,7 @@ RID World3D::get_navigation_map() const {
NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_GET("navigation/3d/default_cell_size"));
NavigationServer3D::get_singleton()->map_set_cell_height(navigation_map, GLOBAL_GET("navigation/3d/default_cell_height"));
+ NavigationServer3D::get_singleton()->map_set_up(navigation_map, GLOBAL_GET("navigation/3d/default_up"));
NavigationServer3D::get_singleton()->map_set_use_edge_connections(navigation_map, GLOBAL_GET("navigation/3d/use_edge_connections"));
NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_GET("navigation/3d/default_edge_connection_margin"));
NavigationServer3D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_GET("navigation/3d/default_link_connection_radius"));
diff --git a/scene/resources/world_boundary_shape_3d.cpp b/scene/resources/world_boundary_shape_3d.cpp
index 3074bd1fd8..beaaddc95e 100644
--- a/scene/resources/world_boundary_shape_3d.cpp
+++ b/scene/resources/world_boundary_shape_3d.cpp
@@ -69,7 +69,7 @@ void WorldBoundaryShape3D::_update_shape() {
void WorldBoundaryShape3D::set_plane(const Plane &p_plane) {
plane = p_plane;
_update_shape();
- notify_change_to_owners();
+ emit_changed();
}
const Plane &WorldBoundaryShape3D::get_plane() const {
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 536ffd1fe4..87835a9522 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -57,7 +57,6 @@ SceneStringNames::SceneStringNames() {
sleeping_state_changed = StaticCString::create("sleeping_state_changed");
finished = StaticCString::create("finished");
- emission_finished = StaticCString::create("emission_finished");
animation_finished = StaticCString::create("animation_finished");
animation_changed = StaticCString::create("animation_changed");
animation_started = StaticCString::create("animation_started");
@@ -168,8 +167,6 @@ SceneStringNames::SceneStringNames() {
_drop_data = StaticCString::create("_drop_data");
_can_drop_data = StaticCString::create("_can_drop_data");
- _im_update = StaticCString::create("_im_update"); // Sprite3D
-
baked_light_changed = StaticCString::create("baked_light_changed");
_baked_light_changed = StaticCString::create("_baked_light_changed");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index ca8f7a1e7d..ad1135e24c 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -93,7 +93,6 @@ public:
StringName sort_children;
StringName finished;
- StringName emission_finished;
StringName animation_finished;
StringName animation_changed;
StringName animation_started;
@@ -180,8 +179,6 @@ public:
StringName _get_minimum_size;
- StringName _im_update;
-
StringName baked_light_changed;
StringName _baked_light_changed;
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 41fa0d2d47..f41238b075 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -362,10 +362,18 @@ String DisplayServer::clipboard_get() const {
ERR_FAIL_V_MSG(String(), "Clipboard is not supported by this display server.");
}
+Ref<Image> DisplayServer::clipboard_get_image() const {
+ ERR_FAIL_V_MSG(Ref<Image>(), "Clipboard is not supported by this display server.");
+}
+
bool DisplayServer::clipboard_has() const {
return !clipboard_get().is_empty();
}
+bool DisplayServer::clipboard_has_image() const {
+ return clipboard_get_image().is_valid();
+}
+
void DisplayServer::clipboard_set_primary(const String &p_text) {
WARN_PRINT("Primary clipboard is not supported by this display server.");
}
@@ -497,6 +505,11 @@ Error DisplayServer::dialog_input_text(String p_title, String p_description, Str
return OK;
}
+Error DisplayServer::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+ WARN_PRINT("Native dialogs not supported by this display server.");
+ return OK;
+}
+
int DisplayServer::keyboard_get_layout_count() const {
return 0;
}
@@ -520,6 +533,10 @@ Key DisplayServer::keyboard_get_keycode_from_physical(Key p_keycode) const {
ERR_FAIL_V_MSG(p_keycode, "Not supported by this display server.");
}
+Key DisplayServer::keyboard_get_label_from_physical(Key p_keycode) const {
+ ERR_FAIL_V_MSG(p_keycode, "Not supported by this display server.");
+}
+
void DisplayServer::force_process_and_drop_events() {
}
@@ -640,7 +657,9 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("clipboard_set", "clipboard"), &DisplayServer::clipboard_set);
ClassDB::bind_method(D_METHOD("clipboard_get"), &DisplayServer::clipboard_get);
+ ClassDB::bind_method(D_METHOD("clipboard_get_image"), &DisplayServer::clipboard_get_image);
ClassDB::bind_method(D_METHOD("clipboard_has"), &DisplayServer::clipboard_has);
+ ClassDB::bind_method(D_METHOD("clipboard_has_image"), &DisplayServer::clipboard_has_image);
ClassDB::bind_method(D_METHOD("clipboard_set_primary", "clipboard_primary"), &DisplayServer::clipboard_set_primary);
ClassDB::bind_method(D_METHOD("clipboard_get_primary"), &DisplayServer::clipboard_get_primary);
@@ -751,12 +770,15 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("dialog_show", "title", "description", "buttons", "callback"), &DisplayServer::dialog_show);
ClassDB::bind_method(D_METHOD("dialog_input_text", "title", "description", "existing_text", "callback"), &DisplayServer::dialog_input_text);
+ ClassDB::bind_method(D_METHOD("file_dialog_show", "title", "current_directory", "filename", "show_hidden", "mode", "filters", "callback"), &DisplayServer::file_dialog_show);
+
ClassDB::bind_method(D_METHOD("keyboard_get_layout_count"), &DisplayServer::keyboard_get_layout_count);
ClassDB::bind_method(D_METHOD("keyboard_get_current_layout"), &DisplayServer::keyboard_get_current_layout);
ClassDB::bind_method(D_METHOD("keyboard_set_current_layout", "index"), &DisplayServer::keyboard_set_current_layout);
ClassDB::bind_method(D_METHOD("keyboard_get_layout_language", "index"), &DisplayServer::keyboard_get_layout_language);
ClassDB::bind_method(D_METHOD("keyboard_get_layout_name", "index"), &DisplayServer::keyboard_get_layout_name);
ClassDB::bind_method(D_METHOD("keyboard_get_keycode_from_physical", "keycode"), &DisplayServer::keyboard_get_keycode_from_physical);
+ ClassDB::bind_method(D_METHOD("keyboard_get_label_from_physical", "keycode"), &DisplayServer::keyboard_get_label_from_physical);
ClassDB::bind_method(D_METHOD("process_events"), &DisplayServer::process_events);
ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events);
@@ -841,6 +863,12 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(CURSOR_HELP);
BIND_ENUM_CONSTANT(CURSOR_MAX);
+ BIND_ENUM_CONSTANT(FILE_DIALOG_MODE_OPEN_FILE);
+ BIND_ENUM_CONSTANT(FILE_DIALOG_MODE_OPEN_FILES);
+ BIND_ENUM_CONSTANT(FILE_DIALOG_MODE_OPEN_DIR);
+ BIND_ENUM_CONSTANT(FILE_DIALOG_MODE_OPEN_ANY);
+ BIND_ENUM_CONSTANT(FILE_DIALOG_MODE_SAVE_FILE);
+
BIND_ENUM_CONSTANT(WINDOW_MODE_WINDOWED);
BIND_ENUM_CONSTANT(WINDOW_MODE_MINIMIZED);
BIND_ENUM_CONSTANT(WINDOW_MODE_MAXIMIZED);
diff --git a/servers/display_server.h b/servers/display_server.h
index fc8207f2d3..85f9270696 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -245,7 +245,9 @@ public:
virtual void clipboard_set(const String &p_text);
virtual String clipboard_get() const;
+ virtual Ref<Image> clipboard_get_image() const;
virtual bool clipboard_has() const;
+ virtual bool clipboard_has_image() const;
virtual void clipboard_set_primary(const String &p_text);
virtual String clipboard_get_primary() const;
@@ -493,12 +495,22 @@ public:
virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback);
virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback);
+ enum FileDialogMode {
+ FILE_DIALOG_MODE_OPEN_FILE,
+ FILE_DIALOG_MODE_OPEN_FILES,
+ FILE_DIALOG_MODE_OPEN_DIR,
+ FILE_DIALOG_MODE_OPEN_ANY,
+ FILE_DIALOG_MODE_SAVE_FILE
+ };
+ virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback);
+
virtual int keyboard_get_layout_count() const;
virtual int keyboard_get_current_layout() const;
virtual void keyboard_set_current_layout(int p_index);
virtual String keyboard_get_layout_language(int p_index) const;
virtual String keyboard_get_layout_name(int p_index) const;
virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const;
+ virtual Key keyboard_get_label_from_physical(Key p_keycode) const;
virtual int tablet_get_driver_count() const { return 1; };
virtual String tablet_get_driver_name(int p_driver) const { return "default"; };
@@ -545,5 +557,6 @@ VARIANT_ENUM_CAST(DisplayServer::VirtualKeyboardType);
VARIANT_ENUM_CAST(DisplayServer::CursorShape)
VARIANT_ENUM_CAST(DisplayServer::VSyncMode)
VARIANT_ENUM_CAST(DisplayServer::TTSUtteranceEvent)
+VARIANT_ENUM_CAST(DisplayServer::FileDialogMode)
#endif // DISPLAY_SERVER_H
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index e906db2acf..cd92d9dd2f 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -391,6 +391,8 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("query_path", "parameters", "result"), &NavigationServer2D::query_path);
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
+ ClassDB::bind_method(D_METHOD("region_set_enabled", "region", "enabled"), &NavigationServer2D::region_set_enabled);
+ ClassDB::bind_method(D_METHOD("region_get_enabled", "region"), &NavigationServer2D::region_get_enabled);
ClassDB::bind_method(D_METHOD("region_set_use_edge_connections", "region", "enabled"), &NavigationServer2D::region_set_use_edge_connections);
ClassDB::bind_method(D_METHOD("region_get_use_edge_connections", "region"), &NavigationServer2D::region_get_use_edge_connections);
ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer2D::region_set_enter_cost);
@@ -413,6 +415,8 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer2D::link_create);
ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer2D::link_set_map);
ClassDB::bind_method(D_METHOD("link_get_map", "link"), &NavigationServer2D::link_get_map);
+ ClassDB::bind_method(D_METHOD("link_set_enabled", "link", "enabled"), &NavigationServer2D::link_set_enabled);
+ ClassDB::bind_method(D_METHOD("link_get_enabled", "link"), &NavigationServer2D::link_get_enabled);
ClassDB::bind_method(D_METHOD("link_set_bidirectional", "link", "bidirectional"), &NavigationServer2D::link_set_bidirectional);
ClassDB::bind_method(D_METHOD("link_is_bidirectional", "link"), &NavigationServer2D::link_is_bidirectional);
ClassDB::bind_method(D_METHOD("link_set_navigation_layers", "link", "navigation_layers"), &NavigationServer2D::link_set_navigation_layers);
@@ -536,6 +540,8 @@ RID FORWARD_2_C(map_get_closest_point_owner, RID, p_map, const Vector2 &, p_poin
RID FORWARD_0(region_create);
+void FORWARD_2(region_set_enabled, RID, p_region, bool, p_enabled, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(region_get_enabled, RID, p_region, rid_to_rid);
void FORWARD_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled, rid_to_rid, bool_to_bool);
bool FORWARD_1_C(region_get_use_edge_connections, RID, p_region, rid_to_rid);
@@ -564,6 +570,8 @@ RID FORWARD_0(link_create);
void FORWARD_2(link_set_map, RID, p_link, RID, p_map, rid_to_rid, rid_to_rid);
RID FORWARD_1_C(link_get_map, RID, p_link, rid_to_rid);
+void FORWARD_2(link_set_enabled, RID, p_link, bool, p_enabled, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(link_get_enabled, RID, p_link, rid_to_rid);
void FORWARD_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional, rid_to_rid, bool_to_bool);
bool FORWARD_1_C(link_is_bidirectional, RID, p_link, rid_to_rid);
void FORWARD_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers, rid_to_rid, uint32_to_uint32);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index b9b1e2a75e..c78edaf878 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -101,6 +101,9 @@ public:
/// Creates a new region.
virtual RID region_create();
+ virtual void region_set_enabled(RID p_region, bool p_enabled);
+ virtual bool region_get_enabled(RID p_region) const;
+
virtual void region_set_use_edge_connections(RID p_region, bool p_enabled);
virtual bool region_get_use_edge_connections(RID p_region) const;
@@ -144,6 +147,9 @@ public:
virtual void link_set_map(RID p_link, RID p_map);
virtual RID link_get_map(RID p_link) const;
+ virtual void link_set_enabled(RID p_link, bool p_enabled);
+ virtual bool link_get_enabled(RID p_link) const;
+
/// Set whether this link travels in both directions.
virtual void link_set_bidirectional(RID p_link, bool p_bidirectional);
virtual bool link_is_bidirectional(RID p_link) const;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index dae8ea6dcd..04facdb8d9 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -67,6 +67,8 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("query_path", "parameters", "result"), &NavigationServer3D::query_path);
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create);
+ ClassDB::bind_method(D_METHOD("region_set_enabled", "region", "enabled"), &NavigationServer3D::region_set_enabled);
+ ClassDB::bind_method(D_METHOD("region_get_enabled", "region"), &NavigationServer3D::region_get_enabled);
ClassDB::bind_method(D_METHOD("region_set_use_edge_connections", "region", "enabled"), &NavigationServer3D::region_set_use_edge_connections);
ClassDB::bind_method(D_METHOD("region_get_use_edge_connections", "region"), &NavigationServer3D::region_get_use_edge_connections);
ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer3D::region_set_enter_cost);
@@ -82,7 +84,9 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_get_navigation_layers", "region"), &NavigationServer3D::region_get_navigation_layers);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer3D::region_set_transform);
ClassDB::bind_method(D_METHOD("region_set_navigation_mesh", "region", "navigation_mesh"), &NavigationServer3D::region_set_navigation_mesh);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("region_bake_navigation_mesh", "navigation_mesh", "root_node"), &NavigationServer3D::region_bake_navigation_mesh);
+#endif // DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer3D::region_get_connections_count);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_start);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_end);
@@ -90,6 +94,8 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer3D::link_create);
ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer3D::link_set_map);
ClassDB::bind_method(D_METHOD("link_get_map", "link"), &NavigationServer3D::link_get_map);
+ ClassDB::bind_method(D_METHOD("link_set_enabled", "link", "enabled"), &NavigationServer3D::link_set_enabled);
+ ClassDB::bind_method(D_METHOD("link_get_enabled", "link"), &NavigationServer3D::link_get_enabled);
ClassDB::bind_method(D_METHOD("link_set_bidirectional", "link", "bidirectional"), &NavigationServer3D::link_set_bidirectional);
ClassDB::bind_method(D_METHOD("link_is_bidirectional", "link"), &NavigationServer3D::link_is_bidirectional);
ClassDB::bind_method(D_METHOD("link_set_navigation_layers", "link", "navigation_layers"), &NavigationServer3D::link_set_navigation_layers);
@@ -183,13 +189,14 @@ NavigationServer3D::NavigationServer3D() {
ERR_FAIL_COND(singleton != nullptr);
singleton = this;
- GLOBAL_DEF_BASIC("navigation/2d/default_cell_size", 1);
+ GLOBAL_DEF_BASIC("navigation/2d/default_cell_size", 1.0);
GLOBAL_DEF("navigation/2d/use_edge_connections", true);
- GLOBAL_DEF_BASIC("navigation/2d/default_edge_connection_margin", 1);
- GLOBAL_DEF_BASIC("navigation/2d/default_link_connection_radius", 4);
+ GLOBAL_DEF_BASIC("navigation/2d/default_edge_connection_margin", 1.0);
+ GLOBAL_DEF_BASIC("navigation/2d/default_link_connection_radius", 4.0);
GLOBAL_DEF_BASIC("navigation/3d/default_cell_size", 0.25);
GLOBAL_DEF_BASIC("navigation/3d/default_cell_height", 0.25);
+ GLOBAL_DEF("navigation/3d/default_up", Vector3(0, 1, 0));
GLOBAL_DEF("navigation/3d/use_edge_connections", true);
GLOBAL_DEF_BASIC("navigation/3d/default_edge_connection_margin", 0.25);
GLOBAL_DEF_BASIC("navigation/3d/default_link_connection_radius", 1.0);
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index cf5552e676..391730e18f 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -117,6 +117,9 @@ public:
/// Creates a new region.
virtual RID region_create() = 0;
+ virtual void region_set_enabled(RID p_region, bool p_enabled) = 0;
+ virtual bool region_get_enabled(RID p_region) const = 0;
+
virtual void region_set_use_edge_connections(RID p_region, bool p_enabled) = 0;
virtual bool region_get_use_edge_connections(RID p_region) const = 0;
@@ -148,8 +151,10 @@ public:
/// Set the navigation mesh of this region.
virtual void region_set_navigation_mesh(RID p_region, Ref<NavigationMesh> p_navigation_mesh) = 0;
+#ifndef DISABLE_DEPRECATED
/// Bake the navigation mesh.
virtual void region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) = 0;
+#endif // DISABLE_DEPRECATED
/// Get a list of a region's connection to other regions.
virtual int region_get_connections_count(RID p_region) const = 0;
@@ -163,6 +168,9 @@ public:
virtual void link_set_map(RID p_link, RID p_map) = 0;
virtual RID link_get_map(RID p_link) const = 0;
+ virtual void link_set_enabled(RID p_link, bool p_enabled) = 0;
+ virtual bool link_get_enabled(RID p_link) const = 0;
+
/// Set whether this link travels in both directions.
virtual void link_set_bidirectional(RID p_link, bool p_bidirectional) = 0;
virtual bool link_is_bidirectional(RID p_link) const = 0;
diff --git a/servers/navigation_server_3d_dummy.h b/servers/navigation_server_3d_dummy.h
index 8e91ec812f..b2d452f67a 100644
--- a/servers/navigation_server_3d_dummy.h
+++ b/servers/navigation_server_3d_dummy.h
@@ -64,6 +64,8 @@ public:
TypedArray<RID> map_get_obstacles(RID p_map) const override { return TypedArray<RID>(); }
void map_force_update(RID p_map) override {}
RID region_create() override { return RID(); }
+ void region_set_enabled(RID p_region, bool p_enabled) override {}
+ bool region_get_enabled(RID p_region) const override { return false; }
void region_set_use_edge_connections(RID p_region, bool p_enabled) override {}
bool region_get_use_edge_connections(RID p_region) const override { return false; }
void region_set_enter_cost(RID p_region, real_t p_enter_cost) override {}
@@ -79,13 +81,17 @@ public:
uint32_t region_get_navigation_layers(RID p_region) const override { return 0; }
void region_set_transform(RID p_region, Transform3D p_transform) override {}
void region_set_navigation_mesh(RID p_region, Ref<NavigationMesh> p_navigation_mesh) override {}
+#ifndef DISABLE_DEPRECATED
void region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) override {}
+#endif // DISABLE_DEPRECATED
int region_get_connections_count(RID p_region) const override { return 0; }
Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override { return Vector3(); }
Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override { return Vector3(); }
RID link_create() override { return RID(); }
void link_set_map(RID p_link, RID p_map) override {}
RID link_get_map(RID p_link) const override { return RID(); }
+ void link_set_enabled(RID p_link, bool p_enabled) override {}
+ bool link_get_enabled(RID p_link) const override { return false; }
void link_set_bidirectional(RID p_link, bool p_bidirectional) override {}
bool link_is_bidirectional(RID p_link) const override { return false; }
void link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers) override {}
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 7cc9a82699..67e48df9c9 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -69,8 +69,10 @@
#include "physics_server_3d.h"
#include "physics_server_3d_wrap_mt.h"
#include "rendering/renderer_compositor.h"
+#include "rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "rendering/rendering_device.h"
#include "rendering/rendering_device_binds.h"
+#include "rendering/storage/render_scene_buffers.h"
#include "rendering_server.h"
#include "servers/extensions/physics_server_2d_extension.h"
#include "servers/extensions/physics_server_3d_extension.h"
@@ -247,6 +249,11 @@ void register_server_types() {
GDREGISTER_CLASS(RDShaderFile);
GDREGISTER_CLASS(RDPipelineSpecializationConstant);
+ GDREGISTER_CLASS(RenderSceneBuffersConfiguration);
+ GDREGISTER_ABSTRACT_CLASS(RenderSceneBuffers);
+ GDREGISTER_CLASS(RenderSceneBuffersExtension);
+ GDREGISTER_ABSTRACT_CLASS(RenderSceneBuffersRD);
+
GDREGISTER_CLASS(CameraFeed);
GDREGISTER_ABSTRACT_CLASS(PhysicsDirectBodyState2D);
diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h
index 768b1ba702..71a1801de9 100644
--- a/servers/rendering/dummy/storage/texture_storage.h
+++ b/servers/rendering/dummy/storage/texture_storage.h
@@ -117,6 +117,8 @@ public:
virtual void texture_set_path(RID p_texture, const String &p_path) override{};
virtual String texture_get_path(RID p_texture) const override { return String(); };
+ virtual Image::Format texture_get_format(RID p_texture) const override { return Image::FORMAT_MAX; }
+
virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override{};
virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override{};
virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override{};
@@ -127,6 +129,7 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); };
+ virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) override{};
virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override { return RID(); };
virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override { return 0; };
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index 86484c982a..eba1c145e3 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -962,7 +962,7 @@ void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, con
RD::get_singleton()->draw_list_end();
}
-void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) {
+void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip, BitField<RD::BarrierMask> p_post_barrier) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -994,7 +994,7 @@ void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuf
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER);
+ RD::get_singleton()->draw_list_end(p_post_barrier);
}
void CopyEffects::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) {
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h
index 3cd26d0f7e..470ac1acee 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.h
+++ b/servers/rendering/renderer_rd/effects/copy_effects.h
@@ -341,7 +341,7 @@ public:
void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false);
void set_color_raster(RID p_dest_texture, const Color &p_color, const Rect2i &p_region);
- void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip);
+ void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip, BitField<RD::BarrierMask> p_post_barrier = RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER);
void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size);
void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp
new file mode 100644
index 0000000000..8cd3c22483
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp
@@ -0,0 +1,328 @@
+/**************************************************************************/
+/* debug_effects.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 "debug_effects.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
+
+using namespace RendererRD;
+
+DebugEffects::DebugEffects() {
+ {
+ // Shadow Frustum debug shader
+ Vector<String> modes;
+ modes.push_back("");
+
+ shadow_frustum.shader.initialize(modes);
+ shadow_frustum.shader_version = shadow_frustum.shader.version_create();
+
+ RD::PipelineRasterizationState raster_state = RD::PipelineRasterizationState();
+ shadow_frustum.pipelines[SFP_TRANSPARENT].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
+
+ raster_state.wireframe = true;
+ shadow_frustum.pipelines[SFP_WIREFRAME].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_LINES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+}
+
+void DebugEffects::_create_frustum_arrays() {
+ if (frustum.vertex_buffer.is_null()) {
+ // Create vertex buffer, but don't put data in it yet
+ frustum.vertex_buffer = RD::get_singleton()->vertex_buffer_create(8 * sizeof(float) * 3, Vector<uint8_t>(), false);
+
+ Vector<RD::VertexAttribute> attributes;
+ Vector<RID> buffers;
+ RD::VertexAttribute vd;
+
+ vd.location = 0;
+ vd.stride = sizeof(float) * 3;
+ vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+
+ attributes.push_back(vd);
+ buffers.push_back(frustum.vertex_buffer);
+
+ frustum.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
+ frustum.vertex_array = RD::get_singleton()->vertex_array_create(8, frustum.vertex_format, buffers);
+ }
+
+ if (frustum.index_buffer.is_null()) {
+ uint32_t indices[6 * 2 * 3] = {
+ // Far
+ 0, 1, 2, // FLT, FLB, FRT
+ 1, 3, 2, // FLB, FRB, FRT
+ // Near
+ 4, 6, 5, // NLT, NRT, NLB
+ 6, 7, 5, // NRT, NRB, NLB
+ // Left
+ 0, 4, 1, // FLT, NLT, FLB
+ 4, 5, 1, // NLT, NLB, FLB
+ // Right
+ 6, 2, 7, // NRT, FRT, NRB
+ 2, 3, 7, // FRT, FRB, NRB
+ // Top
+ 0, 2, 4, // FLT, FRT, NLT
+ 2, 6, 4, // FRT, NRT, NLT
+ // Bottom
+ 5, 7, 1, // NLB, NRB, FLB,
+ 7, 3, 1, // NRB, FRB, FLB
+ };
+
+ // Create our index_array
+ PackedByteArray data;
+ data.resize(6 * 2 * 3 * 4);
+ {
+ uint8_t *w = data.ptrw();
+ int *p32 = (int *)w;
+ for (int i = 0; i < 6 * 2 * 3; i++) {
+ *p32 = indices[i];
+ p32++;
+ }
+ }
+
+ frustum.index_buffer = RD::get_singleton()->index_buffer_create(6 * 2 * 3, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, data);
+ frustum.index_array = RD::get_singleton()->index_array_create(frustum.index_buffer, 0, 6 * 2 * 3);
+ }
+
+ if (frustum.lines_buffer.is_null()) {
+ uint32_t indices[12 * 2] = {
+ 0, 1, // FLT - FLB
+ 1, 3, // FLB - FRB
+ 3, 2, // FRB - FRT
+ 2, 0, // FRT - FLT
+
+ 4, 6, // NLT - NRT
+ 6, 7, // NRT - NRB
+ 7, 5, // NRB - NLB
+ 5, 4, // NLB - NLT
+
+ 0, 4, // FLT - NLT
+ 1, 5, // FLB - NLB
+ 2, 6, // FRT - NRT
+ 3, 7, // FRB - NRB
+ };
+
+ // Create our lines_array
+ PackedByteArray data;
+ data.resize(12 * 2 * 4);
+ {
+ uint8_t *w = data.ptrw();
+ int *p32 = (int *)w;
+ for (int i = 0; i < 12 * 2; i++) {
+ *p32 = indices[i];
+ p32++;
+ }
+ }
+
+ frustum.lines_buffer = RD::get_singleton()->index_buffer_create(12 * 2, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, data);
+ frustum.lines_array = RD::get_singleton()->index_array_create(frustum.lines_buffer, 0, 12 * 2);
+ }
+}
+
+DebugEffects::~DebugEffects() {
+ shadow_frustum.shader.version_free(shadow_frustum.shader_version);
+
+ // Destroy vertex buffer and array.
+ if (frustum.vertex_buffer.is_valid()) {
+ RD::get_singleton()->free(frustum.vertex_buffer); // Array gets freed as dependency.
+ }
+
+ // Destroy index buffer and array,
+ if (frustum.index_buffer.is_valid()) {
+ RD::get_singleton()->free(frustum.index_buffer); // Array gets freed as dependency.
+ }
+
+ // Destroy lines buffer and array.
+ if (frustum.lines_buffer.is_valid()) {
+ RD::get_singleton()->free(frustum.lines_buffer); // Array gets freed as dependency.
+ }
+}
+
+void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
+ RID base = light_storage->light_instance_get_base_light(p_light);
+ ERR_FAIL_COND(light_storage->light_get_type(base) != RS::LIGHT_DIRECTIONAL);
+
+ // Make sure our buffers and arrays exist.
+ _create_frustum_arrays();
+
+ // Setup a points buffer for our view frustum.
+ PackedByteArray points;
+ points.resize(8 * sizeof(float) * 3);
+
+ // Get info about our splits.
+ RS::LightDirectionalShadowMode shadow_mode = light_storage->light_directional_get_shadow_mode(base);
+ bool overlap = light_storage->light_directional_get_blend_splits(base);
+ int splits = 1;
+ if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+ splits = 4;
+ } else if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+ splits = 2;
+ }
+
+ // Setup our camera info (this is mostly a duplicate of the logic found in RendererSceneCull::_light_instance_setup_directional_shadow).
+ bool is_orthogonal = p_cam_projection.is_orthogonal();
+ real_t aspect = p_cam_projection.get_aspect();
+ real_t fov = 0.0;
+ Vector2 vp_he;
+ if (is_orthogonal) {
+ vp_he = p_cam_projection.get_viewport_half_extents();
+ } else {
+ fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it
+ }
+ real_t min_distance = p_cam_projection.get_z_near();
+ real_t max_distance = p_cam_projection.get_z_far();
+ real_t shadow_max = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE);
+ if (shadow_max > 0 && !is_orthogonal) {
+ max_distance = MIN(shadow_max, max_distance);
+ }
+
+ // Make sure we've not got bad info coming in.
+ max_distance = MAX(max_distance, min_distance + 0.001);
+ min_distance = MIN(min_distance, max_distance);
+ real_t range = max_distance - min_distance;
+
+ real_t distances[5];
+ distances[0] = min_distance;
+ for (int i = 0; i < splits; i++) {
+ distances[i + 1] = min_distance + RSG::light_storage->light_get_param(base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range;
+ };
+ distances[splits] = max_distance;
+
+ Color colors[4] = {
+ Color(1.0, 0.0, 0.0, 0.1),
+ Color(0.0, 1.0, 0.0, 0.1),
+ Color(0.0, 0.0, 1.0, 0.1),
+ Color(1.0, 1.0, 0.0, 0.1),
+ };
+
+ for (int split = 0; split < splits; split++) {
+ // Load frustum points into vertex buffer.
+ uint8_t *w = points.ptrw();
+ Vector3 *vw = (Vector3 *)w;
+
+ Projection projection;
+
+ if (is_orthogonal) {
+ projection.set_orthogonal(vp_he.y * 2.0, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], false);
+ } else {
+ projection.set_perspective(fov, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], true);
+ }
+
+ bool res = projection.get_endpoints(p_cam_transform, vw);
+ ERR_CONTINUE(!res);
+
+ RD::get_singleton()->buffer_update(frustum.vertex_buffer, 0, 8 * sizeof(float) * 3, w);
+
+ // Get our light projection info.
+ Projection light_projection = light_storage->light_instance_get_shadow_camera(p_light, split);
+ Transform3D light_transform = light_storage->light_instance_get_shadow_transform(p_light, split);
+ Rect2 atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, split);
+
+ if (!is_orthogonal) {
+ light_transform.orthogonalize();
+ }
+
+ // Setup our push constant.
+ ShadowFrustumPushConstant push_constant;
+ MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp);
+ push_constant.color[0] = colors[split].r;
+ push_constant.color[1] = colors[split].g;
+ push_constant.color[2] = colors[split].b;
+ push_constant.color[3] = colors[split].a;
+
+ // Adjust our rect to our atlas position.
+ Rect2 rect = p_rect;
+ rect.position.x += atlas_rect_norm.position.x * rect.size.x;
+ rect.position.y += atlas_rect_norm.position.y * rect.size.y;
+ rect.size.x *= atlas_rect_norm.size.x;
+ rect.size.y *= atlas_rect_norm.size.y;
+
+ // And draw our frustum.
+ RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb);
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
+
+ RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
+ RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+
+ pipeline = shadow_frustum.pipelines[SFP_WIREFRAME].get_render_pipeline(frustum.vertex_format, fb_format_id);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
+ RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.lines_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+
+ RD::get_singleton()->draw_list_end();
+
+ if (split < (splits - 1) && splits > 1) {
+ // Also draw it in the last split so we get a proper overview of the whole view frustum...
+
+ // Get our light projection info.
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, (splits - 1));
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, (splits - 1));
+ atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, (splits - 1));
+
+ if (!is_orthogonal) {
+ light_transform.orthogonalize();
+ }
+
+ // Update our push constant.
+ MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp);
+ push_constant.color[0] = colors[split].r;
+ push_constant.color[1] = colors[split].g;
+ push_constant.color[2] = colors[split].b;
+ push_constant.color[3] = colors[split].a;
+
+ // Adjust our rect to our atlas position.
+ rect = p_rect;
+ rect.position.x += atlas_rect_norm.position.x * rect.size.x;
+ rect.position.y += atlas_rect_norm.position.y * rect.size.y;
+ rect.size.x *= atlas_rect_norm.size.x;
+ rect.size.y *= atlas_rect_norm.size.y;
+
+ draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
+
+ pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
+ RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+
+ RD::get_singleton()->draw_list_end();
+ }
+ }
+}
diff --git a/servers/rendering/renderer_rd/effects/debug_effects.h b/servers/rendering/renderer_rd/effects/debug_effects.h
new file mode 100644
index 0000000000..21b7b03f84
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/debug_effects.h
@@ -0,0 +1,85 @@
+/**************************************************************************/
+/* debug_effects.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 DEBUG_EFFECTS_RD_H
+#define DEBUG_EFFECTS_RD_H
+
+#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl.gen.h"
+#include "servers/rendering/renderer_scene_render.h"
+
+#include "servers/rendering_server.h"
+
+namespace RendererRD {
+
+class DebugEffects {
+private:
+ struct {
+ RD::VertexFormatID vertex_format;
+ RID vertex_buffer;
+ RID vertex_array;
+
+ RID index_buffer;
+ RID index_array;
+
+ RID lines_buffer;
+ RID lines_array;
+ } frustum;
+
+ struct ShadowFrustumPushConstant {
+ float mvp[16];
+ float color[4];
+ };
+
+ enum ShadowFrustumPipelines {
+ SFP_TRANSPARENT,
+ SFP_WIREFRAME,
+ SFP_MAX
+ };
+
+ struct {
+ ShadowFrustumShaderRD shader;
+ RID shader_version;
+ PipelineCacheRD pipelines[SFP_MAX];
+ } shadow_frustum;
+
+ void _create_frustum_arrays();
+
+protected:
+public:
+ DebugEffects();
+ ~DebugEffects();
+
+ void draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect);
+};
+
+} // namespace RendererRD
+
+#endif // DEBUG_EFFECTS_RD_H
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp
index 96e3683560..b9346c0201 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp
@@ -77,10 +77,9 @@ SSEffects::SSEffects() {
for (int pass = 0; pass < 4; pass++) {
for (int subPass = 0; subPass < sub_pass_count; subPass++) {
int a = pass;
- int b = subPass;
int spmap[5]{ 0, 1, 4, 3, 2 };
- b = spmap[subPass];
+ int b = spmap[subPass];
float ca, sa;
float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f;
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 98ec3d6cc3..98d826b1f9 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -190,10 +190,11 @@ void Fog::init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_lay
MaterialStorage *material_storage = MaterialStorage::get_singleton();
{
+ String defines = "#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
// Initialize local fog shader
Vector<String> volumetric_fog_modes;
volumetric_fog_modes.push_back("");
- volumetric_fog.shader.initialize(volumetric_fog_modes);
+ volumetric_fog.shader.initialize(volumetric_fog_modes, defines);
material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_FOG, _create_fog_shader_funcs);
material_storage->material_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_FOG, _create_fog_material_funcs);
@@ -221,7 +222,6 @@ void Fog::init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_lay
actions.usage_defines["ALBEDO"] = "#define ALBEDO_USED\n";
actions.usage_defines["EMISSION"] = "#define EMISSION_USED\n";
- actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = VolumetricFogShader::FogSet::FOG_SET_MATERIAL;
actions.base_uniform_string = "material.";
@@ -257,27 +257,6 @@ ALBEDO = vec3(1.0);
Vector<RD::Uniform> uniforms;
{
- Vector<RID> ids;
- ids.resize(12);
- RID *ids_ptr = ids.ptrw();
- ids_ptr[0] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
-
- RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 1, ids);
- uniforms.push_back(u);
- }
-
- {
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
@@ -285,8 +264,11 @@ ALBEDO = vec3(1.0);
uniforms.push_back(u);
}
+ uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+
volumetric_fog.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_BASE);
}
+
{
String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(p_max_directional_lights) + "\n";
defines += "\n#define MAX_SKY_LOD " + itos(p_roughness_layers - 1) + ".0\n";
diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h
index 8a7c5c0082..206d7852a7 100644
--- a/servers/rendering/renderer_rd/environment/fog.h
+++ b/servers/rendering/renderer_rd/environment/fog.h
@@ -70,6 +70,8 @@ private:
mutable RID_Owner<FogVolumeInstance> fog_volume_instance_owner;
+ const int SAMPLERS_BINDING_FIRST_INDEX = 3;
+
/* Volumetric Fog */
struct VolumetricFogShader {
enum FogSet {
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index d7eb0287d8..ebf3c5f619 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -236,16 +236,16 @@ void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineC
// Update uniform sets.
{
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, SKY_SET_UNIFORMS);
if (p_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) { // Material may not have a uniform set.
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, SKY_SET_MATERIAL);
}
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, SKY_SET_TEXTURES);
// Fog uniform set can be invalidated before drawing, so validate at draw time
if (sky_scene_state.fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_uniform_set)) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, SKY_SET_FOG);
} else {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.default_fog_uniform_set, 3);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.default_fog_uniform_set, SKY_SET_FOG);
}
}
@@ -738,6 +738,7 @@ void SkyRD::init() {
sky_scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_scene_state.max_directional_lights) + "\n";
+ defines += "\n#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
// Initialize sky
Vector<String> sky_modes;
@@ -806,13 +807,12 @@ void SkyRD::init() {
actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS";
actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS";
actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS";
- actions.custom_samplers["RADIANCE"] = "material_samplers[3]";
+ actions.custom_samplers["RADIANCE"] = "SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP";
actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
actions.render_mode_defines["use_debanding"] = "#define USE_DEBANDING\n";
- actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = 1;
actions.base_uniform_string = "material.";
@@ -853,28 +853,6 @@ void sky() {
Vector<RD::Uniform> uniforms;
{
- Vector<RID> ids;
- ids.resize(12);
- RID *ids_ptr = ids.ptrw();
- ids_ptr[0] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
-
- RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 0, ids);
-
- uniforms.push_back(u);
- }
-
- {
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
@@ -898,6 +876,8 @@ void sky() {
uniforms.push_back(u);
}
+ uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+
sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS);
}
@@ -1041,25 +1021,27 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
material = nullptr;
}
}
+ }
- if (!material) {
- sky_material = sky_shader.default_material;
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
- }
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
+ }
- ERR_FAIL_COND(!material);
+ ERR_FAIL_COND(!material);
- shader_data = material->shader_data;
+ shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_COND(!shader_data);
- material->set_as_used();
+ material->set_as_used();
- // Save our screen size, our buffers will already have been cleared
+ if (sky) {
+ // Save our screen size; our buffers will already have been cleared.
sky->screen_size.x = p_screen_size.x < 4 ? 4 : p_screen_size.x;
sky->screen_size.y = p_screen_size.y < 4 ? 4 : p_screen_size.y;
- // Trigger updating radiance buffers
+ // Trigger updating radiance buffers.
if (sky->radiance.is_null()) {
invalidate_sky(sky);
update_dirty_skys();
@@ -1085,107 +1067,109 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
sky->prev_position = p_cam_transform.origin;
sky->reflection.dirty = true;
}
+ }
+
+ sky_scene_state.ubo.directional_light_count = 0;
+ if (shader_data->uses_light) {
+ // Run through the list of lights in the scene and pick out the Directional Lights.
+ // This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called
+ // after the depth prepass, but this runs before the depth prepass.
+ for (int i = 0; i < (int)p_lights.size(); i++) {
+ if (!light_storage->owns_light_instance(p_lights[i])) {
+ continue;
+ }
+ RID base = light_storage->light_instance_get_base_light(p_lights[i]);
+
+ ERR_CONTINUE(base.is_null());
+
+ RS::LightType type = light_storage->light_get_type(base);
+ if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) {
+ SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.ubo.directional_light_count];
+ Transform3D light_transform = light_storage->light_instance_get_base_transform(p_lights[i]);
+ Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
+
+ sky_light_data.direction[0] = world_direction.x;
+ sky_light_data.direction[1] = world_direction.y;
+ sky_light_data.direction[2] = world_direction.z;
+
+ float sign = light_storage->light_is_negative(base) ? -1 : 1;
+ sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
- sky_scene_state.ubo.directional_light_count = 0;
- if (shader_data->uses_light) {
- // Run through the list of lights in the scene and pick out the Directional Lights.
- // This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called
- // after the depth prepass, but this runs before the depth prepass
- for (int i = 0; i < (int)p_lights.size(); i++) {
- if (!light_storage->owns_light_instance(p_lights[i])) {
- continue;
+ if (p_scene_render->is_using_physical_light_units()) {
+ sky_light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
}
- RID base = light_storage->light_instance_get_base_light(p_lights[i]);
-
- ERR_CONTINUE(base.is_null());
-
- RS::LightType type = light_storage->light_get_type(base);
- if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) {
- SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.ubo.directional_light_count];
- Transform3D light_transform = light_storage->light_instance_get_base_transform(p_lights[i]);
- Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
-
- sky_light_data.direction[0] = world_direction.x;
- sky_light_data.direction[1] = world_direction.y;
- sky_light_data.direction[2] = world_direction.z;
-
- float sign = light_storage->light_is_negative(base) ? -1 : 1;
- sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
-
- if (p_scene_render->is_using_physical_light_units()) {
- sky_light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
- }
-
- if (p_camera_attributes.is_valid()) {
- sky_light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes);
- }
-
- Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
- sky_light_data.color[0] = linear_col.r;
- sky_light_data.color[1] = linear_col.g;
- sky_light_data.color[2] = linear_col.b;
-
- sky_light_data.enabled = true;
-
- float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
- if (angular_diameter > 0.0) {
- // I know tan(0) is 0, but let's not risk it with numerical precision.
- // technically this will keep expanding until reaching the sun, but all we care
- // is expand until we reach the radius of the near plane (there can't be more occluders than that)
- angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter));
- } else {
- angular_diameter = 0.0;
- }
- sky_light_data.size = angular_diameter;
- sky_scene_state.ubo.directional_light_count++;
- if (sky_scene_state.ubo.directional_light_count >= sky_scene_state.max_directional_lights) {
- break;
- }
+
+ if (p_camera_attributes.is_valid()) {
+ sky_light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes);
}
- }
- // Check whether the directional_light_buffer changes
- bool light_data_dirty = false;
-
- // Light buffer is dirty if we have fewer or more lights
- // If we have fewer lights, make sure that old lights are disabled
- if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
- light_data_dirty = true;
- for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
- sky_scene_state.directional_lights[i].enabled = false;
- sky_scene_state.last_frame_directional_lights[i].enabled = false;
+
+ Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
+ sky_light_data.color[0] = linear_col.r;
+ sky_light_data.color[1] = linear_col.g;
+ sky_light_data.color[2] = linear_col.b;
+
+ sky_light_data.enabled = true;
+
+ float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ if (angular_diameter > 0.0) {
+ // I know tan(0) is 0, but let's not risk it with numerical precision.
+ // Technically this will keep expanding until reaching the sun, but all we care about
+ // is expanding until we reach the radius of the near plane. There can't be more occluders than that.
+ angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter));
+ } else {
+ angular_diameter = 0.0;
+ }
+ sky_light_data.size = angular_diameter;
+ sky_scene_state.ubo.directional_light_count++;
+ if (sky_scene_state.ubo.directional_light_count >= sky_scene_state.max_directional_lights) {
+ break;
}
}
+ }
+ // Check whether the directional_light_buffer changes.
+ bool light_data_dirty = false;
+
+ // Light buffer is dirty if we have fewer or more lights.
+ // If we have fewer lights, make sure that old lights are disabled.
+ if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
+ light_data_dirty = true;
+ for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
+ sky_scene_state.directional_lights[i].enabled = false;
+ sky_scene_state.last_frame_directional_lights[i].enabled = false;
+ }
+ }
- if (!light_data_dirty) {
- for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) {
- if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
- sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
- sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
- sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
- sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
- sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
- sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
- sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
- sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
- light_data_dirty = true;
- break;
- }
+ if (!light_data_dirty) {
+ for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) {
+ if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
+ sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
+ sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
+ sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
+ sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
+ sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
+ sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
+ sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
+ sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
+ light_data_dirty = true;
+ break;
}
}
+ }
- if (light_data_dirty) {
- RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights);
+ if (light_data_dirty) {
+ RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights);
- SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
- sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
- sky_scene_state.directional_lights = temp;
- sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count;
+ SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
+ sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
+ sky_scene_state.directional_lights = temp;
+ sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count;
+ if (sky) {
sky->reflection.dirty = true;
}
}
}
- //setup fog variables
+ // Setup fog variables.
sky_scene_state.ubo.volumetric_fog_enabled = false;
if (p_render_buffers.is_valid()) {
if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
@@ -1199,7 +1183,7 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
}
- float fog_detail_spread = fog->spread; //reverse lookup
+ float fog_detail_spread = fog->spread; // Reverse lookup.
if (fog_detail_spread > 0.0) {
sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
} else {
@@ -1212,9 +1196,9 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
sky_scene_state.view_count = p_view_count;
sky_scene_state.cam_transform = p_cam_transform;
- sky_scene_state.cam_projection = p_cam_projection; // We only use this when rendering a single view
+ sky_scene_state.cam_projection = p_cam_projection; // We only use this when rendering a single view.
- // Our info in our UBO is only used if we're rendering stereo
+ // Our info in our UBO is only used if we're rendering stereo.
for (uint32_t i = 0; i < p_view_count; i++) {
Projection view_inv_projection = p_view_projections[i].inverse();
if (p_view_count > 1) {
@@ -1231,7 +1215,7 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
sky_scene_state.ubo.view_eye_offsets[i][3] = 0.0;
}
- sky_scene_state.ubo.z_far = p_view_projections[0].get_z_far(); // Should be the same for all projection
+ sky_scene_state.ubo.z_far = p_view_projections[0].get_z_far(); // Should be the same for all projection.
sky_scene_state.ubo.fog_enabled = RendererSceneRenderRD::get_singleton()->environment_get_fog_enabled(p_env);
sky_scene_state.ubo.fog_density = RendererSceneRenderRD::get_singleton()->environment_get_fog_density(p_env);
sky_scene_state.ubo.fog_aerial_perspective = RendererSceneRenderRD::get_singleton()->environment_get_fog_aerial_perspective(p_env);
diff --git a/servers/rendering/renderer_rd/environment/sky.h b/servers/rendering/renderer_rd/environment/sky.h
index afc6274886..7aee65fd67 100644
--- a/servers/rendering/renderer_rd/environment/sky.h
+++ b/servers/rendering/renderer_rd/environment/sky.h
@@ -53,9 +53,10 @@ public:
SKY_SET_MATERIAL,
SKY_SET_TEXTURES,
SKY_SET_FOG,
- SKY_SET_MAX
};
+ const int SAMPLERS_BINDING_FIRST_INDEX = 4;
+
// Skys need less info from Directional Lights than the normal shaders
struct SkyDirectionalLightData {
float direction[3];
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 069b43203f..ef09552603 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -59,7 +59,7 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular()
if (render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
- render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR_MSAA, format, usage_bits, texture_samples);
+ render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR_MSAA, format, usage_bits, render_buffers->get_texture_samples());
}
}
}
@@ -81,7 +81,7 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_normal_rou
if (render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS_MSAA, format, usage_bits, texture_samples);
+ render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS_MSAA, format, usage_bits, render_buffers->get_texture_samples());
}
}
}
@@ -100,7 +100,7 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_voxelgi()
if (render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI_MSAA, format, usage_bits, texture_samples);
+ render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI_MSAA, format, usage_bits, render_buffers->get_texture_samples());
}
}
}
@@ -134,29 +134,6 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RenderS
render_buffers = p_render_buffers;
ERR_FAIL_NULL(render_buffers);
- RS::ViewportMSAA msaa_3d = render_buffers->get_msaa_3d();
-
- if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
- RD::DataFormat format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
-
- const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
- RD::TEXTURE_SAMPLES_1,
- RD::TEXTURE_SAMPLES_2,
- RD::TEXTURE_SAMPLES_4,
- RD::TEXTURE_SAMPLES_8,
- };
-
- texture_samples = ts[msaa_3d];
-
- p_render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples);
-
- format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
- usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
-
- p_render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
- }
-
if (cluster_builder == nullptr) {
cluster_builder = memnew(ClusterBuilderRD);
}
@@ -171,8 +148,8 @@ RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_only_fb(
bool use_msaa = render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED;
- RID color = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA) : render_buffers->get_internal_texture();
- RID depth = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA) : render_buffers->get_depth_texture();
+ RID color = use_msaa ? render_buffers->get_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA) : render_buffers->get_internal_texture();
+ RID depth = use_msaa ? render_buffers->get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA) : render_buffers->get_depth_texture();
if (render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE)) {
RID vrs_texture = render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
@@ -188,7 +165,7 @@ RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_pass_fb(
bool use_msaa = render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED;
int v_count = (p_color_pass_flags & COLOR_PASS_FLAG_MULTIVIEW) ? render_buffers->get_view_count() : 1;
- RID color = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA) : render_buffers->get_internal_texture();
+ RID color = use_msaa ? render_buffers->get_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA) : render_buffers->get_internal_texture();
RID specular;
if (p_color_pass_flags & COLOR_PASS_FLAG_SEPARATE_SPECULAR) {
@@ -202,7 +179,7 @@ RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_pass_fb(
velocity_buffer = render_buffers->get_velocity_buffer(use_msaa);
}
- RID depth = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA) : render_buffers->get_depth_texture();
+ RID depth = use_msaa ? render_buffers->get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA) : render_buffers->get_depth_texture();
if (render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE)) {
RID vrs_texture = render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
@@ -217,7 +194,7 @@ RID RenderForwardClustered::RenderBufferDataForwardClustered::get_depth_fb(Depth
ERR_FAIL_NULL_V(render_buffers, RID());
bool use_msaa = render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED;
- RID depth = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA) : render_buffers->get_depth_texture();
+ RID depth = use_msaa ? render_buffers->get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA) : render_buffers->get_depth_texture();
switch (p_type) {
case DEPTH_FB: {
@@ -944,25 +921,27 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
// LOD
if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
- // Get the LOD support points on the mesh AABB.
- Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
- Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
-
- // Get the distances to those points on the AABB from the camera origin.
- float distance_min = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_min);
- float distance_max = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_max);
-
float distance = 0.0;
- if (distance_min * distance_max < 0.0) {
- //crossing plane
- distance = 0.0;
- } else if (distance_min >= 0.0) {
- distance = distance_min;
- } else if (distance_max <= 0.0) {
- distance = -distance_max;
+ // Check if camera is NOT inside the mesh AABB.
+ if (!inst->transformed_aabb.has_point(p_render_data->scene_data->cam_transform.origin)) {
+ // Get the LOD support points on the mesh AABB.
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
+
+ // Get the distances to those points on the AABB from the camera origin.
+ float distance_min = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_min);
+ float distance_max = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_max);
+
+ if (distance_min * distance_max < 0.0) {
+ //crossing plane
+ distance = 0.0;
+ } else if (distance_min >= 0.0) {
+ distance = distance_min;
+ } else if (distance_max <= 0.0) {
+ distance = -distance_max;
+ }
}
-
if (p_render_data->scene_data->cam_orthogonal) {
distance = 1.0;
}
@@ -1876,11 +1855,11 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE);
}
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
- resolve_effects->resolve_gi(rb_data->get_depth_msaa(v), rb_data->get_normal_roughness_msaa(v), using_voxelgi ? rb_data->get_voxelgi_msaa(v) : RID(), rb->get_depth_texture(v), rb_data->get_normal_roughness(v), using_voxelgi ? rb_data->get_voxelgi(v) : RID(), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
+ resolve_effects->resolve_gi(rb->get_depth_msaa(v), rb_data->get_normal_roughness_msaa(v), using_voxelgi ? rb_data->get_voxelgi_msaa(v) : RID(), rb->get_depth_texture(v), rb_data->get_normal_roughness(v), using_voxelgi ? rb_data->get_voxelgi(v) : RID(), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
}
} else if (finish_depth) {
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
- resolve_effects->resolve_depth(rb_data->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
+ resolve_effects->resolve_depth(rb->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
}
}
RD::get_singleton()->draw_command_end_label();
@@ -1988,7 +1967,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (!can_continue_color) {
// Handle views individual, might want to look at rewriting our resolve to do both layers in one pass.
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
- RD::get_singleton()->texture_resolve_multisample(rb_data->get_color_msaa(v), rb->get_internal_texture(v));
+ RD::get_singleton()->texture_resolve_multisample(rb->get_color_msaa(v), rb->get_internal_texture(v));
}
if (using_separate_specular) {
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
@@ -1999,7 +1978,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (!can_continue_depth) {
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
- resolve_effects->resolve_depth(rb_data->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
+ resolve_effects->resolve_depth(rb->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
}
}
}
@@ -2028,6 +2007,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
}
+ if (using_separate_specular && is_environment(p_render_data->environment) && (environment_get_background(p_render_data->environment) == RS::ENV_BG_CANVAS)) {
+ // Canvas background mode does not clear the color buffer, but copies over it. If screen-space specular effects are enabled and the background is blank,
+ // this results in ghosting due to the separate specular buffer copy. Need to explicitly clear the specular buffer once we're done with it to fix it.
+ RENDER_TIMESTAMP("Clear Separate Specular (Canvas Background Mode)");
+ Vector<Color> blank_clear_color;
+ blank_clear_color.push_back(Color(0.0, 0.0, 0.0));
+ RD::get_singleton()->draw_list_begin(rb_data->get_specular_only_fb(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, blank_clear_color);
+ RD::get_singleton()->draw_list_end();
+ }
+
if (scene_state.used_screen_texture) {
RENDER_TIMESTAMP("Copy Screen Texture");
@@ -2065,8 +2054,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (rb_data.is_valid() && rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
- RD::get_singleton()->texture_resolve_multisample(rb_data->get_color_msaa(v), rb->get_internal_texture(v));
- resolve_effects->resolve_depth(rb_data->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
+ RD::get_singleton()->texture_resolve_multisample(rb->get_color_msaa(v), rb->get_internal_texture(v));
+ resolve_effects->resolve_depth(rb->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
}
if (taa && rb->get_use_taa()) {
taa->msaa_resolve(rb);
@@ -2096,7 +2085,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
if (rb_data.is_valid()) {
- _render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex);
+ _render_buffers_debug_draw(p_render_data);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb->has_custom_data(RB_SCOPE_SDFGI)) {
Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
@@ -2114,34 +2103,36 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
}
-void RenderForwardClustered::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
+void RenderForwardClustered::_render_buffers_debug_draw(const RenderDataRD *p_render_data) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- ERR_FAIL_COND(p_render_buffers.is_null());
- Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ ERR_FAIL_COND(rb.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
ERR_FAIL_COND(rb_data.is_null());
- RendererSceneRenderRD::_render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occlusion_buffer);
+ RendererSceneRenderRD::_render_buffers_debug_draw(p_render_data);
- RID render_target = p_render_buffers->get_render_target();
+ RID render_target = rb->get_render_target();
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSAO && p_render_buffers->has_texture(RB_SCOPE_SSAO, RB_FINAL)) {
- RID final = p_render_buffers->get_texture_slice(RB_SCOPE_SSAO, RB_FINAL, 0, 0);
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->has_texture(RB_SCOPE_SSAO, RB_FINAL)) {
+ RID final = rb->get_texture_slice(RB_SCOPE_SSAO, RB_FINAL, 0, 0);
Size2i rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, true);
}
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSIL && p_render_buffers->has_texture(RB_SCOPE_SSIL, RB_FINAL)) {
- RID final = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_FINAL, 0, 0);
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSIL && rb->has_texture(RB_SCOPE_SSIL, RB_FINAL)) {
+ RID final = rb->get_texture_slice(RB_SCOPE_SSIL, RB_FINAL, 0, 0);
Size2i rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
}
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && p_render_buffers->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) {
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) {
Size2i rtsize = texture_storage->render_target_get_size(render_target);
- RID ambient_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT);
- RID reflection_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION);
- copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, p_render_buffers->get_view_count() > 1);
+ RID ambient_texture = rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT);
+ RID reflection_texture = rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION);
+ copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, rb->get_view_count() > 1);
}
}
@@ -2707,28 +2698,6 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
Vector<RD::Uniform> uniforms;
{
- Vector<RID> ids;
- ids.resize(12);
- RID *ids_ptr = ids.ptrw();
- ids_ptr[0] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
-
- RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 1, ids);
-
- uniforms.push_back(u);
- }
-
- {
RD::Uniform u;
u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
@@ -2879,6 +2848,8 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
+ uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+
render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
}
}
@@ -3963,6 +3934,7 @@ RenderForwardClustered::RenderForwardClustered() {
}
{
defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
+ defines += "\n#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
}
#ifdef REAL_T_IS_DOUBLE
{
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 7ab9e67bac..155e8b4d19 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -60,9 +60,11 @@ class RenderForwardClustered : public RendererSceneRenderRD {
SCENE_UNIFORM_SET = 0,
RENDER_PASS_UNIFORM_SET = 1,
TRANSFORMS_UNIFORM_SET = 2,
- MATERIAL_UNIFORM_SET = 3
+ MATERIAL_UNIFORM_SET = 3,
};
+ const int SAMPLERS_BINDING_FIRST_INDEX = 16;
+
enum {
SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 6,
SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 7,
@@ -98,7 +100,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
private:
RenderSceneBuffersRD *render_buffers = nullptr;
- RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1;
public:
ClusterBuilderRD *cluster_builder = nullptr;
@@ -120,12 +121,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID render_sdfgi_uniform_set;
- RID get_color_msaa() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA); }
- RID get_color_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA, p_layer, 0); }
-
- RID get_depth_msaa() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA); }
- RID get_depth_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA, p_layer, 0); }
-
void ensure_specular();
bool has_specular() const { return render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR); }
RID get_specular() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR); }
@@ -618,7 +613,7 @@ protected:
/* Rendering */
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
- virtual void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) override;
+ virtual void _render_buffers_debug_draw(const RenderDataRD *p_render_data) override;
virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index fe4ec70f98..377aab1354 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -701,7 +701,7 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
- actions.render_mode_defines["depth_draw_opaque"] = "#define USE_OPAQUE_PREPASS\n";
+ actions.render_mode_defines["depth_prepass_alpha"] = "#define USE_OPAQUE_PREPASS\n";
bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
@@ -724,7 +724,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
- actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
actions.base_uniform_string = "material.";
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 2c75b05595..6434682fc2 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -136,30 +136,6 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RenderSceneBu
render_buffers = p_render_buffers;
ERR_FAIL_NULL(render_buffers); // Huh? really?
-
- RS::ViewportMSAA msaa_3d = render_buffers->get_msaa_3d();
- if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
- // Create our MSAA textures...
-
- RD::DataFormat format = render_buffers->get_base_data_format();
- uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
-
- const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
- RD::TEXTURE_SAMPLES_1,
- RD::TEXTURE_SAMPLES_2,
- RD::TEXTURE_SAMPLES_4,
- RD::TEXTURE_SAMPLES_8,
- };
-
- texture_samples = ts[msaa_3d];
-
- render_buffers->create_texture(RB_SCOPE_MOBILE, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples);
-
- usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, usage_bits) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
-
- render_buffers->create_texture(RB_SCOPE_MOBILE, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
- }
}
RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(FramebufferConfigType p_config_type) {
@@ -185,8 +161,8 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe
Vector<RID> textures;
int color_buffer_id = 0;
- textures.push_back(use_msaa ? get_color_msaa() : render_buffers->get_internal_texture()); // 0 - color buffer
- textures.push_back(use_msaa ? get_depth_msaa() : render_buffers->get_depth_texture()); // 1 - depth buffer
+ textures.push_back(use_msaa ? render_buffers->get_color_msaa() : render_buffers->get_internal_texture()); // 0 - color buffer
+ textures.push_back(use_msaa ? render_buffers->get_depth_msaa() : render_buffers->get_depth_texture()); // 1 - depth buffer
if (vrs_texture.is_valid()) {
textures.push_back(vrs_texture); // 2 - vrs texture
}
@@ -1083,7 +1059,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_disable_clear_request(p_render_data);
}
- _render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex);
+ _render_buffers_debug_draw(p_render_data);
}
/* these are being called from RendererSceneRenderRD::_pre_opaque_render */
@@ -1245,14 +1221,15 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i
_render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info);
if (finalize_cubemap) {
_render_shadow_process();
- _render_shadow_end();
- //reblit
+ _render_shadow_end(RD::BARRIER_MASK_FRAGMENT);
+
+ // reblit
Rect2 atlas_rect_norm = atlas_rect;
atlas_rect_norm.position /= float(atlas_size);
atlas_rect_norm.size /= float(atlas_size);
- copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false, RD::BARRIER_MASK_NO_BARRIER);
atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
- copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true, RD::BARRIER_MASK_NO_BARRIER);
//restore transform so it can be properly used
light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0);
@@ -1362,7 +1339,7 @@ void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
}
if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) {
- RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, p_barrier);
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_FRAGMENT, p_barrier);
}
RD::get_singleton()->draw_command_end_label();
}
@@ -1559,28 +1536,6 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
Vector<RD::Uniform> uniforms;
{
- Vector<RID> ids;
- ids.resize(12);
- RID *ids_ptr = ids.ptrw();
- ids_ptr[0] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
-
- RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 1, ids);
-
- uniforms.push_back(u);
- }
-
- {
RD::Uniform u;
u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
@@ -1723,6 +1678,8 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
+ uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+
render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
}
}
@@ -2808,6 +2765,7 @@ RenderForwardMobile::RenderForwardMobile() {
}
{
defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
+ defines += "\n#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
}
#ifdef REAL_T_IS_DOUBLE
{
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index 214b39c496..f2913dd185 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -56,9 +56,11 @@ private:
SCENE_UNIFORM_SET = 0,
RENDER_PASS_UNIFORM_SET = 1,
TRANSFORMS_UNIFORM_SET = 2,
- MATERIAL_UNIFORM_SET = 3
+ MATERIAL_UNIFORM_SET = 3,
};
+ const int SAMPLERS_BINDING_FIRST_INDEX = 15;
+
enum {
SPEC_CONSTANT_USING_PROJECTOR = 0,
@@ -118,19 +120,12 @@ private:
FB_CONFIG_MAX
};
- RID get_color_msaa() const { return render_buffers->get_texture(RB_SCOPE_MOBILE, RB_TEX_COLOR_MSAA); }
- RID get_color_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_MOBILE, RB_TEX_COLOR_MSAA, p_layer, 0); }
-
- RID get_depth_msaa() const { return render_buffers->get_texture(RB_SCOPE_MOBILE, RB_TEX_DEPTH_MSAA); }
- RID get_depth_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_MOBILE, RB_TEX_DEPTH_MSAA, p_layer, 0); }
-
RID get_color_fbs(FramebufferConfigType p_config_type);
virtual void free_data() override;
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
private:
RenderSceneBuffersRD *render_buffers = nullptr;
- RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1;
};
virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) override;
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 6603b97963..e4498ac533 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -589,7 +589,7 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
- actions.render_mode_defines["depth_draw_opaque"] = "#define USE_OPAQUE_PREPASS\n";
+ actions.render_mode_defines["depth_prepass_alpha"] = "#define USE_OPAQUE_PREPASS\n";
bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
if (!force_lambert) {
@@ -611,7 +611,6 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
- actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = RenderForwardMobile::MATERIAL_UNIFORM_SET;
actions.base_uniform_string = "material.";
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 72a42265b3..eb33f296d0 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1010,29 +1010,6 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo
}
{
- //needs samplers for the material (uses custom textures) create them
- Vector<RID> ids;
- ids.resize(12);
- RID *ids_ptr = ids.ptrw();
- ids_ptr[0] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
-
- RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 8, ids);
-
- uniforms.push_back(u);
- }
-
- {
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 9;
@@ -1040,6 +1017,8 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo
uniforms.push_back(u);
}
+ uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+
RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, BASE_UNIFORM_SET);
if (p_backbuffer) {
texture_storage->render_target_set_backbuffer_uniform_set(p_to_render_target, uniform_set);
@@ -2302,6 +2281,8 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
global_defines += "#define MAX_LIGHTS " + itos(DEFAULT_MAX_LIGHTS_PER_RENDER) + "\n";
}
+ global_defines += "\n#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
+
state.light_uniforms = memnew_arr(LightUniform, state.max_lights_per_render);
Vector<String> variants;
//non light variants
@@ -2471,7 +2452,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.custom_samplers["TEXTURE"] = "texture_sampler";
actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
actions.custom_samplers["SPECULAR_SHININESS_TEXTURE"] = "texture_sampler";
- actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = MATERIAL_UNIFORM_SET;
actions.base_uniform_string = "material.";
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 7dea4a1a65..1116bed6e4 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -48,6 +48,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
CANVAS_TEXTURE_UNIFORM_SET = 3,
};
+ const int SAMPLERS_BINDING_FIRST_INDEX = 10;
+
enum ShaderVariant {
SHADER_VARIANT_QUAD,
SHADER_VARIANT_NINEPATCH,
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 16bc36f4b8..646bdc5436 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -659,16 +659,18 @@ void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_
texture_storage->render_target_disable_clear_request(p_render_data->render_buffers->get_render_target());
}
-void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
+void RendererSceneRenderRD::_render_buffers_debug_draw(const RenderDataRD *p_render_data) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- ERR_FAIL_COND(p_render_buffers.is_null());
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ ERR_FAIL_COND(rb.is_null());
- RID render_target = p_render_buffers->get_render_target();
+ RID render_target = rb->get_render_target();
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) {
- if (p_shadow_atlas.is_valid()) {
- RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_shadow_atlas);
+ if (p_render_data->shadow_atlas.is_valid()) {
+ RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_render_data->shadow_atlas);
if (shadow_atlas_texture.is_null()) {
shadow_atlas_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
@@ -683,8 +685,27 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD>
if (RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture().is_valid()) {
RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture();
Size2i rtsize = texture_storage->render_target_get_size(render_target);
+ RID dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target);
+
+ // Determine our display size, try and keep square by using the smallest edge.
+ Size2i size = 2 * rtsize / 3;
+ if (size.x < size.y) {
+ size.y = size.x;
+ } else if (size.y < size.x) {
+ size.x = size.y;
+ }
- copy_effects->copy_to_fb_rect(shadow_atlas_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize / 2), false, true);
+ copy_effects->copy_to_fb_rect(shadow_atlas_texture, dest_fb, Rect2i(Vector2(), size), false, true);
+
+ // Visualise our view frustum to show coverage.
+ for (int i = 0; i < p_render_data->render_shadow_count; i++) {
+ RID light = p_render_data->render_shadows[i].light;
+ RID base = light_storage->light_instance_get_base_light(light);
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
+ debug_effects->draw_shadow_frustum(light, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, dest_fb, Rect2(Size2(), size));
+ }
+ }
}
}
@@ -699,7 +720,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD>
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE) {
- RID luminance_texture = luminance->get_current_luminance_buffer(p_render_buffers);
+ RID luminance_texture = luminance->get_current_luminance_buffer(rb);
if (luminance_texture.is_valid()) {
Size2i rtsize = texture_storage->render_target_get_size(render_target);
@@ -707,21 +728,21 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD>
}
}
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) {
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(rb).is_valid()) {
Size2 rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
+ copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
- if (p_occlusion_buffer.is_valid()) {
+ if (p_render_data->occluder_debug_tex.is_valid()) {
Size2i rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(texture_storage->texture_get_rd_texture(p_occlusion_buffer), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize), true, false);
+ copy_effects->copy_to_fb_rect(texture_storage->texture_get_rd_texture(p_render_data->occluder_debug_tex), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize), true, false);
}
}
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS && _render_buffers_get_velocity_texture(p_render_buffers).is_valid()) {
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS && _render_buffers_get_velocity_texture(rb).is_valid()) {
Size2i rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
+ copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
}
}
@@ -1293,6 +1314,7 @@ void RendererSceneRenderRD::init() {
bool can_use_vrs = is_vrs_supported();
bokeh_dof = memnew(RendererRD::BokehDOF(!can_use_storage));
copy_effects = memnew(RendererRD::CopyEffects(!can_use_storage));
+ debug_effects = memnew(RendererRD::DebugEffects);
luminance = memnew(RendererRD::Luminance(!can_use_storage));
tone_mapper = memnew(RendererRD::ToneMapper);
if (can_use_vrs) {
@@ -1314,6 +1336,9 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
if (copy_effects) {
memdelete(copy_effects);
}
+ if (debug_effects) {
+ memdelete(debug_effects);
+ }
if (luminance) {
memdelete(luminance);
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 7c43021eb0..4bce6a172e 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -37,6 +37,7 @@
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/effects/bokeh_dof.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
+#include "servers/rendering/renderer_rd/effects/debug_effects.h"
#include "servers/rendering/renderer_rd/effects/fsr.h"
#include "servers/rendering/renderer_rd/effects/luminance.h"
#include "servers/rendering/renderer_rd/effects/tone_mapper.h"
@@ -106,6 +107,7 @@ protected:
RendererRD::ForwardIDStorage *forward_id_storage = nullptr;
RendererRD::BokehDOF *bokeh_dof = nullptr;
RendererRD::CopyEffects *copy_effects = nullptr;
+ RendererRD::DebugEffects *debug_effects = nullptr;
RendererRD::Luminance *luminance = nullptr;
RendererRD::ToneMapper *tone_mapper = nullptr;
RendererRD::FSR *fsr = nullptr;
@@ -128,7 +130,7 @@ protected:
virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
- virtual void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
+ virtual void _render_buffers_debug_draw(const RenderDataRD *p_render_data);
virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) = 0;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index c85ece6366..eaa84b7614 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -382,7 +382,7 @@ String ShaderRD::_version_get_sha1(Version *p_version) const {
}
static const char *shader_file_header = "GDSC";
-static const uint32_t cache_file_version = 2;
+static const uint32_t cache_file_version = 3;
bool ShaderRD::_load_from_cache(Version *p_version) {
String sha1 = _version_get_sha1(p_version);
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 7deeacf86e..6270450c15 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -237,7 +237,7 @@ vec2 screen_uv_to_sdf(vec2 p_uv) {
float texture_sdf(vec2 p_sdf) {
vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
- float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r;
+ float d = texture(sampler2D(sdf_texture, SAMPLER_LINEAR_CLAMP), uv).r;
d *= SDF_MAX_LENGTH;
return d * canvas_data.tex_to_sdf;
}
@@ -247,8 +247,8 @@ vec2 texture_sdf_normal(vec2 p_sdf) {
const float EPSILON = 0.001;
return normalize(vec2(
- texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(EPSILON, 0.0)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(EPSILON, 0.0)).r,
- texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(0.0, EPSILON)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(0.0, EPSILON)).r));
+ texture(sampler2D(sdf_texture, SAMPLER_LINEAR_CLAMP), uv + vec2(EPSILON, 0.0)).r - texture(sampler2D(sdf_texture, SAMPLER_LINEAR_CLAMP), uv - vec2(EPSILON, 0.0)).r,
+ texture(sampler2D(sdf_texture, SAMPLER_LINEAR_CLAMP), uv + vec2(0.0, EPSILON)).r - texture(sampler2D(sdf_texture, SAMPLER_LINEAR_CLAMP), uv - vec2(0.0, EPSILON)).r));
}
vec2 sdf_to_screen_uv(vec2 p_sdf) {
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index a904f4e0a6..2dd5abb75f 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -30,19 +30,6 @@
#define FLAGS_FLIP_H (1 << 30)
#define FLAGS_FLIP_V (1 << 31)
-#define SAMPLER_NEAREST_CLAMP 0
-#define SAMPLER_LINEAR_CLAMP 1
-#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
-#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
-#define SAMPLER_NEAREST_REPEAT 6
-#define SAMPLER_LINEAR_REPEAT 7
-#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
-#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
-
// Push Constant
layout(push_constant, std430) uniform DrawData {
@@ -140,7 +127,7 @@ layout(set = 0, binding = 5) uniform sampler shadow_sampler;
layout(set = 0, binding = 6) uniform texture2D color_buffer;
layout(set = 0, binding = 7) uniform texture2D sdf_texture;
-layout(set = 0, binding = 8) uniform sampler material_samplers[12];
+#include "samplers_inc.glsl"
layout(set = 0, binding = 9, std430) restrict readonly buffer GlobalShaderUniformData {
vec4 data[];
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index 1626244b0a..1e01d94533 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -263,7 +263,9 @@ void main() {
// Schlick term.
float metallic = texelFetch(source_metallic, ssC << 1, 0).w;
- float f0 = mix(0.04, 0.37, metallic); // The default value of R0 is 0.04 and the maximum value is considered to be Germanium with R0 value of 0.37
+ // F0 is the reflectance of normally incident light (perpendicular to the surface).
+ // Dielectric materials have a widely accepted default value of 0.04. We assume that metals reflect all light, so their F0 is 1.0.
+ float f0 = mix(0.04, 1.0, metallic);
float m = clamp(1.0 - dot(normal, -view_dir), 0.0, 1.0);
float m2 = m * m;
m = m2 * m2 * m; // pow(m,5)
diff --git a/servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl b/servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl
new file mode 100644
index 0000000000..11ec7ec59e
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl
@@ -0,0 +1,41 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+/* clang-format on */
+
+layout(push_constant, std430) uniform Info {
+ mat4 mvp;
+ vec4 color;
+}
+info;
+
+layout(location = 0) in vec3 vertex_attrib;
+
+void main() {
+ vec4 vertex = info.mvp * vec4(vertex_attrib, 1.0);
+ vertex.xyz /= vertex.w;
+ gl_Position = vec4(vertex.xy, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, std430) uniform Info {
+ mat4 mvp;
+ vec4 color;
+}
+info;
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+ frag_color = info.color;
+}
diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
index b38aa0ad75..d605917acc 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
@@ -62,20 +62,7 @@ layout(push_constant, std430) uniform Params {
}
params;
-#define SAMPLER_NEAREST_CLAMP 0
-#define SAMPLER_LINEAR_CLAMP 1
-#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
-#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
-#define SAMPLER_NEAREST_REPEAT 6
-#define SAMPLER_LINEAR_REPEAT 7
-#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
-#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
-
-layout(set = 0, binding = 0) uniform sampler material_samplers[12];
+#include "../samplers_inc.glsl"
layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalShaderUniformData {
vec4 data[];
@@ -177,7 +164,7 @@ vec4 volumetric_fog_process(vec2 screen_uv) {
vec3 fog_pos = vec3(screen_uv, 1.0);
#endif
- return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
+ return texture(sampler3D(volumetric_fog_texture, SAMPLER_LINEAR_CLAMP), fog_pos);
}
vec4 fog_process(vec3 view, vec3 sky_color) {
@@ -231,27 +218,27 @@ void main() {
#ifdef USE_CUBEMAP_PASS
#ifdef USES_HALF_RES_COLOR
- half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) / params.luminance_multiplier;
+ half_res_color = texture(samplerCube(half_res, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_normal) / params.luminance_multiplier;
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) / params.luminance_multiplier;
+ quarter_res_color = texture(samplerCube(quarter_res, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_normal) / params.luminance_multiplier;
#endif
#else
#ifdef USES_HALF_RES_COLOR
#ifdef USE_MULTIVIEW
- half_res_color = textureLod(sampler2DArray(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0) / params.luminance_multiplier;
+ half_res_color = textureLod(sampler2DArray(half_res, SAMPLER_LINEAR_CLAMP), vec3(uv, ViewIndex), 0.0) / params.luminance_multiplier;
#else
- half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) / params.luminance_multiplier;
+ half_res_color = textureLod(sampler2D(half_res, SAMPLER_LINEAR_CLAMP), uv, 0.0) / params.luminance_multiplier;
#endif // USE_MULTIVIEW
#endif // USES_HALF_RES_COLOR
#ifdef USES_QUARTER_RES_COLOR
#ifdef USE_MULTIVIEW
- quarter_res_color = textureLod(sampler2DArray(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0) / params.luminance_multiplier;
+ quarter_res_color = textureLod(sampler2DArray(quarter_res, SAMPLER_LINEAR_CLAMP), vec3(uv, ViewIndex), 0.0) / params.luminance_multiplier;
#else
- quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) / params.luminance_multiplier;
+ quarter_res_color = textureLod(sampler2D(quarter_res, SAMPLER_LINEAR_CLAMP), uv, 0.0) / params.luminance_multiplier;
#endif // USE_MULTIVIEW
#endif // USES_QUARTER_RES_COLOR
diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl
index 8e4f5762fd..6ba1fe2819 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl
@@ -6,19 +6,6 @@
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
-#define SAMPLER_NEAREST_CLAMP 0
-#define SAMPLER_LINEAR_CLAMP 1
-#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
-#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
-#define SAMPLER_NEAREST_REPEAT 6
-#define SAMPLER_LINEAR_REPEAT 7
-#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
-#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
-
#define DENSITY_SCALE 1024.0
#include "../cluster_data_inc.glsl"
@@ -26,7 +13,7 @@ layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
#define M_PI 3.14159265359
-layout(set = 0, binding = 1) uniform sampler material_samplers[12];
+#include "../samplers_inc.glsl"
layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalShaderUniformData {
vec4 data[];
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 b38f0629c0..9214a953aa 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
@@ -661,7 +661,7 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) {
fog_pos.z = pow(fog_pos.z, implementation_data.volumetric_fog_detail_spread);
}
- return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
+ return texture(sampler3D(volumetric_fog_texture, SAMPLER_LINEAR_CLAMP), fog_pos);
}
vec4 fog_process(vec3 vertex) {
@@ -675,10 +675,10 @@ vec4 fog_process(vec3 vertex) {
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
float lod, blend;
blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod);
- sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb;
- sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend);
+ sky_fog_color = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb;
+ sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend);
#else
- sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
+ sky_fog_color = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
fog_color = mix(fog_color, sky_fog_color, scene_data_block.data.fog_aerial_perspective);
}
@@ -875,11 +875,15 @@ void fragment_shader(in SceneData scene_data) {
alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge);
#endif // ALPHA_ANTIALIASING_EDGE_USED
+#ifdef MODE_RENDER_DEPTH
#ifdef USE_OPAQUE_PREPASS
+#ifndef ALPHA_SCISSOR_USED
if (alpha < scene_data.opaque_prepass_threshold) {
discard;
}
+#endif // !ALPHA_SCISSOR_USED
#endif // USE_OPAQUE_PREPASS
+#endif // MODE_RENDER_DEPTH
#endif // !USE_SHADOW_TO_OPACITY
@@ -1124,11 +1128,11 @@ void fragment_shader(in SceneData scene_data) {
float lod, blend;
blend = modf(sqrt(roughness) * MAX_ROUGHNESS_LOD, lod);
- specular_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb;
- specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend);
+ specular_light = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
+ specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
#else
- specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb;
+ specular_light = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light *= scene_data.IBL_exposure_normalization;
@@ -1148,9 +1152,9 @@ void fragment_shader(in SceneData scene_data) {
if (scene_data.use_ambient_cubemap) {
vec3 ambient_dir = scene_data.radiance_inverse_xform * normal;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
- vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
+ vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
#else
- vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
+ vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
cubemap_ambient *= scene_data.IBL_exposure_normalization;
ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
@@ -1181,11 +1185,11 @@ void fragment_shader(in SceneData scene_data) {
float lod, blend;
blend = modf(roughness_lod, lod);
- vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb;
- clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend);
+ vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
+ clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
#else
- vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness_lod).rgb;
+ vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a;
@@ -1231,10 +1235,10 @@ void fragment_shader(in SceneData scene_data) {
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
- vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
- vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
- vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
- vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
+ vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
+ vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
+ 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);
@@ -1253,7 +1257,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], material_samplers[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[idx].exposure_normalization;
}
}
#else
@@ -1373,18 +1377,18 @@ void fragment_shader(in SceneData scene_data) {
vec2 base_coord = screen_uv;
vec2 closest_coord = base_coord;
#ifdef USE_MULTIVIEW
- float closest_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(base_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
+ float closest_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(base_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
#else // USE_MULTIVIEW
- float closest_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord, 0.0).xyz * 2.0 - 1.0);
+ float closest_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), base_coord, 0.0).xyz * 2.0 - 1.0);
#endif // USE_MULTIVIEW
for (int i = 0; i < 4; i++) {
const vec2 neighbors[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1));
vec2 neighbour_coord = base_coord + neighbors[i] * scene_data.screen_pixel_size;
#ifdef USE_MULTIVIEW
- float neighbour_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
+ float neighbour_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
#else // USE_MULTIVIEW
- float neighbour_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord, 0.0).xyz * 2.0 - 1.0);
+ float neighbour_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), neighbour_coord, 0.0).xyz * 2.0 - 1.0);
#endif // USE_MULTIVIEW
if (neighbour_ang > closest_ang) {
closest_ang = neighbour_ang;
@@ -1399,11 +1403,11 @@ void fragment_shader(in SceneData scene_data) {
}
#ifdef USE_MULTIVIEW
- vec4 buffer_ambient = textureLod(sampler2DArray(ambient_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(coord, ViewIndex), 0.0);
- vec4 buffer_reflection = textureLod(sampler2DArray(reflection_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(coord, ViewIndex), 0.0);
+ vec4 buffer_ambient = textureLod(sampler2DArray(ambient_buffer, SAMPLER_LINEAR_CLAMP), vec3(coord, ViewIndex), 0.0);
+ vec4 buffer_reflection = textureLod(sampler2DArray(reflection_buffer, SAMPLER_LINEAR_CLAMP), vec3(coord, ViewIndex), 0.0);
#else // USE_MULTIVIEW
- vec4 buffer_ambient = textureLod(sampler2D(ambient_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0);
- vec4 buffer_reflection = textureLod(sampler2D(reflection_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0);
+ vec4 buffer_ambient = textureLod(sampler2D(ambient_buffer, SAMPLER_LINEAR_CLAMP), coord, 0.0);
+ vec4 buffer_reflection = textureLod(sampler2D(reflection_buffer, SAMPLER_LINEAR_CLAMP), coord, 0.0);
#endif // USE_MULTIVIEW
ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a);
@@ -1413,9 +1417,9 @@ void fragment_shader(in SceneData scene_data) {
if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) {
#ifdef USE_MULTIVIEW
- float ssao = texture(sampler2DArray(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(screen_uv, ViewIndex)).r;
+ float ssao = texture(sampler2DArray(ao_buffer, SAMPLER_LINEAR_CLAMP), vec3(screen_uv, ViewIndex)).r;
#else
- float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
+ float ssao = texture(sampler2D(ao_buffer, SAMPLER_LINEAR_CLAMP), screen_uv).r;
#endif
ao = min(ao, ssao);
ao_light_affect = mix(ao_light_affect, max(ao_light_affect, implementation_data.ssao_light_affect), implementation_data.ssao_ao_affect);
@@ -1500,9 +1504,9 @@ void fragment_shader(in SceneData scene_data) {
if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) {
#ifdef USE_MULTIVIEW
- vec4 ssil = textureLod(sampler2DArray(ssil_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(screen_uv, ViewIndex), 0.0);
+ vec4 ssil = textureLod(sampler2DArray(ssil_buffer, SAMPLER_LINEAR_CLAMP), vec3(screen_uv, ViewIndex), 0.0);
#else
- vec4 ssil = textureLod(sampler2D(ssil_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv, 0.0);
+ vec4 ssil = textureLod(sampler2D(ssil_buffer, SAMPLER_LINEAR_CLAMP), screen_uv, 0.0);
#endif // USE_MULTIVIEW
ambient_light *= 1.0 - ssil.a;
ambient_light += ssil.rgb * albedo.rgb;
@@ -1786,7 +1790,7 @@ void fragment_shader(in SceneData scene_data) {
vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex;
trans_coord /= trans_coord.w;
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
shadow_z *= directional_lights.data[i].shadow_z_range.x;
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x;
@@ -1796,7 +1800,7 @@ void fragment_shader(in SceneData scene_data) {
vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex;
trans_coord /= trans_coord.w;
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
shadow_z *= directional_lights.data[i].shadow_z_range.y;
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y;
@@ -1806,7 +1810,7 @@ void fragment_shader(in SceneData scene_data) {
vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex;
trans_coord /= trans_coord.w;
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
shadow_z *= directional_lights.data[i].shadow_z_range.z;
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z;
@@ -1817,7 +1821,7 @@ void fragment_shader(in SceneData scene_data) {
vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex;
trans_coord /= trans_coord.w;
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
shadow_z *= directional_lights.data[i].shadow_z_range.w;
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w;
@@ -2038,8 +2042,8 @@ void fragment_shader(in SceneData scene_data) {
if (alpha < alpha_scissor) {
discard;
}
-#endif // ALPHA_SCISSOR_USED
-
+#else
+#ifdef MODE_RENDER_DEPTH
#ifdef USE_OPAQUE_PREPASS
if (alpha < scene_data.opaque_prepass_threshold) {
@@ -2047,6 +2051,8 @@ void fragment_shader(in SceneData scene_data) {
}
#endif // USE_OPAQUE_PREPASS
+#endif // MODE_RENDER_DEPTH
+#endif // ALPHA_SCISSOR_USED
#endif // USE_SHADOW_TO_OPACITY
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
index 043bba1e4e..8ead363f3b 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
@@ -42,20 +42,7 @@ draw_call;
#include "../light_data_inc.glsl"
-#define SAMPLER_NEAREST_CLAMP 0
-#define SAMPLER_LINEAR_CLAMP 1
-#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
-#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
-#define SAMPLER_NEAREST_REPEAT 6
-#define SAMPLER_LINEAR_REPEAT 7
-#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
-#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
-
-layout(set = 0, binding = 1) uniform sampler material_samplers[12];
+#include "../samplers_inc.glsl"
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
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 b43138606f..b63eea1401 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
@@ -624,10 +624,10 @@ vec4 fog_process(vec3 vertex) {
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
float lod, blend;
blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod);
- sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb;
- sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend);
+ sky_fog_color = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb;
+ sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend);
#else
- sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
+ sky_fog_color = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
fog_color = mix(fog_color, sky_fog_color, scene_data_block.data.fog_aerial_perspective);
}
@@ -817,11 +817,15 @@ void main() {
alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge);
#endif // ALPHA_ANTIALIASING_EDGE_USED
+#ifdef MODE_RENDER_DEPTH
#ifdef USE_OPAQUE_PREPASS
+#ifndef ALPHA_SCISSOR_USED
if (alpha < scene_data.opaque_prepass_threshold) {
discard;
}
+#endif // !ALPHA_SCISSOR_USED
#endif // USE_OPAQUE_PREPASS
+#endif // MODE_RENDER_DEPTH
#endif // !USE_SHADOW_TO_OPACITY
@@ -1007,11 +1011,11 @@ void main() {
float lod, blend;
blend = modf(sqrt(roughness) * MAX_ROUGHNESS_LOD, lod);
- specular_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb;
- specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend);
+ specular_light = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
+ specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
#else // USE_RADIANCE_CUBEMAP_ARRAY
- specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb;
+ specular_light = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light *= sc_luminance_multiplier;
@@ -1032,9 +1036,9 @@ void main() {
if (scene_data.use_ambient_cubemap) {
vec3 ambient_dir = scene_data.radiance_inverse_xform * normal;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
- vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
+ vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
#else
- vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
+ vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
cubemap_ambient *= sc_luminance_multiplier;
cubemap_ambient *= scene_data.IBL_exposure_normalization;
@@ -1066,11 +1070,11 @@ void main() {
float lod, blend;
blend = modf(roughness_lod, lod);
- vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb;
- clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend);
+ vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
+ clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
#else
- vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness_lod).rgb;
+ vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a;
@@ -1117,10 +1121,10 @@ void main() {
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
- vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
- vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
- vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
- vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
+ vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
+ vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
+ 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;
@@ -1137,7 +1141,7 @@ void main() {
}
} else {
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[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[idx].exposure_normalization;
}
}
@@ -1685,8 +1689,8 @@ void main() {
if (alpha < alpha_scissor) {
discard;
}
-#endif // ALPHA_SCISSOR_USED
-
+#else
+#ifdef MODE_RENDER_DEPTH
#ifdef USE_OPAQUE_PREPASS
if (alpha < scene_data.opaque_prepass_threshold) {
@@ -1694,6 +1698,8 @@ void main() {
}
#endif // USE_OPAQUE_PREPASS
+#endif // MODE_RENDER_DEPTH
+#endif // !ALPHA_SCISSOR_USED
#endif // USE_SHADOW_TO_OPACITY
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
index f16f80c6f6..d0a315858d 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
@@ -36,20 +36,7 @@ draw_call;
#include "../light_data_inc.glsl"
-#define SAMPLER_NEAREST_CLAMP 0
-#define SAMPLER_LINEAR_CLAMP 1
-#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
-#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
-#define SAMPLER_NEAREST_REPEAT 6
-#define SAMPLER_LINEAR_REPEAT 7
-#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
-#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
-
-layout(set = 0, binding = 1) uniform sampler material_samplers[12];
+#include "../samplers_inc.glsl"
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index a609076e2c..7ba03a27f7 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -6,24 +6,11 @@
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
-#define SAMPLER_NEAREST_CLAMP 0
-#define SAMPLER_LINEAR_CLAMP 1
-#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
-#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
-#define SAMPLER_NEAREST_REPEAT 6
-#define SAMPLER_LINEAR_REPEAT 7
-#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
-#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
-#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
-#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
-
#define SDF_MAX_LENGTH 16384.0
/* SET 0: GLOBAL DATA */
-layout(set = 0, binding = 1) uniform sampler material_samplers[12];
+#include "samplers_inc.glsl"
layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalShaderUniformData {
vec4 data[];
@@ -473,7 +460,7 @@ void main() {
if (any(lessThan(uvw_pos, vec3(0.0))) || any(greaterThan(uvw_pos, vec3(1.0)))) {
continue;
}
- vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz * -2.0 + 1.0;
+ vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos).xyz * -2.0 + 1.0;
dir = mat3(FRAME.attractors[i].transform) * safe_normalize(s); //revert direction
amount = length(s);
@@ -509,15 +496,15 @@ void main() {
vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
float sdf_particle_size = distance(sdf_pos, sdf_pos2);
- float d = texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos).r * SDF_MAX_LENGTH;
+ float d = texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos).r * SDF_MAX_LENGTH;
d -= sdf_particle_size;
if (d < 0.0) {
const float EPSILON = 0.001;
vec2 n = normalize(vec2(
- texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(EPSILON, 0.0)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(EPSILON, 0.0)).r,
- texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(0.0, EPSILON)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(0.0, EPSILON)).r));
+ texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos + vec2(EPSILON, 0.0)).r - texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos - vec2(EPSILON, 0.0)).r,
+ texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos + vec2(0.0, EPSILON)).r - texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos - vec2(0.0, EPSILON)).r));
collided = true;
sdf_pos2 = sdf_pos + n * d;
@@ -596,7 +583,7 @@ void main() {
}
vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
- float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r;
+ float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos).r;
s *= FRAME.colliders[i].scale;
s += extra_dist;
if (s < particle_size) {
@@ -606,9 +593,9 @@ void main() {
normal = mat3(FRAME.colliders[i].transform) *
normalize(
vec3(
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
}
} break;
@@ -623,14 +610,14 @@ void main() {
vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
- float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
+ float y = 1.0 - texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uvw_pos.xz).r;
if (y > uvw_pos.y) {
//inside heightfield
vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
normal = normalize(cross(pos1 - pos2, pos1 - pos3));
float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
diff --git a/servers/rendering/renderer_rd/shaders/samplers_inc.glsl b/servers/rendering/renderer_rd/shaders/samplers_inc.glsl
new file mode 100644
index 0000000000..3f6172795e
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/samplers_inc.glsl
@@ -0,0 +1,12 @@
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 0) uniform sampler SAMPLER_NEAREST_CLAMP;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 1) uniform sampler SAMPLER_LINEAR_CLAMP;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 2) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 3) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 4) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 5) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 6) uniform sampler SAMPLER_NEAREST_REPEAT;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 7) uniform sampler SAMPLER_LINEAR_REPEAT;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 8) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 9) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 10) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 11) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT; \ No newline at end of file
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
index ae5e1b7251..8f68030cba 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
@@ -13,7 +13,7 @@ vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction,
if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + half_diameter * cell_size)))) {
break;
}
- vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter));
+ vec4 scolor = textureLod(sampler3D(probe, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), uvw_pos, log2(diameter));
float a = (1.0 - color.a);
color += a * scolor;
dist += half_diameter;
@@ -35,7 +35,7 @@ vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3
if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + radius * cell_size)))) {
break;
}
- vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level);
+ vec4 scolor = textureLod(sampler3D(probe, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), uvw_pos, lod_level);
lod_level += 1.0;
float a = (1.0 - color.a);
@@ -176,7 +176,7 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
}
occ_pos *= sdfgi.occlusion_renormalize;
- float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, material_samplers[SAMPLER_LINEAR_CLAMP]), occ_pos, 0.0), occ_mask);
+ float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, SAMPLER_LINEAR_CLAMP), occ_pos, 0.0), occ_mask);
weight *= max(occlusion, 0.01);
}
@@ -187,7 +187,7 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
vec3 pos_uvw = diffuse_posf;
pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy;
pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
- diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb;
+ diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, SAMPLER_LINEAR_CLAMP), pos_uvw, 0.0).rgb;
diffuse_accum += vec4(diffuse * weight * sdfgi.cascades[cascade].exposure_normalization, weight);
@@ -197,10 +197,10 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy;
pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
if (roughness < 0.99) {
- specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb;
+ specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, SAMPLER_LINEAR_CLAMP), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb;
}
if (roughness > 0.5) {
- specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0);
+ specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, SAMPLER_LINEAR_CLAMP), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0);
}
specular_accum += specular * weight * sdfgi.cascades[cascade].exposure_normalization;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index e159e5628c..ba8d901772 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -374,7 +374,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
for (uint i = 0; i < sc_directional_penumbra_shadow_samples; i++) {
vec2 suv = pssm_coord.xy + (disk_rotation * scene_data_block.data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
- float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
+ float d = textureLod(sampler2D(shadow, SAMPLER_LINEAR_CLAMP), suv, 0.0).r;
if (d < pssm_coord.z) {
blocker_average += d;
blocker_count += 1.0;
@@ -478,7 +478,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
pos.xy = pos.xy * 0.5 + 0.5;
pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
- float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r;
+ float d = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), pos.xy, 0.0).r;
if (d < z_norm) {
blocker_average += d;
blocker_count += 1.0;
@@ -605,7 +605,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
// splane.xy = clamp(splane.xy,clamp_rect.xy + scene_data_block.data.shadow_atlas_pixel_size,clamp_rect.xy + clamp_rect.zw - scene_data_block.data.shadow_atlas_pixel_size );
splane.w = 1.0; //needed? i think it should be 1 already
- float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), splane.xy, 0.0).r;
transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius;
}
#endif
@@ -734,7 +734,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data_block.data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
- float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
+ float d = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), suv, 0.0).r;
if (d < splane.z) {
blocker_average += d;
blocker_count += 1.0;
@@ -838,7 +838,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
splane /= splane.w;
splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
- float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), splane.xy, 0.0).r;
shadow_z = shadow_z * 2.0 - 1.0;
float z_far = 1.0 / spot_lights.data[idx].inv_radius;
@@ -932,7 +932,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 ref_vec, vec3 normal,
vec4 reflection;
- reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb * sc_luminance_multiplier;
+ reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb * sc_luminance_multiplier;
reflection.rgb *= reflections.data[ref_index].exposure_normalization;
if (reflections.data[ref_index].exterior) {
reflection.rgb = mix(specular_light, reflection.rgb, blend);
@@ -955,7 +955,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 ref_vec, vec3 normal,
vec4 ambient_out;
- ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb;
+ ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb;
ambient_out.rgb *= reflections.data[ref_index].exposure_normalization;
ambient_out.a = blend;
if (reflections.data[ref_index].exterior) {
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 8d1eb87e3c..d055f01009 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -2398,6 +2398,26 @@ void MaterialStorage::material_update_dependency(RID p_material, DependencyTrack
}
}
+Vector<RD::Uniform> MaterialStorage::get_default_sampler_uniforms(int first_index) {
+ Vector<RD::Uniform> uniforms;
+
+ // Binding ids are aligned with samplers_inc.glsl.
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 0, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 1, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 2, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 3, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 4, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 5, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 6, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 7, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 8, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 9, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 10, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 11, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
+
+ return uniforms;
+}
+
void MaterialStorage::material_set_data_request_function(ShaderType p_shader_type, MaterialStorage::MaterialDataRequestFunction p_function) {
ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
material_data_request_func[p_shader_type] = p_function;
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h
index ac217d9a49..b6da3df783 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h
@@ -344,6 +344,8 @@ public:
void sampler_rd_configure_custom(float mipmap_bias);
+ Vector<RD::Uniform> get_default_sampler_uniforms(int first_index);
+
// void sampler_rd_set_default(float p_mipmap_bias);
/* Buffers */
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index b36e027f07..8f647be5c9 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -54,10 +54,11 @@ ParticlesStorage::ParticlesStorage() {
/* Particles */
{
+ String defines = "#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
// Initialize particles
Vector<String> particles_modes;
particles_modes.push_back("");
- particles_shader.shader.initialize(particles_modes, String());
+ particles_shader.shader.initialize(particles_modes, defines);
}
MaterialStorage::get_singleton()->shader_set_data_request_function(MaterialStorage::SHADER_TYPE_PARTICLES, _create_particles_shader_funcs);
MaterialStorage::get_singleton()->material_set_data_request_function(MaterialStorage::SHADER_TYPE_PARTICLES, _create_particles_material_funcs);
@@ -109,7 +110,6 @@ ParticlesStorage::ParticlesStorage() {
actions.render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
actions.render_mode_defines["collision_use_scale"] = "#define USE_COLLISION_SCALE\n";
- actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = 3;
actions.base_uniform_string = "material.";
@@ -145,27 +145,6 @@ void process() {
Vector<RD::Uniform> uniforms;
{
- Vector<RID> ids;
- ids.resize(12);
- RID *ids_ptr = ids.ptrw();
- ids_ptr[0] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
-
- RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 1, ids);
- uniforms.push_back(u);
- }
-
- {
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
@@ -173,7 +152,9 @@ void process() {
uniforms.push_back(u);
}
- particles_shader.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 0);
+ uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+
+ particles_shader.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, BASE_UNIFORM_SET);
}
{
@@ -430,7 +411,7 @@ void ParticlesStorage::particles_set_fractional_delta(RID p_particles, bool p_en
void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, double p_length) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_COND(!particles);
- ERR_FAIL_COND(p_length < 0.1);
+ ERR_FAIL_COND(p_length < 0.01);
p_length = MIN(10.0, p_length);
particles->trails_enabled = p_enable;
@@ -1119,9 +1100,9 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
//todo should maybe compute all particle systems together?
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles_shader.base_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->particles_material_uniform_set, 1);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->collision_textures_uniform_set, 2);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles_shader.base_uniform_set, BASE_UNIFORM_SET);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->particles_material_uniform_set, MATERIAL_UNIFORM_SET);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->collision_textures_uniform_set, COLLISION_TEXTURTES_UNIFORM_SET);
if (m->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(m->uniform_set)) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, m->uniform_set, 3);
@@ -1288,7 +1269,10 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
particles->userdata_count = userdata_count;
- particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (xform_size + 1 + 1) * total_amount);
+ PackedByteArray data;
+ data.resize_zeroed(sizeof(float) * 4 * (xform_size + 1 + 1) * total_amount);
+
+ particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (xform_size + 1 + 1) * total_amount, data);
//needs to clear it
{
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index 4f9253144e..612420a36c 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -53,6 +53,14 @@ private:
/* PARTICLES */
+ enum {
+ BASE_UNIFORM_SET,
+ MATERIAL_UNIFORM_SET,
+ COLLISION_TEXTURTES_UNIFORM_SET,
+ };
+
+ const int SAMPLERS_BINDING_FIRST_INDEX = 3;
+
struct ParticleData {
float xform[16];
float velocity[3];
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index 609fb2afe7..71bc21d5d4 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -44,15 +44,28 @@ RenderSceneBuffersRD::~RenderSceneBuffersRD() {
void RenderSceneBuffersRD::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_texture", "context", "name"), &RenderSceneBuffersRD::has_texture);
- // FIXME we can't pass RD::DataFormat, RD::TextureSamples and RD::TextureView in ClassDB, need to solve views differently...
- // ClassDB::bind_method(D_METHOD("create_texture", "context", "name", "data_format", "usage_bits", "texture_samples", "size", "layers", "mipmaps", "unique"), &RenderSceneBuffersRD::create_texture);
- // ClassDB::bind_method(D_METHOD("create_texture_from_format", "context", "name", "format", "view", "unique"), &RenderSceneBuffersRD::create_texture_from_format);
- // ClassDB::bind_method(D_METHOD("create_texture_view", "context", "name", "view_name", "view"), &RenderSceneBuffersRD::has_texture);
+ ClassDB::bind_method(D_METHOD("create_texture", "context", "name", "data_format", "usage_bits", "texture_samples", "size", "layers", "mipmaps", "unique"), &RenderSceneBuffersRD::create_texture);
+ ClassDB::bind_method(D_METHOD("create_texture_from_format", "context", "name", "format", "view", "unique"), &RenderSceneBuffersRD::_create_texture_from_format);
+ ClassDB::bind_method(D_METHOD("create_texture_view", "context", "name", "view_name", "view"), &RenderSceneBuffersRD::_create_texture_view);
ClassDB::bind_method(D_METHOD("get_texture", "context", "name"), &RenderSceneBuffersRD::get_texture);
- // ClassDB::bind_method(D_METHOD("get_texture_format", "context", "name"), &RenderSceneBuffersRD::get_texture_format);
+ ClassDB::bind_method(D_METHOD("get_texture_format", "context", "name"), &RenderSceneBuffersRD::_get_texture_format);
ClassDB::bind_method(D_METHOD("get_texture_slice", "context", "name", "layer", "mipmap", "layers", "mipmaps"), &RenderSceneBuffersRD::get_texture_slice);
ClassDB::bind_method(D_METHOD("get_texture_slice_size", "context", "name", "mipmap"), &RenderSceneBuffersRD::get_texture_slice_size);
ClassDB::bind_method(D_METHOD("clear_context", "context"), &RenderSceneBuffersRD::clear_context);
+
+ // Access to some core buffers so users don't need to know their names.
+ ClassDB::bind_method(D_METHOD("get_color_texture"), &RenderSceneBuffersRD::_get_color_texture);
+ ClassDB::bind_method(D_METHOD("get_color_layer", "layer"), &RenderSceneBuffersRD::_get_color_layer);
+ ClassDB::bind_method(D_METHOD("get_depth_texture"), &RenderSceneBuffersRD::_get_depth_texture);
+ ClassDB::bind_method(D_METHOD("get_depth_layer", "layer"), &RenderSceneBuffersRD::_get_depth_layer);
+ ClassDB::bind_method(D_METHOD("get_velocity_texture"), &RenderSceneBuffersRD::_get_velocity_texture);
+ ClassDB::bind_method(D_METHOD("get_velocity_layer", "layer"), &RenderSceneBuffersRD::_get_velocity_layer);
+
+ // Expose a few properties we're likely to use externally
+ ClassDB::bind_method(D_METHOD("get_render_target"), &RenderSceneBuffersRD::get_render_target);
+ ClassDB::bind_method(D_METHOD("get_view_count"), &RenderSceneBuffersRD::get_view_count);
+ ClassDB::bind_method(D_METHOD("get_internal_size"), &RenderSceneBuffersRD::get_internal_size);
+ ClassDB::bind_method(D_METHOD("get_use_taa"), &RenderSceneBuffersRD::get_use_taa);
}
void RenderSceneBuffersRD::update_sizes(NamedTexture &p_named_texture) {
@@ -90,42 +103,44 @@ void RenderSceneBuffersRD::cleanup() {
named_textures.clear();
}
-void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_config) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
- ERR_FAIL_COND_MSG(p_view_count == 0, "Must have at least 1 view");
+ render_target = p_config->get_render_target();
+ target_size = p_config->get_target_size();
+ internal_size = p_config->get_internal_size();
+ view_count = p_config->get_view_count();
+
+ scaling_3d_mode = p_config->get_scaling_3d_mode();
+ msaa_3d = p_config->get_msaa_3d();
+ screen_space_aa = p_config->get_screen_space_aa();
- target_size = p_target_size;
- internal_size = p_internal_size;
- scaling_3d_mode = p_scaling_3d_mode;
+ fsr_sharpness = p_config->get_fsr_sharpness();
+ texture_mipmap_bias = p_config->get_texture_mipmap_bias();
+ use_taa = p_config->get_use_taa();
+ use_debanding = p_config->get_use_debanding();
- if (p_use_taa) {
+ ERR_FAIL_COND_MSG(view_count == 0, "Must have at least 1 view");
+
+ if (use_taa) {
// Use negative mipmap LOD bias when TAA is enabled to compensate for loss of sharpness.
// This restores sharpness in still images to be roughly at the same level as without TAA,
// but moving scenes will still be blurrier.
- p_texture_mipmap_bias -= 0.5;
+ texture_mipmap_bias -= 0.5;
}
- if (p_screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
+ if (screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
// Use negative mipmap LOD bias when FXAA is enabled to compensate for loss of sharpness.
// If both TAA and FXAA are enabled, combine their negative LOD biases together.
- p_texture_mipmap_bias -= 0.25;
+ texture_mipmap_bias -= 0.25;
}
- material_storage->sampler_rd_configure_custom(p_texture_mipmap_bias);
+ material_storage->sampler_rd_configure_custom(texture_mipmap_bias);
// need to check if we really need to do this here..
RendererSceneRenderRD::get_singleton()->update_uniform_sets();
- render_target = p_render_target;
- fsr_sharpness = p_fsr_sharpness;
- msaa_3d = p_msaa_3d;
- screen_space_aa = p_screen_space_aa;
- use_taa = p_use_taa;
- use_debanding = p_use_debanding;
- view_count = p_view_count;
-
// cleanout any old buffers we had.
cleanup();
@@ -161,9 +176,33 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, format, usage_bits);
}
+ // Create our MSAA buffers
+ if (msaa_3d == RS::VIEWPORT_MSAA_DISABLED) {
+ texture_samples = RD::TEXTURE_SAMPLES_1;
+ } else {
+ RD::DataFormat format = base_data_format;
+ uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
+ RD::TEXTURE_SAMPLES_1,
+ RD::TEXTURE_SAMPLES_2,
+ RD::TEXTURE_SAMPLES_4,
+ RD::TEXTURE_SAMPLES_8,
+ };
+
+ texture_samples = ts[msaa_3d];
+
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples);
+
+ usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, usage_bits) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
+ }
+
// VRS (note, our vrs object will only be set if VRS is supported)
RID vrs_texture;
- RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_target);
+ RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(render_target);
if (vrs && vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
vrs_texture = create_texture(RB_SCOPE_VRS, RB_TEXTURE, RD::DATA_FORMAT_R8_UINT, usage_bits, RD::TEXTURE_SAMPLES_1, vrs->get_vrs_texture_size(internal_size));
@@ -244,6 +283,17 @@ RID RenderSceneBuffersRD::create_texture(const StringName &p_context, const Stri
return create_texture_from_format(p_context, p_texture_name, tf, RD::TextureView(), p_unique);
}
+RID RenderSceneBuffersRD::_create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const Ref<RDTextureFormat> &p_texture_format, const Ref<RDTextureView> &p_view, bool p_unique) {
+ ERR_FAIL_COND_V(p_texture_format.is_null(), RID());
+
+ RD::TextureView texture_view;
+ if (p_view.is_valid()) { // only use when supplied, else default.
+ texture_view = p_view->base;
+ }
+
+ return create_texture_from_format(p_context, p_texture_name, p_texture_format->base, texture_view, p_unique);
+}
+
RID RenderSceneBuffersRD::create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const RD::TextureFormat &p_texture_format, RD::TextureView p_view, bool p_unique) {
// TODO p_unique, if p_unique is true, this is a texture that can be shared. This will be implemented later as an optimization.
@@ -272,6 +322,15 @@ RID RenderSceneBuffersRD::create_texture_from_format(const StringName &p_context
return named_texture.texture;
}
+RID RenderSceneBuffersRD::_create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, const Ref<RDTextureView> p_view) {
+ RD::TextureView texture_view;
+ if (p_view.is_valid()) { // only use when supplied, else default.
+ texture_view = p_view->base;
+ }
+
+ return create_texture_view(p_context, p_texture_name, p_view_name, texture_view);
+}
+
RID RenderSceneBuffersRD::create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, RD::TextureView p_view) {
NTKey view_key(p_context, p_view_name);
@@ -310,6 +369,15 @@ RID RenderSceneBuffersRD::get_texture(const StringName &p_context, const StringN
return named_textures[key].texture;
}
+Ref<RDTextureFormat> RenderSceneBuffersRD::_get_texture_format(const StringName &p_context, const StringName &p_texture_name) const {
+ Ref<RDTextureFormat> tf;
+ tf.instantiate();
+
+ tf->base = get_texture_format(p_context, p_texture_name);
+
+ return tf;
+}
+
const RD::TextureFormat RenderSceneBuffersRD::get_texture_format(const StringName &p_context, const StringName &p_texture_name) const {
NTKey key(p_context, p_texture_name);
@@ -535,15 +603,6 @@ void RenderSceneBuffersRD::ensure_velocity() {
uint32_t msaa_usage_bits = usage_bits | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
- const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
- RD::TEXTURE_SAMPLES_1,
- RD::TEXTURE_SAMPLES_2,
- RD::TEXTURE_SAMPLES_4,
- RD::TEXTURE_SAMPLES_8,
- };
-
- RD::TextureSamples texture_samples = ts[msaa_3d];
-
create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, RD::DATA_FORMAT_R16G16_SFLOAT, msaa_usage_bits, texture_samples);
}
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
index 9a299a3415..85140c674c 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
@@ -36,6 +36,7 @@
#include "core/templates/hash_map.h"
#include "render_buffer_custom_data_rd.h"
#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/rendering_device_binds.h"
#include "servers/rendering/rendering_method.h"
#include "servers/rendering/storage/render_scene_buffers.h"
@@ -75,12 +76,14 @@ private:
Size2i internal_size = Size2i(0, 0);
RS::ViewportScaling3DMode scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
float fsr_sharpness = 0.2f;
+ float texture_mipmap_bias = 0.0f;
// Aliassing settings
RS::ViewportMSAA msaa_3d = RS::VIEWPORT_MSAA_DISABLED;
RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
bool use_taa = false;
bool use_debanding = false;
+ RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1;
// Named Textures
@@ -166,7 +169,7 @@ public:
void set_vrs(RendererRD::VRS *p_vrs) { vrs = p_vrs; }
void cleanup();
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void configure(const RenderSceneBuffersConfiguration *p_config) override;
void configure_for_reflections(const Size2i p_reflection_size);
virtual void set_fsr_sharpness(float p_fsr_sharpness) override;
virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override;
@@ -202,6 +205,7 @@ public:
_FORCE_INLINE_ RS::ViewportScaling3DMode get_scaling_3d_mode() const { return scaling_3d_mode; }
_FORCE_INLINE_ float get_fsr_sharpness() const { return fsr_sharpness; }
_FORCE_INLINE_ RS::ViewportMSAA get_msaa_3d() const { return msaa_3d; }
+ _FORCE_INLINE_ RD::TextureSamples get_texture_samples() const { return texture_samples; }
_FORCE_INLINE_ RS::ViewportScreenSpaceAA get_screen_space_aa() const { return screen_space_aa; }
_FORCE_INLINE_ bool get_use_taa() const { return use_taa; }
_FORCE_INLINE_ bool get_use_debanding() const { return use_debanding; }
@@ -220,11 +224,24 @@ public:
_FORCE_INLINE_ RID get_internal_texture(const uint32_t p_layer) {
return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_COLOR, p_layer, 0);
}
+ _FORCE_INLINE_ RID get_color_msaa() const {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA);
+ }
+ _FORCE_INLINE_ RID get_color_msaa(uint32_t p_layer) {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA, p_layer, 0);
+ }
bool has_depth_texture();
RID get_depth_texture();
RID get_depth_texture(const uint32_t p_layer);
+ RID get_depth_msaa() const {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA);
+ }
+ RID get_depth_msaa(uint32_t p_layer) {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA, p_layer, 0);
+ }
+
// back buffer (color)
RID get_back_buffer_texture() const { return has_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) ? get_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) : RID(); } // We (re)use our blur texture here.
@@ -236,8 +253,78 @@ public:
RID get_velocity_buffer(bool p_get_msaa, uint32_t p_layer);
////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Everything after this needs to be re-evaluated, this is all old implementation
+ // Our classDB doesn't support calling our normal exposed functions
+
+private:
+ RID _create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const Ref<RDTextureFormat> &p_texture_format, const Ref<RDTextureView> &p_view = Ref<RDTextureView>(), bool p_unique = true);
+ RID _create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, const Ref<RDTextureView> p_view = Ref<RDTextureView>());
+ Ref<RDTextureFormat> _get_texture_format(const StringName &p_context, const StringName &p_texture_name) const;
+
+ // For color and depth as exposed to extensions, we return the buffer that we're rendering into.
+ // Resolving happens after effects etc. are run.
+ RID _get_color_texture() {
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED && has_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA)) {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA);
+ } else if (has_internal_texture()) {
+ return get_internal_texture();
+ } else {
+ return RID();
+ }
+ }
+
+ RID _get_color_layer(const uint32_t p_layer) {
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED && has_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA)) {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA, p_layer, 0);
+ } else if (has_internal_texture()) {
+ return get_internal_texture(p_layer);
+ } else {
+ return RID();
+ }
+ }
+
+ RID _get_depth_texture() {
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED && has_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA)) {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA);
+ } else if (has_depth_texture()) {
+ return get_depth_texture();
+ } else {
+ return RID();
+ }
+ }
+
+ RID _get_depth_layer(const uint32_t p_layer) {
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED && has_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA)) {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA, p_layer, 0);
+ } else if (has_depth_texture()) {
+ return get_depth_texture(p_layer);
+ } else {
+ return RID();
+ }
+ }
+
+ RID _get_velocity_texture() {
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED && has_velocity_buffer(true)) {
+ return get_velocity_buffer(true);
+ } else if (has_velocity_buffer(false)) {
+ return get_velocity_buffer(false);
+ } else {
+ return RID();
+ }
+ }
+
+ RID _get_velocity_layer(const uint32_t p_layer) {
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED && has_velocity_buffer(true)) {
+ return get_velocity_buffer(true, p_layer);
+ } else if (has_velocity_buffer(false)) {
+ return get_velocity_buffer(false, p_layer);
+ } else {
+ return RID();
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Everything after this needs to be re-evaluated, this is all old implementation
+public:
struct WeightBuffers {
RID weight;
RID fb; // FB with both texture and weight writing into one level lower
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 3c4e792b37..d84f6e6850 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -1395,6 +1395,13 @@ String TextureStorage::texture_get_path(RID p_texture) const {
return tex->path;
}
+Image::Format TextureStorage::texture_get_format(RID p_texture) const {
+ Texture *tex = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!tex, Image::FORMAT_MAX);
+
+ return tex->format;
+}
+
void TextureStorage::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
@@ -1429,6 +1436,79 @@ Size2 TextureStorage::texture_size_with_proxy(RID p_proxy) {
return texture_2d_get_size(p_proxy);
}
+void TextureStorage::texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type) {
+ ERR_FAIL_COND(!RD::get_singleton()->texture_is_valid(p_rd_texture));
+
+ // TODO : investigate if we can support this, will need to be able to obtain the order and obtain the slice info
+ ERR_FAIL_COND_MSG(RD::get_singleton()->texture_is_shared(p_rd_texture), "Please create the texture object using the original texture");
+
+ RD::TextureFormat tf = RD::get_singleton()->texture_get_format(p_rd_texture);
+ ERR_FAIL_COND(!(tf.usage_bits & RD::TEXTURE_USAGE_SAMPLING_BIT));
+
+ TextureFromRDFormat imfmt;
+ _texture_format_from_rd(tf.format, imfmt);
+ ERR_FAIL_COND(imfmt.image_format == Image::FORMAT_MAX);
+
+ Texture texture;
+
+ switch (tf.texture_type) {
+ case RD::TEXTURE_TYPE_2D: {
+ ERR_FAIL_COND(tf.array_layers != 1);
+ texture.type = TextureStorage::TYPE_2D;
+ } break;
+ case RD::TEXTURE_TYPE_2D_ARRAY: {
+ // RenderingDevice doesn't distinguish between Array textures and Cube textures
+ // this condition covers TextureArrays, TextureCube, and TextureCubeArray.
+ ERR_FAIL_COND(tf.array_layers == 1);
+ texture.type = TextureStorage::TYPE_LAYERED;
+ texture.layered_type = p_layer_type;
+ } break;
+ case RD::TEXTURE_TYPE_3D: {
+ ERR_FAIL_COND(tf.array_layers != 1);
+ texture.type = TextureStorage::TYPE_3D;
+ } break;
+ default: {
+ ERR_FAIL_MSG("This RD texture can't be used as a render texture");
+ } break;
+ }
+
+ texture.width = tf.width;
+ texture.height = tf.height;
+ texture.depth = tf.depth;
+ texture.layers = tf.array_layers;
+ texture.mipmaps = tf.mipmaps;
+ texture.format = imfmt.image_format;
+ texture.validated_format = texture.format; // ??
+
+ RD::TextureView rd_view;
+ rd_view.format_override = imfmt.rd_format == tf.format ? RD::DATA_FORMAT_MAX : imfmt.rd_format;
+ rd_view.swizzle_r = imfmt.swizzle_r;
+ rd_view.swizzle_g = imfmt.swizzle_g;
+ rd_view.swizzle_b = imfmt.swizzle_b;
+ rd_view.swizzle_a = imfmt.swizzle_a;
+
+ texture.rd_type = tf.texture_type;
+ texture.rd_view = rd_view;
+ texture.rd_format = imfmt.rd_format;
+ // We create a shared texture here even if our view matches, so we don't obtain ownership.
+ texture.rd_texture = RD::get_singleton()->texture_create_shared(rd_view, p_rd_texture);
+ if (imfmt.rd_format_srgb != RD::DATA_FORMAT_MAX) {
+ rd_view.format_override = imfmt.rd_format_srgb == tf.format ? RD::DATA_FORMAT_MAX : imfmt.rd_format;
+ texture.rd_format_srgb = imfmt.rd_format_srgb;
+ // We create a shared texture here even if our view matches, so we don't obtain ownership.
+ texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, p_rd_texture);
+ }
+
+ // TODO figure out what to do with slices
+
+ texture.width_2d = texture.width;
+ texture.height_2d = texture.height;
+ texture.is_render_target = false;
+ texture.is_proxy = false;
+
+ texture_owner.initialize_rid(p_texture, texture);
+}
+
RID TextureStorage::texture_get_rd_texture(RID p_texture, bool p_srgb) const {
if (p_texture.is_null()) {
return RID();
@@ -1921,6 +2001,362 @@ Ref<Image> TextureStorage::_validate_texture_format(const Ref<Image> &p_image, T
return image;
}
+void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, TextureFromRDFormat &r_format) {
+ switch (p_rd_format) {
+ case RD::DATA_FORMAT_R8_UNORM: {
+ r_format.image_format = Image::FORMAT_L8;
+ r_format.rd_format = RD::DATA_FORMAT_R8_UNORM;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //luminance
+ case RD::DATA_FORMAT_R8G8_UNORM: {
+ r_format.image_format = Image::FORMAT_LA8;
+ r_format.rd_format = RD::DATA_FORMAT_R8G8_UNORM;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_G;
+ } break; //luminance-alpha
+ /* already maps to L8/LA8
+ case RD::DATA_FORMAT_R8_UNORM: {
+ r_format.image_format = Image::FORMAT_R8;
+ r_format.rd_format = RD::DATA_FORMAT_R8_UNORM;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case RD::DATA_FORMAT_R8G8_UNORM: {
+ r_format.image_format = Image::FORMAT_RG8;
+ r_format.rd_format = RD::DATA_FORMAT_R8G8_UNORM;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ */
+ case RD::DATA_FORMAT_R8G8B8_UNORM:
+ case RD::DATA_FORMAT_R8G8B8_SRGB: {
+ r_format.image_format = Image::FORMAT_RGB8;
+ r_format.rd_format = RD::DATA_FORMAT_R8G8B8_UNORM;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_R8G8B8_SRGB;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ case RD::DATA_FORMAT_R8G8B8A8_UNORM:
+ case RD::DATA_FORMAT_R8G8B8A8_SRGB: {
+ r_format.image_format = Image::FORMAT_RGBA8;
+ r_format.rd_format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case RD::DATA_FORMAT_B4G4R4A4_UNORM_PACK16: {
+ r_format.image_format = Image::FORMAT_RGBA4444;
+ r_format.rd_format = RD::DATA_FORMAT_B4G4R4A4_UNORM_PACK16;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_B; //needs swizzle
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case RD::DATA_FORMAT_B5G6R5_UNORM_PACK16: {
+ r_format.image_format = Image::FORMAT_RGB565;
+ r_format.rd_format = RD::DATA_FORMAT_B5G6R5_UNORM_PACK16;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case RD::DATA_FORMAT_R32_SFLOAT: {
+ r_format.image_format = Image::FORMAT_RF;
+ r_format.rd_format = RD::DATA_FORMAT_R32_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //float
+ case RD::DATA_FORMAT_R32G32_SFLOAT: {
+ r_format.image_format = Image::FORMAT_RGF;
+ r_format.rd_format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case RD::DATA_FORMAT_R32G32B32_SFLOAT: {
+ r_format.image_format = Image::FORMAT_RGBF;
+ r_format.rd_format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case RD::DATA_FORMAT_R32G32B32A32_SFLOAT: {
+ r_format.image_format = Image::FORMAT_RGBF;
+ r_format.rd_format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break;
+ case RD::DATA_FORMAT_R16_SFLOAT: {
+ r_format.image_format = Image::FORMAT_RH;
+ r_format.rd_format = RD::DATA_FORMAT_R16_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break; //half float
+ case RD::DATA_FORMAT_R16G16_SFLOAT: {
+ r_format.image_format = Image::FORMAT_RGH;
+ r_format.rd_format = RD::DATA_FORMAT_R16G16_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ case RD::DATA_FORMAT_R16G16B16_SFLOAT: {
+ r_format.image_format = Image::FORMAT_RGBH;
+ r_format.rd_format = RD::DATA_FORMAT_R16G16B16_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case RD::DATA_FORMAT_R16G16B16A16_SFLOAT: {
+ r_format.image_format = Image::FORMAT_RGBAH;
+ r_format.rd_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break;
+ case RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32: {
+ r_format.image_format = Image::FORMAT_RGBE9995;
+ r_format.rd_format = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
+ // TODO: Need to make a function in Image to swap bits for this.
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_IDENTITY;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_IDENTITY;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_IDENTITY;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_IDENTITY;
+ } break;
+ case RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
+ case RD::DATA_FORMAT_BC1_RGB_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_DXT1;
+ r_format.rd_format = RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_BC1_RGB_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break; //s3tc bc1
+ case RD::DATA_FORMAT_BC2_UNORM_BLOCK:
+ case RD::DATA_FORMAT_BC2_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_DXT3;
+ r_format.rd_format = RD::DATA_FORMAT_BC2_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_BC2_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break; //bc2
+ case RD::DATA_FORMAT_BC3_UNORM_BLOCK:
+ case RD::DATA_FORMAT_BC3_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_DXT5;
+ r_format.rd_format = RD::DATA_FORMAT_BC3_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_BC3_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break; //bc3
+ case RD::DATA_FORMAT_BC4_UNORM_BLOCK: {
+ r_format.image_format = Image::FORMAT_RGTC_R;
+ r_format.rd_format = RD::DATA_FORMAT_BC4_UNORM_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ case RD::DATA_FORMAT_BC5_UNORM_BLOCK: {
+ r_format.image_format = Image::FORMAT_RGTC_RG;
+ r_format.rd_format = RD::DATA_FORMAT_BC5_UNORM_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ case RD::DATA_FORMAT_BC7_UNORM_BLOCK:
+ case RD::DATA_FORMAT_BC7_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_BPTC_RGBA;
+ r_format.rd_format = RD::DATA_FORMAT_BC7_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_BC7_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break; //btpc bc7
+ case RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK: {
+ r_format.image_format = Image::FORMAT_BPTC_RGBF;
+ r_format.rd_format = RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //float bc6h
+ case RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK: {
+ r_format.image_format = Image::FORMAT_BPTC_RGBFU;
+ r_format.rd_format = RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //unsigned float bc6hu
+ case RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK: {
+ r_format.image_format = Image::FORMAT_ETC2_R11;
+ r_format.rd_format = RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break; //etc2
+ case RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK: {
+ r_format.image_format = Image::FORMAT_ETC2_R11S;
+ r_format.rd_format = RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //signed: {} break; NOT srgb.
+ case RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: {
+ r_format.image_format = Image::FORMAT_ETC2_RG11;
+ r_format.rd_format = RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: {
+ r_format.image_format = Image::FORMAT_ETC2_RG11S;
+ r_format.rd_format = RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+ case RD::DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_ETC2_RGB8;
+ r_format.rd_format = RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ /* already maps to FORMAT_ETC2_RGBA8
+ case RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
+ case RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_ETC2_RGBA8;
+ r_format.rd_format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ */
+ case RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+ case RD::DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_ETC2_RGB8A1;
+ r_format.rd_format = RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
+ case RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_ETC2_RA_AS_RG;
+ r_format.rd_format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_A;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ /* already maps to FORMAT_DXT5
+ case RD::DATA_FORMAT_BC3_UNORM_BLOCK:
+ case RD::DATA_FORMAT_BC3_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_DXT5_RA_AS_RG;
+ r_format.rd_format = RD::DATA_FORMAT_BC3_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_BC3_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_A;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ */
+ case RD::DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: {
+ // Q: Do we do as we do below, just create the sRGB variant?
+ r_format.image_format = Image::FORMAT_ASTC_4x4;
+ r_format.rd_format = RD::DATA_FORMAT_ASTC_4x4_UNORM_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case RD::DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_ASTC_4x4_HDR;
+ r_format.rd_format = RD::DATA_FORMAT_ASTC_4x4_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_ASTC_4x4_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break; // astc 4x4
+ case RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: {
+ // Q: Do we do as we do below, just create the sRGB variant?
+ r_format.image_format = Image::FORMAT_ASTC_8x8;
+ r_format.rd_format = RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK;
+ } break;
+ case RD::DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: {
+ r_format.image_format = Image::FORMAT_ASTC_8x8_HDR;
+ r_format.rd_format = RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK;
+ r_format.rd_format_srgb = RD::DATA_FORMAT_ASTC_8x8_SRGB_BLOCK;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break; // astc 8x8
+
+ default: {
+ ERR_FAIL_MSG("Unsupported image format");
+ }
+ }
+}
+
/* DECAL API */
RID TextureStorage::decal_atlas_get_texture() const {
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index 8f021f3179..6df6faa40a 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -196,6 +196,27 @@ private:
Ref<Image> _validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format);
void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0, bool p_immediate = false);
+ struct TextureFromRDFormat {
+ Image::Format image_format;
+ RD::DataFormat rd_format;
+ RD::DataFormat rd_format_srgb;
+ RD::TextureSwizzle swizzle_r;
+ RD::TextureSwizzle swizzle_g;
+ RD::TextureSwizzle swizzle_b;
+ RD::TextureSwizzle swizzle_a;
+ TextureFromRDFormat() {
+ image_format = Image::FORMAT_MAX;
+ rd_format = RD::DATA_FORMAT_MAX;
+ rd_format_srgb = RD::DATA_FORMAT_MAX;
+ swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ }
+ };
+
+ void _texture_format_from_rd(RD::DataFormat p_rd_format, TextureFromRDFormat &r_format);
+
/* DECAL API */
struct DecalAtlas {
@@ -488,6 +509,8 @@ public:
virtual void texture_set_path(RID p_texture, const String &p_path) override;
virtual String texture_get_path(RID p_texture) const override;
+ virtual Image::Format texture_get_format(RID p_texture) const override;
+
virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override;
virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override;
virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override;
@@ -498,6 +521,7 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) override;
+ virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) override;
virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override;
virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index c5eabba326..44b15ee91d 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -3994,11 +3994,12 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
}
void RendererSceneCull::update_dirty_instances() {
- RSG::utilities->update_dirty_resources();
-
while (_instance_update_list.first()) {
_update_dirty_instance(_instance_update_list.first()->self());
}
+
+ // Update dirty resources after dirty instances as instance updates may affect resources.
+ RSG::utilities->update_dirty_resources();
}
void RendererSceneCull::update() {
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 71f6a28671..7a829826d2 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -180,7 +180,19 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
// to compensate for the loss of sharpness.
const float texture_mipmap_bias = log2f(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias;
- p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), scaling_3d_mode, p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count);
+ RenderSceneBuffersConfiguration rb_config;
+ rb_config.set_render_target(p_viewport->render_target);
+ rb_config.set_internal_size(Size2i(render_width, render_height));
+ rb_config.set_target_size(Size2(width, height));
+ rb_config.set_view_count(p_viewport->view_count);
+ rb_config.set_scaling_3d_mode(scaling_3d_mode);
+ rb_config.set_msaa_3d(p_viewport->msaa_3d);
+ rb_config.set_screen_space_aa(p_viewport->screen_space_aa);
+ rb_config.set_fsr_sharpness(p_viewport->fsr_sharpness);
+ rb_config.set_texture_mipmap_bias(texture_mipmap_bias);
+ rb_config.set_use_taa(p_viewport->use_taa);
+
+ p_viewport->render_buffers->configure(&rb_config);
}
}
}
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index d87c09a857..7bfa23bfa5 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -114,6 +114,14 @@ RID RenderingDevice::_texture_create_shared_from_slice(const Ref<RDTextureView>
return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_mipmaps, p_slice_type);
}
+Ref<RDTextureFormat> RenderingDevice::_texture_get_format(RID p_rd_texture) {
+ Ref<RDTextureFormat> rtf;
+ rtf.instantiate();
+ rtf->base = texture_get_format(p_rd_texture);
+
+ return rtf;
+}
+
RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count) {
Vector<AttachmentFormat> attachments;
attachments.resize(p_attachments.size());
@@ -720,6 +728,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL_BARRIERS));
+ ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &RenderingDevice::_texture_get_format);
ClassDB::bind_method(D_METHOD("texture_get_native_handle", "texture"), &RenderingDevice::texture_get_native_handle);
ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments", "view_count"), &RenderingDevice::_framebuffer_format_create, DEFVAL(1));
@@ -1073,9 +1082,11 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM);
BIND_ENUM_CONSTANT(DATA_FORMAT_MAX);
- BIND_BITFIELD_FLAG(BARRIER_MASK_RASTER);
+ BIND_BITFIELD_FLAG(BARRIER_MASK_VERTEX);
+ BIND_BITFIELD_FLAG(BARRIER_MASK_FRAGMENT);
BIND_BITFIELD_FLAG(BARRIER_MASK_COMPUTE);
BIND_BITFIELD_FLAG(BARRIER_MASK_TRANSFER);
+ BIND_BITFIELD_FLAG(BARRIER_MASK_RASTER);
BIND_BITFIELD_FLAG(BARRIER_MASK_ALL_BARRIERS);
BIND_BITFIELD_FLAG(BARRIER_MASK_NO_BARRIER);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index dd2f8d55aa..5edeb109e2 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -393,11 +393,14 @@ public:
/*****************/
enum BarrierMask {
- BARRIER_MASK_RASTER = 1,
- BARRIER_MASK_COMPUTE = 2,
- BARRIER_MASK_TRANSFER = 4,
+ BARRIER_MASK_VERTEX = 1,
+ BARRIER_MASK_FRAGMENT = 2,
+ BARRIER_MASK_COMPUTE = 4,
+ BARRIER_MASK_TRANSFER = 8,
+
+ BARRIER_MASK_RASTER = BARRIER_MASK_VERTEX | BARRIER_MASK_FRAGMENT, // 3,
BARRIER_MASK_ALL_BARRIERS = BARRIER_MASK_RASTER | BARRIER_MASK_COMPUTE | BARRIER_MASK_TRANSFER, // 7
- BARRIER_MASK_NO_BARRIER = 8,
+ BARRIER_MASK_NO_BARRIER = 16,
};
/*****************/
@@ -538,6 +541,7 @@ public:
virtual bool texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const = 0;
virtual bool texture_is_shared(RID p_texture) = 0;
virtual bool texture_is_valid(RID p_texture) = 0;
+ virtual TextureFormat texture_get_format(RID p_texture) = 0;
virtual Size2i texture_size(RID p_texture) = 0;
virtual uint64_t texture_get_native_handle(RID p_texture) = 0;
@@ -1313,6 +1317,7 @@ protected:
RID _texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data = Array());
RID _texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture);
RID _texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D);
+ Ref<RDTextureFormat> _texture_get_format(RID p_rd_texture);
FramebufferFormatID _framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count);
FramebufferFormatID _framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count);
diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h
index e173400299..bf30efbcf6 100644
--- a/servers/rendering/rendering_device_binds.h
+++ b/servers/rendering/rendering_device_binds.h
@@ -53,7 +53,9 @@
class RDTextureFormat : public RefCounted {
GDCLASS(RDTextureFormat, RefCounted)
+
friend class RenderingDevice;
+ friend class RenderSceneBuffersRD;
RD::TextureFormat base;
@@ -91,6 +93,7 @@ class RDTextureView : public RefCounted {
GDCLASS(RDTextureView, RefCounted)
friend class RenderingDevice;
+ friend class RenderSceneBuffersRD;
RD::TextureView base;
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 65bdb94c9f..ff6bf3a6ba 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -258,22 +258,10 @@ uint64_t RenderingServerDefault::get_rendering_info(RenderingInfo p_info) {
return RSG::utilities->get_rendering_info(p_info);
}
-String RenderingServerDefault::get_video_adapter_name() const {
- return RSG::utilities->get_video_adapter_name();
-}
-
-String RenderingServerDefault::get_video_adapter_vendor() const {
- return RSG::utilities->get_video_adapter_vendor();
-}
-
RenderingDevice::DeviceType RenderingServerDefault::get_video_adapter_type() const {
return RSG::utilities->get_video_adapter_type();
}
-String RenderingServerDefault::get_video_adapter_api_version() const {
- return RSG::utilities->get_video_adapter_api_version();
-}
-
void RenderingServerDefault::set_frame_profiling_enabled(bool p_enable) {
RSG::utilities->capturing_timestamps = p_enable;
}
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 797fe73ba0..c79d3a64cf 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -210,9 +210,13 @@ public:
FUNC2(texture_set_path, RID, const String &)
FUNC1RC(String, texture_get_path, RID)
+
+ FUNC1RC(Image::Format, texture_get_format, RID)
+
FUNC1(texture_debug_usage, List<TextureInfo> *)
FUNC2(texture_set_force_redraw_if_visible, RID, bool)
+ FUNCRIDTEX2(texture_rd, const RID &, const RS::TextureLayeredType)
FUNC2RC(RID, texture_get_rd_texture, RID, bool)
FUNC2RC(uint64_t, texture_get_native_handle, RID, bool)
@@ -946,9 +950,26 @@ public:
#undef server_name
#undef ServerName
+ /* STATUS INFORMATION */
+#define ServerName RendererUtilities
+#define server_name RSG::utilities
+ FUNC0RC(String, get_video_adapter_name)
+ FUNC0RC(String, get_video_adapter_vendor)
+ FUNC0RC(String, get_video_adapter_api_version)
+#undef server_name
+#undef ServerName
#undef WRITE_ACTION
#undef SYNC_DEBUG
+ virtual uint64_t get_rendering_info(RenderingInfo p_info) override;
+ virtual RenderingDevice::DeviceType get_video_adapter_type() const override;
+
+ virtual void set_frame_profiling_enabled(bool p_enable) override;
+ virtual Vector<FrameProfileArea> get_frame_profile() override;
+ virtual uint64_t get_frame_profile_frame() override;
+
+ virtual RID get_test_cube() override;
+
/* FREE */
virtual void free(RID p_rid) override {
@@ -970,20 +991,6 @@ public:
virtual void init() override;
virtual void finish() override;
- /* STATUS INFORMATION */
-
- virtual uint64_t get_rendering_info(RenderingInfo p_info) override;
- virtual String get_video_adapter_name() const override;
- virtual String get_video_adapter_vendor() const override;
- virtual RenderingDevice::DeviceType get_video_adapter_type() const override;
- virtual String get_video_adapter_api_version() const override;
-
- virtual void set_frame_profiling_enabled(bool p_enable) override;
- virtual Vector<FrameProfileArea> get_frame_profile() override;
- virtual uint64_t get_frame_profile_frame() override;
-
- virtual RID get_test_cube() override;
-
/* TESTING */
virtual double get_frame_setup_time_cpu() const override;
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 4ea06afe79..0e6c0e4bf6 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -178,7 +178,7 @@ static String _mkid(const String &p_id) {
}
static String f2sp0(float p_float) {
- String num = rtoss(p_float);
+ String num = rtos(p_float);
if (!num.contains(".") && !num.contains("e")) {
num += ".0";
}
@@ -283,7 +283,21 @@ String ShaderCompiler::_get_sampler_name(ShaderLanguage::TextureFilter p_filter,
ERR_FAIL_COND_V(actions.default_repeat == ShaderLanguage::REPEAT_DEFAULT, String());
p_repeat = actions.default_repeat;
}
- return actions.sampler_array_name + "[" + itos(p_filter + (p_repeat == ShaderLanguage::REPEAT_ENABLE ? ShaderLanguage::FILTER_DEFAULT : 0)) + "]";
+ constexpr const char *name_mapping[] = {
+ "SAMPLER_NEAREST_CLAMP",
+ "SAMPLER_LINEAR_CLAMP",
+ "SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP",
+ "SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP",
+ "SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP",
+ "SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP",
+ "SAMPLER_NEAREST_REPEAT",
+ "SAMPLER_LINEAR_REPEAT",
+ "SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT",
+ "SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT",
+ "SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT",
+ "SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT"
+ };
+ return String(name_mapping[p_filter + (p_repeat == ShaderLanguage::REPEAT_ENABLE ? ShaderLanguage::FILTER_DEFAULT : 0)]);
}
void ShaderCompiler::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const HashMap<StringName, String> &p_func_code, String &r_to_add, HashSet<StringName> &added) {
@@ -909,7 +923,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
//its a uniform!
const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[vnode->name];
if (u.texture_order >= 0) {
- StringName name = vnode->name;
+ StringName name;
if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) {
name = "color_buffer";
if (u.filter >= ShaderLanguage::FILTER_NEAREST_MIPMAP) {
diff --git a/servers/rendering/shader_compiler.h b/servers/rendering/shader_compiler.h
index 3bb29a545b..2d58be7261 100644
--- a/servers/rendering/shader_compiler.h
+++ b/servers/rendering/shader_compiler.h
@@ -93,7 +93,6 @@ public:
HashMap<StringName, String> custom_samplers;
ShaderLanguage::TextureFilter default_filter;
ShaderLanguage::TextureRepeat default_repeat;
- String sampler_array_name;
int base_texture_binding_index = 0;
int texture_layout_set = 0;
String base_uniform_string;
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index ca41cc8d51..e9421a435e 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -659,7 +659,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
char t = char(i);
suffix_lut[CASE_ALL][i] = t == '.' || t == 'x' || t == 'e' || t == 'f' || t == 'u' || t == '-' || t == '+';
- suffix_lut[CASE_HEXA_PERIOD][i] = t == 'e' || t == 'f';
+ suffix_lut[CASE_HEXA_PERIOD][i] = t == 'e' || t == 'f' || t == 'u';
suffix_lut[CASE_EXPONENT][i] = t == 'f' || t == '-' || t == '+';
suffix_lut[CASE_SIGN_AFTER_EXPONENT][i] = t == 'f';
suffix_lut[CASE_NONE][i] = false;
@@ -738,6 +738,13 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
char32_t last_char = str[str.length() - 1];
if (hexa_found) { // Integer (hex).
+ if (uint_suffix_found) {
+ // Strip the suffix.
+ str = str.left(str.length() - 1);
+
+ // Compensate reading cursor position.
+ char_idx += 1;
+ }
if (str.size() > 11 || !str.is_valid_hex_number(true)) { // > 0xFFFFFFFF
return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant");
}
@@ -3381,12 +3388,14 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
int last_arg_count = 0;
+ bool exists = false;
String arg_list = "";
for (int i = 0; i < shader->functions.size(); i++) {
if (name != shader->functions[i].name) {
continue;
}
+ exists = true;
if (!shader->functions[i].callable) {
_set_error(vformat(RTR("Function '%s' can't be called from source code."), String(name)));
@@ -3487,10 +3496,12 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
}
- if (last_arg_count > args.size()) {
- _set_error(vformat(RTR("Too few arguments for \"%s(%s)\" call. Expected at least %d but received %d."), String(name), arg_list, last_arg_count, args.size()));
- } else if (last_arg_count < args.size()) {
- _set_error(vformat(RTR("Too many arguments for \"%s(%s)\" call. Expected at most %d but received %d."), String(name), arg_list, last_arg_count, args.size()));
+ if (exists) {
+ if (last_arg_count > args.size()) {
+ _set_error(vformat(RTR("Too few arguments for \"%s(%s)\" call. Expected at least %d but received %d."), String(name), arg_list, last_arg_count, args.size()));
+ } else if (last_arg_count < args.size()) {
+ _set_error(vformat(RTR("Too many arguments for \"%s(%s)\" call. Expected at most %d but received %d."), String(name), arg_list, last_arg_count, args.size()));
+ }
}
return false;
@@ -8612,7 +8623,12 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
}
if (uniform.array_size > 0) {
- if (tk.type != TK_HINT_SOURCE_COLOR) {
+ static Vector<int> supported_hints = {
+ TK_HINT_SOURCE_COLOR, TK_REPEAT_DISABLE, TK_REPEAT_ENABLE,
+ TK_FILTER_LINEAR, TK_FILTER_LINEAR_MIPMAP, TK_FILTER_LINEAR_MIPMAP_ANISOTROPIC,
+ TK_FILTER_NEAREST, TK_FILTER_NEAREST_MIPMAP, TK_FILTER_NEAREST_MIPMAP_ANISOTROPIC
+ };
+ if (!supported_hints.has(tk.type)) {
_set_error(RTR("This hint is not supported for uniform arrays."));
return ERR_PARSE_ERROR;
}
@@ -8800,8 +8816,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
new_hint = ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE;
--texture_uniforms;
--texture_binding;
- if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
- _set_error(RTR("'hint_normal_roughness_texture' is not supported in gl_compatibility shaders."));
+ if (OS::get_singleton()->get_current_rendering_method() != "forward_plus") {
+ _set_error(RTR("'hint_normal_roughness_texture' is only available when using the Forward+ backend."));
return ERR_PARSE_ERROR;
}
if (String(shader_type_identifier) != "spatial") {
@@ -10537,19 +10553,23 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
}
} else if ((int(completion_base) > int(TYPE_MAT4) && int(completion_base) < int(TYPE_STRUCT))) {
Vector<String> options;
+ if (current_uniform_filter == FILTER_DEFAULT) {
+ options.push_back("filter_linear");
+ options.push_back("filter_linear_mipmap");
+ options.push_back("filter_linear_mipmap_anisotropic");
+ options.push_back("filter_nearest");
+ options.push_back("filter_nearest_mipmap");
+ options.push_back("filter_nearest_mipmap_anisotropic");
+ }
+ if (current_uniform_repeat == REPEAT_DEFAULT) {
+ options.push_back("repeat_enable");
+ options.push_back("repeat_disable");
+ }
if (completion_base_array) {
if (current_uniform_hint == ShaderNode::Uniform::HINT_NONE) {
options.push_back("source_color");
}
} else {
- if (current_uniform_filter == FILTER_DEFAULT) {
- options.push_back("filter_linear");
- options.push_back("filter_linear_mipmap");
- options.push_back("filter_linear_mipmap_anisotropic");
- options.push_back("filter_nearest");
- options.push_back("filter_nearest_mipmap");
- options.push_back("filter_nearest_mipmap_anisotropic");
- }
if (current_uniform_hint == ShaderNode::Uniform::HINT_NONE) {
options.push_back("hint_anisotropy");
options.push_back("hint_default_black");
@@ -10567,10 +10587,6 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
options.push_back("hint_depth_texture");
options.push_back("source_color");
}
- if (current_uniform_repeat == REPEAT_DEFAULT) {
- options.push_back("repeat_enable");
- options.push_back("repeat_disable");
- }
}
for (int i = 0; i < options.size(); i++) {
diff --git a/servers/rendering/storage/render_scene_buffers.cpp b/servers/rendering/storage/render_scene_buffers.cpp
index 6369139aa6..19496c0116 100644
--- a/servers/rendering/storage/render_scene_buffers.cpp
+++ b/servers/rendering/storage/render_scene_buffers.cpp
@@ -30,22 +30,67 @@
#include "render_scene_buffers.h"
+void RenderSceneBuffersConfiguration::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_render_target"), &RenderSceneBuffersConfiguration::get_render_target);
+ ClassDB::bind_method(D_METHOD("set_render_target", "render_target"), &RenderSceneBuffersConfiguration::set_render_target);
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "render_target"), "set_render_target", "get_render_target");
+
+ ClassDB::bind_method(D_METHOD("get_internal_size"), &RenderSceneBuffersConfiguration::get_internal_size);
+ ClassDB::bind_method(D_METHOD("set_internal_size", "internal_size"), &RenderSceneBuffersConfiguration::set_internal_size);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "internal_size"), "set_internal_size", "get_internal_size");
+
+ ClassDB::bind_method(D_METHOD("get_target_size"), &RenderSceneBuffersConfiguration::get_target_size);
+ ClassDB::bind_method(D_METHOD("set_target_size", "target_size"), &RenderSceneBuffersConfiguration::set_target_size);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "target_size"), "set_target_size", "get_target_size");
+
+ ClassDB::bind_method(D_METHOD("get_view_count"), &RenderSceneBuffersConfiguration::get_view_count);
+ ClassDB::bind_method(D_METHOD("set_view_count", "view_count"), &RenderSceneBuffersConfiguration::set_view_count);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "view_count"), "set_view_count", "get_view_count");
+
+ ClassDB::bind_method(D_METHOD("get_scaling_3d_mode"), &RenderSceneBuffersConfiguration::get_scaling_3d_mode);
+ ClassDB::bind_method(D_METHOD("set_scaling_3d_mode", "scaling_3d_mode"), &RenderSceneBuffersConfiguration::set_scaling_3d_mode);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast)"), "set_scaling_3d_mode", "get_scaling_3d_mode"); // TODO VIEWPORT_SCALING_3D_MODE_OFF is possible here too, but we can't specify an enum string for it.
+
+ ClassDB::bind_method(D_METHOD("get_msaa_3d"), &RenderSceneBuffersConfiguration::get_msaa_3d);
+ ClassDB::bind_method(D_METHOD("set_msaa_3d", "msaa_3d"), &RenderSceneBuffersConfiguration::set_msaa_3d);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa_3d", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x"), "set_msaa_3d", "get_msaa_3d");
+
+ ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &RenderSceneBuffersConfiguration::get_screen_space_aa);
+ ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &RenderSceneBuffersConfiguration::set_screen_space_aa);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa");
+
+ ClassDB::bind_method(D_METHOD("get_fsr_sharpness"), &RenderSceneBuffersConfiguration::get_fsr_sharpness);
+ ClassDB::bind_method(D_METHOD("set_fsr_sharpness", "fsr_sharpness"), &RenderSceneBuffersConfiguration::set_fsr_sharpness);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fsr_sharpness"), "set_fsr_sharpness", "get_fsr_sharpness");
+
+ ClassDB::bind_method(D_METHOD("get_texture_mipmap_bias"), &RenderSceneBuffersConfiguration::get_texture_mipmap_bias);
+ ClassDB::bind_method(D_METHOD("set_texture_mipmap_bias", "texture_mipmap_bias"), &RenderSceneBuffersConfiguration::set_texture_mipmap_bias);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "texture_mipmap_bias"), "set_texture_mipmap_bias", "get_texture_mipmap_bias");
+}
+
void RenderSceneBuffers::_bind_methods() {
- ClassDB::bind_method(D_METHOD("configure", "render_target", "internal_size", "target_size", "fsr_sharpness", "texture_mipmap_bias", "msaa", "screen_space_aa", "use_taa", "use_debanding", "view_count"), &RenderSceneBuffers::configure);
+ ClassDB::bind_method(D_METHOD("configure", "config"), &RenderSceneBuffers::configure);
+}
+
+void RenderSceneBuffersExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_configure, "config");
+ GDVIRTUAL_BIND(_set_fsr_sharpness, "fsr_sharpness");
+ GDVIRTUAL_BIND(_set_texture_mipmap_bias, "texture_mipmap_bias");
+ GDVIRTUAL_BIND(_set_use_debanding, "use_debanding");
}
-void RenderSceneBuffers::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
- GDVIRTUAL_CALL(_configure, p_render_target, p_internal_size, p_target_size, p_scaling_3d_mode, p_fsr_sharpness, p_texture_mipmap_bias, p_msaa, p_screen_space_aa, p_use_taa, p_use_debanding, p_view_count);
+void RenderSceneBuffersExtension::configure(const RenderSceneBuffersConfiguration *p_config) {
+ GDVIRTUAL_CALL(_configure, p_config);
};
-void RenderSceneBuffers::set_fsr_sharpness(float p_fsr_sharpness) {
+void RenderSceneBuffersExtension::set_fsr_sharpness(float p_fsr_sharpness) {
GDVIRTUAL_CALL(_set_fsr_sharpness, p_fsr_sharpness);
}
-void RenderSceneBuffers::set_texture_mipmap_bias(float p_texture_mipmap_bias) {
+void RenderSceneBuffersExtension::set_texture_mipmap_bias(float p_texture_mipmap_bias) {
GDVIRTUAL_CALL(_set_texture_mipmap_bias, p_texture_mipmap_bias);
}
-void RenderSceneBuffers::set_use_debanding(bool p_use_debanding) {
+void RenderSceneBuffersExtension::set_use_debanding(bool p_use_debanding) {
GDVIRTUAL_CALL(_set_use_debanding, p_use_debanding);
}
diff --git a/servers/rendering/storage/render_scene_buffers.h b/servers/rendering/storage/render_scene_buffers.h
index cf96a9f372..6c82d47799 100644
--- a/servers/rendering/storage/render_scene_buffers.h
+++ b/servers/rendering/storage/render_scene_buffers.h
@@ -34,27 +34,103 @@
#include "core/object/ref_counted.h"
#include "servers/rendering_server.h"
+class RenderSceneBuffersConfiguration : public RefCounted {
+ GDCLASS(RenderSceneBuffersConfiguration, RefCounted);
+
+private:
+ RID render_target;
+
+ Size2i internal_size;
+ Size2i target_size;
+ uint32_t view_count = 1;
+
+ RS::ViewportScaling3DMode scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
+ RS::ViewportMSAA msaa_3d = RS::VIEWPORT_MSAA_DISABLED;
+ RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
+
+ float fsr_sharpness = 0.0;
+ float texture_mipmap_bias = 0.0;
+ bool use_taa = false;
+ bool use_debanding = false;
+
+protected:
+ static void _bind_methods();
+
+public:
+ RID get_render_target() const { return render_target; }
+ void set_render_target(RID p_render_target) { render_target = p_render_target; }
+
+ Size2i get_internal_size() const { return internal_size; }
+ void set_internal_size(Size2i p_internal_size) { internal_size = p_internal_size; }
+
+ Size2i get_target_size() const { return target_size; }
+ void set_target_size(Size2i p_target_size) { target_size = p_target_size; }
+
+ uint32_t get_view_count() const { return view_count; }
+ void set_view_count(uint32_t p_view_count) { view_count = p_view_count; }
+
+ RS::ViewportScaling3DMode get_scaling_3d_mode() const { return scaling_3d_mode; }
+ void set_scaling_3d_mode(RS::ViewportScaling3DMode p_scaling_3d_mode) { scaling_3d_mode = p_scaling_3d_mode; }
+
+ RS::ViewportMSAA get_msaa_3d() const { return msaa_3d; }
+ void set_msaa_3d(RS::ViewportMSAA p_msaa_3d) { msaa_3d = p_msaa_3d; }
+
+ RS::ViewportScreenSpaceAA get_screen_space_aa() const { return screen_space_aa; }
+ void set_screen_space_aa(RS::ViewportScreenSpaceAA p_screen_space_aa) { screen_space_aa = p_screen_space_aa; }
+
+ float get_fsr_sharpness() const { return fsr_sharpness; }
+ void set_fsr_sharpness(float p_fsr_sharpness) { fsr_sharpness = p_fsr_sharpness; }
+
+ float get_texture_mipmap_bias() const { return texture_mipmap_bias; }
+ void set_texture_mipmap_bias(float p_texture_mipmap_bias) { texture_mipmap_bias = p_texture_mipmap_bias; }
+
+ bool get_use_taa() const { return use_taa; }
+ void set_use_taa(bool p_use_taa) { use_taa = p_use_taa; }
+
+ bool get_use_debanding() const { return use_debanding; }
+ void set_use_debanding(bool p_use_debanding) { use_debanding = p_use_debanding; }
+
+ RenderSceneBuffersConfiguration() {}
+ virtual ~RenderSceneBuffersConfiguration(){};
+};
+
class RenderSceneBuffers : public RefCounted {
GDCLASS(RenderSceneBuffers, RefCounted);
protected:
static void _bind_methods();
- GDVIRTUAL11(_configure, RID, Size2i, Size2i, RS::ViewportScaling3DMode, float, float, RS::ViewportMSAA, RenderingServer::ViewportScreenSpaceAA, bool, bool, uint32_t)
+public:
+ RenderSceneBuffers(){};
+ virtual ~RenderSceneBuffers(){};
+
+ virtual void configure(const RenderSceneBuffersConfiguration *p_config) = 0;
+
+ // for those settings that are unlikely to require buffers to be recreated, we'll add setters
+ virtual void set_fsr_sharpness(float p_fsr_sharpness) = 0;
+ virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) = 0;
+ virtual void set_use_debanding(bool p_use_debanding) = 0;
+};
+
+class RenderSceneBuffersExtension : public RenderSceneBuffers {
+ GDCLASS(RenderSceneBuffersExtension, RenderSceneBuffers);
+
+protected:
+ static void _bind_methods();
+
+ GDVIRTUAL1(_configure, const RenderSceneBuffersConfiguration *)
GDVIRTUAL1(_set_fsr_sharpness, float)
GDVIRTUAL1(_set_texture_mipmap_bias, float)
GDVIRTUAL1(_set_use_debanding, bool)
public:
- RenderSceneBuffers(){};
- virtual ~RenderSceneBuffers(){};
+ virtual ~RenderSceneBuffersExtension(){};
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count);
+ virtual void configure(const RenderSceneBuffersConfiguration *p_config) override;
- // for those settings that are unlikely to require buffers to be recreated, we'll add setters
- virtual void set_fsr_sharpness(float p_fsr_sharpness);
- virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias);
- virtual void set_use_debanding(bool p_use_debanding);
+ virtual void set_fsr_sharpness(float p_fsr_sharpness) override;
+ virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override;
+ virtual void set_use_debanding(bool p_use_debanding) override;
};
#endif // RENDER_SCENE_BUFFERS_H
diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h
index 93b32bd372..c3a257595c 100644
--- a/servers/rendering/storage/texture_storage.h
+++ b/servers/rendering/storage/texture_storage.h
@@ -90,6 +90,8 @@ public:
virtual void texture_set_path(RID p_texture, const String &p_path) = 0;
virtual String texture_get_path(RID p_texture) const = 0;
+ virtual Image::Format texture_get_format(RID p_texture) const = 0;
+
virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0;
virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0;
virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) = 0;
@@ -100,6 +102,7 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) = 0;
+ virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) = 0;
virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const = 0;
virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const = 0;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 0c5c263265..4a95dc1963 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -402,9 +402,9 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const Vector3 *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
Vector2 res = src[i].octahedron_encode();
- int16_t vector[2] = {
- (int16_t)CLAMP(res.x * 65535, 0, 65535),
- (int16_t)CLAMP(res.y * 65535, 0, 65535),
+ uint16_t vector[2] = {
+ (uint16_t)CLAMP(res.x * 65535, 0, 65535),
+ (uint16_t)CLAMP(res.y * 65535, 0, 65535),
};
memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4);
@@ -422,9 +422,9 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]);
Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]);
- int16_t vector[2] = {
- (int16_t)CLAMP(res.x * 65535, 0, 65535),
- (int16_t)CLAMP(res.y * 65535, 0, 65535),
+ uint16_t vector[2] = {
+ (uint16_t)CLAMP(res.x * 65535, 0, 65535),
+ (uint16_t)CLAMP(res.y * 65535, 0, 65535),
};
memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4);
@@ -437,9 +437,9 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]);
Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]);
- int16_t vector[2] = {
- (int16_t)CLAMP(res.x * 65535, 0, 65535),
- (int16_t)CLAMP(res.y * 65535, 0, 65535),
+ uint16_t vector[2] = {
+ (uint16_t)CLAMP(res.x * 65535, 0, 65535),
+ (uint16_t)CLAMP(res.y * 65535, 0, 65535),
};
memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4);
@@ -1697,7 +1697,10 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_set_path", "texture", "path"), &RenderingServer::texture_set_path);
ClassDB::bind_method(D_METHOD("texture_get_path", "texture"), &RenderingServer::texture_get_path);
+ ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &RenderingServer::texture_get_format);
+
ClassDB::bind_method(D_METHOD("texture_set_force_redraw_if_visible", "texture", "enable"), &RenderingServer::texture_set_force_redraw_if_visible);
+ ClassDB::bind_method(D_METHOD("texture_rd_create", "rd_texture", "layer_type"), &RenderingServer::texture_rd_create, DEFVAL(RenderingServer::TEXTURE_LAYERED_2D_ARRAY));
ClassDB::bind_method(D_METHOD("texture_get_rd_texture", "texture", "srgb"), &RenderingServer::texture_get_rd_texture, DEFVAL(false));
ClassDB::bind_method(D_METHOD("texture_get_native_handle", "texture", "srgb"), &RenderingServer::texture_get_native_handle, DEFVAL(false));
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index deac2a59f9..9ea55c31b4 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -127,6 +127,8 @@ public:
virtual void texture_set_path(RID p_texture, const String &p_path) = 0;
virtual String texture_get_path(RID p_texture) const = 0;
+ virtual Image::Format texture_get_format(RID p_texture) const = 0;
+
typedef void (*TextureDetectCallback)(void *);
virtual void texture_set_detect_3d_callback(RID p_texture, TextureDetectCallback p_callback, void *p_userdata) = 0;
@@ -158,6 +160,7 @@ public:
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0;
+ virtual RID texture_rd_create(const RID &p_rd_texture, const RenderingServer::TextureLayeredType p_layer_type = RenderingServer::TEXTURE_LAYERED_2D_ARRAY) = 0;
virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const = 0;
virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const = 0;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 329344d4c4..07ad14f120 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -1539,7 +1539,7 @@ void TextServer::shaped_text_draw_outline(const RID &p_shaped, const RID &p_canv
if (rtl && ellipsis_pos >= 0) {
for (int i = ellipsis_gl_size - 1; i >= 0; i--) {
for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
- font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color);
+ font_draw_glyph_outline(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, p_outline_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color);
if (orientation == ORIENTATION_HORIZONTAL) {
ofs.x += ellipsis_glyphs[i].advance;
} else {
@@ -1602,7 +1602,7 @@ void TextServer::shaped_text_draw_outline(const RID &p_shaped, const RID &p_canv
if (!rtl && ellipsis_pos >= 0) {
for (int i = 0; i < ellipsis_gl_size; i++) {
for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
- font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color);
+ font_draw_glyph_outline(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, p_outline_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color);
if (orientation == ORIENTATION_HORIZONTAL) {
ofs.x += ellipsis_glyphs[i].advance;
} else {
diff --git a/tests/core/input/test_input_event.h b/tests/core/input/test_input_event.h
new file mode 100644
index 0000000000..6b4b80486c
--- /dev/null
+++ b/tests/core/input/test_input_event.h
@@ -0,0 +1,115 @@
+/**************************************************************************/
+/* test_input_event.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_INPUT_EVENT_H
+#define TEST_INPUT_EVENT_H
+
+#include "core/input/input_event.h"
+#include "core/math/rect2.h"
+#include "core/os/memory.h"
+#include "core/variant/array.h"
+
+#include "tests/test_macros.h"
+
+namespace TestInputEvent {
+TEST_CASE("[InputEvent] Signal is emitted when device is changed") {
+ Ref<InputEventKey> input_event;
+ input_event.instantiate();
+
+ SIGNAL_WATCH(*input_event, SNAME("changed"));
+ Array args1;
+ Array empty_args;
+ empty_args.push_back(args1);
+
+ input_event->set_device(1);
+
+ SIGNAL_CHECK("changed", empty_args);
+ CHECK(input_event->get_device() == 1);
+
+ SIGNAL_UNWATCH(*input_event, SNAME("changed"));
+}
+
+TEST_CASE("[InputEvent] Test accumulate") {
+ Ref<InputEventMouseMotion> iemm1, iemm2;
+ Ref<InputEventKey> iek;
+
+ iemm1.instantiate(), iemm2.instantiate();
+ iek.instantiate();
+
+ iemm1->set_button_mask(MouseButtonMask::LEFT);
+
+ CHECK_FALSE(iemm1->accumulate(iemm2));
+
+ iemm2->set_button_mask(MouseButtonMask::LEFT);
+
+ CHECK(iemm1->accumulate(iemm2));
+
+ CHECK_FALSE(iemm1->accumulate(iek));
+ CHECK_FALSE(iemm2->accumulate(iek));
+}
+
+TEST_CASE("[InputEvent][SceneTree] Test methods that interact with the InputMap") {
+ const String mock_action = "mock_action";
+ Ref<InputEventJoypadMotion> iejm;
+ iejm.instantiate();
+
+ InputMap::get_singleton()->add_action(mock_action, 0.5);
+ InputMap::get_singleton()->action_add_event(mock_action, iejm);
+
+ CHECK(iejm->is_action_type());
+ CHECK(iejm->is_action(mock_action));
+
+ CHECK(iejm->is_action_released(mock_action));
+ CHECK(Math::is_equal_approx(iejm->get_action_strength(mock_action), 0.0f));
+
+ iejm->set_axis_value(0.8f);
+ // Since deadzone is 0.5, action_strength grows linearly from 0.5 to 1.0.
+ CHECK(Math::is_equal_approx(iejm->get_action_strength(mock_action), 0.6f));
+ CHECK(Math::is_equal_approx(iejm->get_action_raw_strength(mock_action), 0.8f));
+ CHECK(iejm->is_action_pressed(mock_action));
+
+ InputMap::get_singleton()->erase_action(mock_action);
+}
+
+TEST_CASE("[InputEvent] Test xformed_by") {
+ Ref<InputEventMouseMotion> iemm1;
+ iemm1.instantiate();
+
+ iemm1->set_position(Vector2(0.0f, 0.0f));
+ Transform2D transform;
+ transform = transform.translated(Vector2(2.0f, 3.0f));
+
+ Ref<InputEventMouseMotion> iemm2 = iemm1->xformed_by(transform);
+
+ CHECK(iemm2->get_position().is_equal_approx(Vector2(2.0f, 3.0f)));
+}
+} // namespace TestInputEvent
+
+#endif // TEST_INPUT_EVENT_H
diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h
index d6eaa8bd77..a117f518de 100644
--- a/tests/core/io/test_image.h
+++ b/tests/core/io/test_image.h
@@ -325,6 +325,86 @@ TEST_CASE("[Image] Modifying pixels of an image") {
CHECK_MESSAGE(gray_image->get_pixel(2, 2).is_equal_approx(Color(0.266666681, 0.266666681, 0.266666681, 1)), "convert() RGBA to L8 should be around 0.266666681 (68).");
}
}
+
+TEST_CASE("[Image] Custom mipmaps") {
+ Ref<Image> image = memnew(Image(100, 100, false, Image::FORMAT_RGBA8));
+
+ REQUIRE(!image->has_mipmaps());
+ image->generate_mipmaps();
+ REQUIRE(image->has_mipmaps());
+
+ const int mipmaps = image->get_mipmap_count() + 1;
+ REQUIRE(mipmaps == 7);
+
+ // Initialize reference mipmap data.
+ // Each byte is given value "mipmap_index * 5".
+
+ {
+ PackedByteArray data = image->get_data();
+ uint8_t *data_ptr = data.ptrw();
+
+ for (int mip = 0; mip < mipmaps; mip++) {
+ int mip_offset = 0;
+ int mip_size = 0;
+ image->get_mipmap_offset_and_size(mip, mip_offset, mip_size);
+
+ for (int i = 0; i < mip_size; i++) {
+ data_ptr[mip_offset + i] = mip * 5;
+ }
+ }
+ image->set_data(image->get_width(), image->get_height(), image->has_mipmaps(), image->get_format(), data);
+ }
+
+ // Byte format conversion.
+
+ for (int format = Image::FORMAT_L8; format <= Image::FORMAT_RGBA8; format++) {
+ Ref<Image> image_bytes = memnew(Image());
+ image_bytes->copy_internals_from(image);
+ image_bytes->convert((Image::Format)format);
+ REQUIRE(image_bytes->has_mipmaps());
+
+ PackedByteArray data = image_bytes->get_data();
+ const uint8_t *data_ptr = data.ptr();
+
+ for (int mip = 0; mip < mipmaps; mip++) {
+ int mip_offset = 0;
+ int mip_size = 0;
+ image_bytes->get_mipmap_offset_and_size(mip, mip_offset, mip_size);
+
+ for (int i = 0; i < mip_size; i++) {
+ if (data_ptr[mip_offset + i] != mip * 5) {
+ REQUIRE_MESSAGE(false, "Byte format conversion error.");
+ }
+ }
+ }
+ }
+
+ // Floating point format conversion.
+
+ for (int format = Image::FORMAT_RF; format <= Image::FORMAT_RGBAF; format++) {
+ Ref<Image> image_rgbaf = memnew(Image());
+ image_rgbaf->copy_internals_from(image);
+ image_rgbaf->convert((Image::Format)format);
+ REQUIRE(image_rgbaf->has_mipmaps());
+
+ PackedByteArray data = image_rgbaf->get_data();
+ const uint8_t *data_ptr = data.ptr();
+
+ for (int mip = 0; mip < mipmaps; mip++) {
+ int mip_offset = 0;
+ int mip_size = 0;
+ image_rgbaf->get_mipmap_offset_and_size(mip, mip_offset, mip_size);
+
+ for (int i = 0; i < mip_size; i += 4) {
+ float value = *(float *)(data_ptr + mip_offset + i);
+ if (!Math::is_equal_approx(value * 255.0f, mip * 5)) {
+ REQUIRE_MESSAGE(false, "Floating point conversion error.");
+ }
+ }
+ }
+ }
+}
+
} // namespace TestImage
#endif // TEST_IMAGE_H
diff --git a/tests/core/io/test_json.h b/tests/core/io/test_json.h
index 34a66ab6b5..73c7ac7a2e 100644
--- a/tests/core/io/test_json.h
+++ b/tests/core/io/test_json.h
@@ -146,6 +146,90 @@ TEST_CASE("[JSON] Parsing objects (dictionaries)") {
dictionary["empty_object"].hash() == Dictionary().hash(),
"The parsed JSON should contain the expected values.");
}
+
+TEST_CASE("[JSON] Parsing escape sequences") {
+ // Only certain escape sequences are valid according to the JSON specification.
+ // Others must result in a parsing error instead.
+
+ JSON json;
+
+ TypedArray<String> valid_escapes;
+ valid_escapes.push_back("\";\"");
+ valid_escapes.push_back("\\;\\");
+ valid_escapes.push_back("/;/");
+ valid_escapes.push_back("b;\b");
+ valid_escapes.push_back("f;\f");
+ valid_escapes.push_back("n;\n");
+ valid_escapes.push_back("r;\r");
+ valid_escapes.push_back("t;\t");
+
+ SUBCASE("Basic valid escape sequences") {
+ for (int i = 0; i < valid_escapes.size(); i++) {
+ String valid_escape = valid_escapes[i];
+ String valid_escape_string = valid_escape.get_slice(";", 0);
+ String valid_escape_value = valid_escape.get_slice(";", 1);
+
+ String json_string = "\"\\";
+ json_string += valid_escape_string;
+ json_string += "\"";
+ json.parse(json_string);
+
+ CHECK_MESSAGE(
+ json.get_error_line() == 0,
+ vformat("Parsing valid escape sequence `%s` as JSON should parse successfully.", valid_escape_string));
+
+ String json_value = json.get_data();
+ CHECK_MESSAGE(
+ json_value == valid_escape_value,
+ vformat("Parsing valid escape sequence `%s` as JSON should return the expected value.", valid_escape_string));
+ }
+ }
+
+ SUBCASE("Valid unicode escape sequences") {
+ String json_string = "\"\\u0000\"";
+ json.parse(json_string);
+
+ CHECK_MESSAGE(
+ json.get_error_line() == 0,
+ vformat("Parsing valid unicode escape sequence with value `0000` as JSON should parse successfully."));
+
+ String json_value = json.get_data();
+ CHECK_MESSAGE(
+ json_value == "\0",
+ vformat("Parsing valid unicode escape sequence with value `0000` as JSON should return the expected value."));
+ }
+
+ SUBCASE("Invalid escape sequences") {
+ for (char32_t i = 0; i < 128; i++) {
+ bool skip = false;
+ for (int j = 0; j < valid_escapes.size(); j++) {
+ String valid_escape = valid_escapes[j];
+ String valid_escape_string = valid_escape.get_slice(";", 0);
+ if (valid_escape_string[0] == i) {
+ skip = true;
+ break;
+ }
+ }
+
+ if (skip) {
+ continue;
+ }
+
+ String json_string = "\"\\";
+ json_string += i;
+ json_string += "\"";
+ Error err = json.parse(json_string);
+
+ // TODO: Line number is currently kept on 0, despite an error occurring. This should be fixed in the JSON parser.
+ // CHECK_MESSAGE(
+ // json.get_error_line() != 0,
+ // vformat("Parsing invalid escape sequence with ASCII value `%d` as JSON should fail to parse.", i));
+ CHECK_MESSAGE(
+ err == ERR_PARSE_ERROR,
+ vformat("Parsing invalid escape sequence with ASCII value `%d` as JSON should fail to parse with ERR_PARSE_ERROR.", i));
+ }
+ }
+}
} // namespace TestJSON
#endif // TEST_JSON_H
diff --git a/tests/core/io/test_resource.h b/tests/core/io/test_resource.h
index 20d76c8894..8fc2a2f040 100644
--- a/tests/core/io/test_resource.h
+++ b/tests/core/io/test_resource.h
@@ -109,6 +109,58 @@ TEST_CASE("[Resource] Saving and loading") {
loaded_child_resource_text->get_name() == "I'm a child resource",
"The loaded child resource name should be equal to the expected value.");
}
+
+TEST_CASE("[Resource] Breaking circular references on save") {
+ Ref<Resource> resource_a = memnew(Resource);
+ resource_a->set_name("A");
+ Ref<Resource> resource_b = memnew(Resource);
+ resource_b->set_name("B");
+ Ref<Resource> resource_c = memnew(Resource);
+ resource_c->set_name("C");
+ resource_a->set_meta("next", resource_b);
+ resource_b->set_meta("next", resource_c);
+ resource_c->set_meta("next", resource_b);
+
+ const String save_path_binary = OS::get_singleton()->get_cache_path().path_join("resource.res");
+ const String save_path_text = OS::get_singleton()->get_cache_path().path_join("resource.tres");
+ ResourceSaver::save(resource_a, save_path_binary);
+ ResourceSaver::save(resource_a, save_path_text);
+
+ const Ref<Resource> &loaded_resource_a_binary = ResourceLoader::load(save_path_binary);
+ CHECK_MESSAGE(
+ loaded_resource_a_binary->get_name() == "A",
+ "The loaded resource name should be equal to the expected value.");
+ const Ref<Resource> &loaded_resource_b_binary = loaded_resource_a_binary->get_meta("next");
+ CHECK_MESSAGE(
+ loaded_resource_b_binary->get_name() == "B",
+ "The loaded child resource name should be equal to the expected value.");
+ const Ref<Resource> &loaded_resource_c_binary = loaded_resource_b_binary->get_meta("next");
+ CHECK_MESSAGE(
+ 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"),
+ "The loaded child resource circular reference should be NULL.");
+
+ const Ref<Resource> &loaded_resource_a_text = ResourceLoader::load(save_path_text);
+ CHECK_MESSAGE(
+ loaded_resource_a_text->get_name() == "A",
+ "The loaded resource name should be equal to the expected value.");
+ const Ref<Resource> &loaded_resource_b_text = loaded_resource_a_text->get_meta("next");
+ CHECK_MESSAGE(
+ loaded_resource_b_text->get_name() == "B",
+ "The loaded child resource name should be equal to the expected value.");
+ const Ref<Resource> &loaded_resource_c_text = loaded_resource_b_text->get_meta("next");
+ CHECK_MESSAGE(
+ 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"),
+ "The loaded child resource circular reference should be NULL.");
+
+ // Break circular reference to avoid memory leak
+ resource_c->remove_meta("next");
+}
} // namespace TestResource
#endif // TEST_RESOURCE_H
diff --git a/tests/core/object/test_object.h b/tests/core/object/test_object.h
index 98f9b3da65..8ab6221a1c 100644
--- a/tests/core/object/test_object.h
+++ b/tests/core/object/test_object.h
@@ -399,6 +399,29 @@ TEST_CASE("[Object] Signals") {
SIGNAL_CHECK("my_custom_signal", empty_signal_args);
SIGNAL_UNWATCH(&object, "my_custom_signal");
}
+
+ SUBCASE("Connecting and then disconnecting many signals should not leave anything behind") {
+ List<Object::Connection> signal_connections;
+ Object targets[100];
+
+ for (int i = 0; i < 10; i++) {
+ ERR_PRINT_OFF;
+ for (Object &target : targets) {
+ object.connect("my_custom_signal", callable_mp(&target, &Object::notify_property_list_changed));
+ }
+ ERR_PRINT_ON;
+ signal_connections.clear();
+ object.get_all_signal_connections(&signal_connections);
+ CHECK(signal_connections.size() == 100);
+ }
+
+ for (Object &target : targets) {
+ object.disconnect("my_custom_signal", callable_mp(&target, &Object::notify_property_list_changed));
+ }
+ signal_connections.clear();
+ object.get_all_signal_connections(&signal_connections);
+ CHECK(signal_connections.size() == 0);
+ }
}
} // namespace TestObject
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index 5a2f871430..93b237788d 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -1095,7 +1095,9 @@ TEST_CASE("[String] pad") {
s = String("10.10");
CHECK(s.pad_decimals(4) == U"10.1000");
+ CHECK(s.pad_decimals(1) == U"10.1");
CHECK(s.pad_zeros(4) == U"0010.10");
+ CHECK(s.pad_zeros(1) == U"10.10");
}
TEST_CASE("[String] is_subsequence_of") {
diff --git a/tests/core/variant/test_array.h b/tests/core/variant/test_array.h
index ccb02ed5fa..228d77b3b5 100644
--- a/tests/core/variant/test_array.h
+++ b/tests/core/variant/test_array.h
@@ -304,13 +304,31 @@ TEST_CASE("[Array] slice()") {
CHECK(slice8[1] == Variant(3));
CHECK(slice8[2] == Variant(1));
+ Array slice9 = array.slice(10, 0, -2);
+ CHECK(slice9.size() == 3);
+ CHECK(slice9[0] == Variant(5));
+ CHECK(slice9[1] == Variant(3));
+ CHECK(slice9[2] == Variant(1));
+
+ Array slice10 = array.slice(2, -10, -1);
+ CHECK(slice10.size() == 3);
+ CHECK(slice10[0] == Variant(2));
+ CHECK(slice10[1] == Variant(1));
+ CHECK(slice10[2] == Variant(0));
+
ERR_PRINT_OFF;
- Array slice9 = array.slice(4, 1);
- CHECK(slice9.size() == 0);
+ Array slice11 = array.slice(4, 1);
+ CHECK(slice11.size() == 0);
- Array slice10 = array.slice(3, -4);
- CHECK(slice10.size() == 0);
+ Array slice12 = array.slice(3, -4);
+ CHECK(slice12.size() == 0);
ERR_PRINT_ON;
+
+ Array slice13 = Array().slice(1);
+ CHECK(slice13.size() == 0);
+
+ Array slice14 = array.slice(6);
+ CHECK(slice14.size() == 0);
}
TEST_CASE("[Array] Duplicate array") {
diff --git a/tests/scene/test_theme.h b/tests/scene/test_theme.h
index 69d29e5ca5..ad1ce1fd50 100644
--- a/tests/scene/test_theme.h
+++ b/tests/scene/test_theme.h
@@ -31,6 +31,8 @@
#ifndef TEST_THEME_H
#define TEST_THEME_H
+#include "scene/resources/image_texture.h"
+#include "scene/resources/style_box_flat.h"
#include "scene/resources/theme.h"
#include "tests/test_tools.h"
diff --git a/tests/scene/test_viewport.h b/tests/scene/test_viewport.h
index d76fc40125..a6b3b2c40c 100644
--- a/tests/scene/test_viewport.h
+++ b/tests/scene/test_viewport.h
@@ -33,6 +33,7 @@
#include "scene/2d/node_2d.h"
#include "scene/gui/control.h"
+#include "scene/gui/subviewport_container.h"
#include "scene/main/window.h"
#include "tests/test_macros.h"
@@ -715,6 +716,46 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
memdelete(node_a);
}
+TEST_CASE("[SceneTree][Viewport] Control mouse cursor shape") {
+ SUBCASE("[Viewport][CursorShape] Mouse cursor is not overridden by SubViewportContainer") {
+ SubViewportContainer *node_a = memnew(SubViewportContainer);
+ SubViewport *node_b = memnew(SubViewport);
+ Control *node_c = memnew(Control);
+
+ node_a->set_name("SubViewportContainer");
+ node_b->set_name("SubViewport");
+ node_c->set_name("Control");
+ node_a->set_position(Point2i(0, 0));
+ node_c->set_position(Point2i(0, 0));
+ node_a->set_size(Point2i(100, 100));
+ node_b->set_size(Point2i(100, 100));
+ node_c->set_size(Point2i(100, 100));
+ node_a->set_default_cursor_shape(Control::CURSOR_ARROW);
+ node_c->set_default_cursor_shape(Control::CURSOR_FORBIDDEN);
+ Window *root = SceneTree::get_singleton()->get_root();
+ DisplayServerMock *DS = (DisplayServerMock *)(DisplayServer::get_singleton());
+
+ // Scene tree:
+ // - root
+ // - node_a (SubViewportContainer)
+ // - node_b (SubViewport)
+ // - node_c (Control)
+
+ root->add_child(node_a);
+ node_a->add_child(node_b);
+ node_b->add_child(node_c);
+
+ Point2i on_c = Point2i(5, 5);
+
+ SEND_GUI_MOUSE_MOTION_EVENT(on_c, MouseButtonMask::NONE, Key::NONE);
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_FORBIDDEN); // GH-74805
+
+ memdelete(node_c);
+ memdelete(node_b);
+ memdelete(node_a);
+ }
+}
+
} // namespace TestViewport
#endif // TEST_VIEWPORT_H
diff --git a/tests/servers/test_navigation_server_3d.h b/tests/servers/test_navigation_server_3d.h
index ffd5b83231..8ea69ec67c 100644
--- a/tests/servers/test_navigation_server_3d.h
+++ b/tests/servers/test_navigation_server_3d.h
@@ -31,11 +31,38 @@
#ifndef TEST_NAVIGATION_SERVER_3D_H
#define TEST_NAVIGATION_SERVER_3D_H
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/resources/primitive_meshes.h"
#include "servers/navigation_server_3d.h"
#include "tests/test_macros.h"
namespace TestNavigationServer3D {
+
+// TODO: Find a more generic way to create `Callable` mocks.
+class CallableMock : public Object {
+ GDCLASS(CallableMock, Object);
+
+public:
+ void function1(Variant arg0) {
+ function1_calls++;
+ function1_latest_arg0 = arg0;
+ }
+
+ unsigned function1_calls{ 0 };
+ Variant function1_latest_arg0{};
+};
+
+static inline Array build_array() {
+ return Array();
+}
+template <typename... Targs>
+static inline Array build_array(Variant item, Targs... Fargs) {
+ Array a = build_array(Fargs...);
+ a.push_front(item);
+ return a;
+}
+
TEST_SUITE("[Navigation]") {
TEST_CASE("[NavigationServer3D] Server should be empty when initialized") {
NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
@@ -56,7 +83,6 @@ TEST_SUITE("[Navigation]") {
TEST_CASE("[NavigationServer3D] Server should manage agent properly") {
NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
- CHECK_EQ(navigation_server->get_maps().size(), 0);
RID agent = navigation_server->agent_create();
CHECK(agent.is_valid());
@@ -69,6 +95,7 @@ TEST_SUITE("[Navigation]") {
bool initial_use_3d_avoidance = navigation_server->agent_get_use_3d_avoidance(agent);
navigation_server->agent_set_use_3d_avoidance(agent, !initial_use_3d_avoidance);
navigation_server->process(0.0); // Give server some cycles to commit.
+
CHECK_EQ(navigation_server->agent_get_use_3d_avoidance(agent), !initial_use_3d_avoidance);
// TODO: Add remaining setters/getters once the missing getters are added.
}
@@ -83,20 +110,40 @@ TEST_SUITE("[Navigation]") {
navigation_server->agent_set_map(agent, RID());
navigation_server->free(map);
navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_AGENT_COUNT), 0);
}
navigation_server->free(agent);
-
- SUBCASE("'ProcessInfo' should not report removed agent") {
- CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_AGENT_COUNT), 0);
- }
}
TEST_CASE("[NavigationServer3D] Server should manage map properly") {
NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
- CHECK_EQ(navigation_server->get_maps().size(), 0);
- RID map = navigation_server->map_create();
+ RID map;
+ CHECK_FALSE(map.is_valid());
+
+ SUBCASE("Queries against invalid map should return empty or invalid values") {
+ CHECK_EQ(navigation_server->map_get_closest_point(map, Vector3(7, 7, 7)), Vector3());
+ CHECK_EQ(navigation_server->map_get_closest_point_normal(map, Vector3(7, 7, 7)), Vector3());
+ CHECK_FALSE(navigation_server->map_get_closest_point_owner(map, Vector3(7, 7, 7)).is_valid());
+ CHECK_EQ(navigation_server->map_get_closest_point_to_segment(map, Vector3(7, 7, 7), Vector3(8, 8, 8), true), Vector3());
+ CHECK_EQ(navigation_server->map_get_closest_point_to_segment(map, Vector3(7, 7, 7), Vector3(8, 8, 8), false), Vector3());
+ CHECK_EQ(navigation_server->map_get_path(map, Vector3(7, 7, 7), Vector3(8, 8, 8), true).size(), 0);
+ CHECK_EQ(navigation_server->map_get_path(map, Vector3(7, 7, 7), Vector3(8, 8, 8), false).size(), 0);
+
+ Ref<NavigationPathQueryParameters3D> query_parameters = memnew(NavigationPathQueryParameters3D);
+ query_parameters->set_map(map);
+ query_parameters->set_start_position(Vector3(7, 7, 7));
+ query_parameters->set_target_position(Vector3(8, 8, 8));
+ Ref<NavigationPathQueryResult3D> query_result = memnew(NavigationPathQueryResult3D);
+ navigation_server->query_path(query_parameters, query_result);
+ CHECK_EQ(query_result->get_path().size(), 0);
+ CHECK_EQ(query_result->get_path_types().size(), 0);
+ CHECK_EQ(query_result->get_path_rids().size(), 0);
+ CHECK_EQ(query_result->get_path_owner_ids().size(), 0);
+ }
+
+ map = navigation_server->map_create();
CHECK(map.is_valid());
CHECK_EQ(navigation_server->get_maps().size(), 1);
@@ -112,6 +159,7 @@ TEST_SUITE("[Navigation]") {
bool initial_use_edge_connections = navigation_server->map_get_use_edge_connections(map);
navigation_server->map_set_use_edge_connections(map, !initial_use_edge_connections);
navigation_server->process(0.0); // Give server some cycles to commit.
+
CHECK_EQ(navigation_server->map_get_cell_size(map), doctest::Approx(0.55));
CHECK_EQ(navigation_server->map_get_edge_connection_margin(map), doctest::Approx(0.66));
CHECK_EQ(navigation_server->map_get_link_connection_radius(map), doctest::Approx(0.77));
@@ -140,10 +188,429 @@ TEST_SUITE("[Navigation]") {
CHECK_EQ(navigation_server->map_get_agents(map).size(), 0);
}
+ SUBCASE("Number of links should be reported properly") {
+ RID link = navigation_server->link_create();
+ CHECK(link.is_valid());
+ navigation_server->link_set_map(link, map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->map_get_links(map).size(), 1);
+ navigation_server->free(link);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->map_get_links(map).size(), 0);
+ }
+
+ SUBCASE("Number of obstacles should be reported properly") {
+ RID obstacle = navigation_server->obstacle_create();
+ CHECK(obstacle.is_valid());
+ navigation_server->obstacle_set_map(obstacle, map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->map_get_obstacles(map).size(), 1);
+ navigation_server->free(obstacle);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->map_get_obstacles(map).size(), 0);
+ }
+
+ SUBCASE("Number of regions should be reported properly") {
+ RID region = navigation_server->region_create();
+ CHECK(region.is_valid());
+ navigation_server->region_set_map(region, map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->map_get_regions(map).size(), 1);
+ navigation_server->free(region);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->map_get_regions(map).size(), 0);
+ }
+
+ SUBCASE("Queries against empty map should return empty or invalid values") {
+ navigation_server->map_set_active(map, true);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+
+ CHECK_EQ(navigation_server->map_get_closest_point(map, Vector3(7, 7, 7)), Vector3());
+ CHECK_EQ(navigation_server->map_get_closest_point_normal(map, Vector3(7, 7, 7)), Vector3());
+ CHECK_FALSE(navigation_server->map_get_closest_point_owner(map, Vector3(7, 7, 7)).is_valid());
+ CHECK_EQ(navigation_server->map_get_closest_point_to_segment(map, Vector3(7, 7, 7), Vector3(8, 8, 8), true), Vector3());
+ CHECK_EQ(navigation_server->map_get_closest_point_to_segment(map, Vector3(7, 7, 7), Vector3(8, 8, 8), false), Vector3());
+ CHECK_EQ(navigation_server->map_get_path(map, Vector3(7, 7, 7), Vector3(8, 8, 8), true).size(), 0);
+ CHECK_EQ(navigation_server->map_get_path(map, Vector3(7, 7, 7), Vector3(8, 8, 8), false).size(), 0);
+
+ Ref<NavigationPathQueryParameters3D> query_parameters = memnew(NavigationPathQueryParameters3D);
+ query_parameters->set_map(map);
+ query_parameters->set_start_position(Vector3(7, 7, 7));
+ query_parameters->set_target_position(Vector3(8, 8, 8));
+ Ref<NavigationPathQueryResult3D> query_result = memnew(NavigationPathQueryResult3D);
+ navigation_server->query_path(query_parameters, query_result);
+ CHECK_EQ(query_result->get_path().size(), 0);
+ CHECK_EQ(query_result->get_path_types().size(), 0);
+ CHECK_EQ(query_result->get_path_rids().size(), 0);
+ CHECK_EQ(query_result->get_path_owner_ids().size(), 0);
+
+ navigation_server->map_set_active(map, false);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ }
+
navigation_server->free(map);
navigation_server->process(0.0); // Give server some cycles to actually remove map.
CHECK_EQ(navigation_server->get_maps().size(), 0);
}
+
+ TEST_CASE("[NavigationServer3D] Server should manage link properly") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ RID link = navigation_server->link_create();
+ CHECK(link.is_valid());
+
+ SUBCASE("'ProcessInfo' should not report dangling link") {
+ CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_LINK_COUNT), 0);
+ }
+
+ SUBCASE("Setters/getters should work") {
+ bool initial_bidirectional = navigation_server->link_is_bidirectional(link);
+ navigation_server->link_set_bidirectional(link, !initial_bidirectional);
+ navigation_server->link_set_end_position(link, Vector3(7, 7, 7));
+ navigation_server->link_set_enter_cost(link, 0.55);
+ navigation_server->link_set_navigation_layers(link, 6);
+ navigation_server->link_set_owner_id(link, ObjectID((int64_t)7));
+ navigation_server->link_set_start_position(link, Vector3(8, 8, 8));
+ navigation_server->link_set_travel_cost(link, 0.66);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+
+ CHECK_EQ(navigation_server->link_is_bidirectional(link), !initial_bidirectional);
+ CHECK_EQ(navigation_server->link_get_end_position(link), Vector3(7, 7, 7));
+ CHECK_EQ(navigation_server->link_get_enter_cost(link), doctest::Approx(0.55));
+ CHECK_EQ(navigation_server->link_get_navigation_layers(link), 6);
+ CHECK_EQ(navigation_server->link_get_owner_id(link), ObjectID((int64_t)7));
+ CHECK_EQ(navigation_server->link_get_start_position(link), Vector3(8, 8, 8));
+ CHECK_EQ(navigation_server->link_get_travel_cost(link), doctest::Approx(0.66));
+ }
+
+ SUBCASE("'ProcessInfo' should report link with active map") {
+ RID map = navigation_server->map_create();
+ CHECK(map.is_valid());
+ navigation_server->map_set_active(map, true);
+ navigation_server->link_set_map(link, map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_LINK_COUNT), 1);
+ navigation_server->link_set_map(link, RID());
+ navigation_server->free(map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_LINK_COUNT), 0);
+ }
+
+ navigation_server->free(link);
+ }
+
+ TEST_CASE("[NavigationServer3D] Server should manage obstacles properly") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ RID obstacle = navigation_server->obstacle_create();
+ CHECK(obstacle.is_valid());
+
+ // TODO: Add tests for setters/getters once getters are added.
+
+ navigation_server->free(obstacle);
+ }
+
+ TEST_CASE("[NavigationServer3D] Server should manage regions properly") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ RID region = navigation_server->region_create();
+ CHECK(region.is_valid());
+
+ SUBCASE("'ProcessInfo' should not report dangling region") {
+ CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_REGION_COUNT), 0);
+ }
+
+ SUBCASE("Setters/getters should work") {
+ bool initial_use_edge_connections = navigation_server->region_get_use_edge_connections(region);
+ navigation_server->region_set_enter_cost(region, 0.55);
+ navigation_server->region_set_navigation_layers(region, 5);
+ navigation_server->region_set_owner_id(region, ObjectID((int64_t)7));
+ navigation_server->region_set_travel_cost(region, 0.66);
+ navigation_server->region_set_use_edge_connections(region, !initial_use_edge_connections);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+
+ CHECK_EQ(navigation_server->region_get_enter_cost(region), doctest::Approx(0.55));
+ CHECK_EQ(navigation_server->region_get_navigation_layers(region), 5);
+ CHECK_EQ(navigation_server->region_get_owner_id(region), ObjectID((int64_t)7));
+ CHECK_EQ(navigation_server->region_get_travel_cost(region), doctest::Approx(0.66));
+ CHECK_EQ(navigation_server->region_get_use_edge_connections(region), !initial_use_edge_connections);
+ }
+
+ SUBCASE("'ProcessInfo' should report region with active map") {
+ RID map = navigation_server->map_create();
+ CHECK(map.is_valid());
+ navigation_server->map_set_active(map, true);
+ navigation_server->region_set_map(region, map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_REGION_COUNT), 1);
+ navigation_server->region_set_map(region, RID());
+ navigation_server->free(map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_REGION_COUNT), 0);
+ }
+
+ SUBCASE("Queries against empty region should return empty or invalid values") {
+ CHECK_EQ(navigation_server->region_get_connections_count(region), 0);
+ CHECK_EQ(navigation_server->region_get_connection_pathway_end(region, 55), Vector3());
+ CHECK_EQ(navigation_server->region_get_connection_pathway_start(region, 55), Vector3());
+ }
+
+ navigation_server->free(region);
+ }
+
+ // This test case does not check precise values on purpose - to not be too sensitivte.
+ TEST_CASE("[NavigationServer3D] Server should move agent properly") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ RID map = navigation_server->map_create();
+ RID agent = navigation_server->agent_create();
+
+ navigation_server->map_set_active(map, true);
+ navigation_server->agent_set_map(agent, map);
+ navigation_server->agent_set_avoidance_enabled(agent, true);
+ navigation_server->agent_set_velocity(agent, Vector3(1, 0, 1));
+ CallableMock agent_avoidance_callback_mock;
+ navigation_server->agent_set_avoidance_callback(agent, callable_mp(&agent_avoidance_callback_mock, &CallableMock::function1));
+ CHECK_EQ(agent_avoidance_callback_mock.function1_calls, 0);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(agent_avoidance_callback_mock.function1_calls, 1);
+ CHECK_NE(agent_avoidance_callback_mock.function1_latest_arg0, Vector3(0, 0, 0));
+
+ navigation_server->free(agent);
+ navigation_server->free(map);
+ }
+
+ // This test case does not check precise values on purpose - to not be too sensitivte.
+ TEST_CASE("[NavigationServer3D] Server should make agents avoid each other when avoidance enabled") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ RID map = navigation_server->map_create();
+ RID agent_1 = navigation_server->agent_create();
+ RID agent_2 = navigation_server->agent_create();
+
+ navigation_server->map_set_active(map, true);
+
+ navigation_server->agent_set_map(agent_1, map);
+ navigation_server->agent_set_avoidance_enabled(agent_1, true);
+ navigation_server->agent_set_position(agent_1, Vector3(0, 0, 0));
+ navigation_server->agent_set_radius(agent_1, 1);
+ navigation_server->agent_set_velocity(agent_1, Vector3(1, 0, 0));
+ CallableMock agent_1_avoidance_callback_mock;
+ navigation_server->agent_set_avoidance_callback(agent_1, callable_mp(&agent_1_avoidance_callback_mock, &CallableMock::function1));
+
+ navigation_server->agent_set_map(agent_2, map);
+ navigation_server->agent_set_avoidance_enabled(agent_2, true);
+ navigation_server->agent_set_position(agent_2, Vector3(2.5, 0, 0.5));
+ navigation_server->agent_set_radius(agent_2, 1);
+ navigation_server->agent_set_velocity(agent_2, Vector3(-1, 0, 0));
+ CallableMock agent_2_avoidance_callback_mock;
+ navigation_server->agent_set_avoidance_callback(agent_2, callable_mp(&agent_2_avoidance_callback_mock, &CallableMock::function1));
+
+ CHECK_EQ(agent_1_avoidance_callback_mock.function1_calls, 0);
+ CHECK_EQ(agent_2_avoidance_callback_mock.function1_calls, 0);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(agent_1_avoidance_callback_mock.function1_calls, 1);
+ CHECK_EQ(agent_2_avoidance_callback_mock.function1_calls, 1);
+ Vector3 agent_1_safe_velocity = agent_1_avoidance_callback_mock.function1_latest_arg0;
+ Vector3 agent_2_safe_velocity = agent_2_avoidance_callback_mock.function1_latest_arg0;
+ CHECK_MESSAGE(agent_1_safe_velocity.x > 0, "agent 1 should move a bit along desired velocity (+X)");
+ CHECK_MESSAGE(agent_2_safe_velocity.x < 0, "agent 2 should move a bit along desired velocity (-X)");
+ CHECK_MESSAGE(agent_1_safe_velocity.z < 0, "agent 1 should move a bit to the side so that it avoids agent 2");
+ CHECK_MESSAGE(agent_2_safe_velocity.z > 0, "agent 2 should move a bit to the side so that it avoids agent 1");
+
+ navigation_server->free(agent_2);
+ navigation_server->free(agent_1);
+ navigation_server->free(map);
+ }
+
+ // This test case uses only public APIs on purpose - other test cases use simplified baking.
+ // FIXME: Remove once deprecated `region_bake_navigation_mesh()` is removed.
+ TEST_CASE("[NavigationServer3D][SceneTree][DEPRECATED] Server should be able to bake map correctly") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ // Prepare scene tree with simple mesh to serve as an input geometry.
+ Node3D *node_3d = memnew(Node3D);
+ SceneTree::get_singleton()->get_root()->add_child(node_3d);
+ Ref<PlaneMesh> plane_mesh = memnew(PlaneMesh);
+ plane_mesh->set_size(Size2(10.0, 10.0));
+ MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
+ mesh_instance->set_mesh(plane_mesh);
+ node_3d->add_child(mesh_instance);
+
+ // Prepare anything necessary to bake navigation mesh.
+ RID map = navigation_server->map_create();
+ RID region = navigation_server->region_create();
+ Ref<NavigationMesh> navigation_mesh = memnew(NavigationMesh);
+ navigation_server->map_set_active(map, true);
+ navigation_server->region_set_map(region, map);
+ navigation_server->region_set_navigation_mesh(region, navigation_mesh);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+
+ CHECK_EQ(navigation_mesh->get_polygon_count(), 0);
+ CHECK_EQ(navigation_mesh->get_vertices().size(), 0);
+
+ navigation_server->region_bake_navigation_mesh(navigation_mesh, node_3d);
+ // FIXME: The above line should trigger the update (line below) under the hood.
+ navigation_server->region_set_navigation_mesh(region, navigation_mesh); // Force update.
+ CHECK_EQ(navigation_mesh->get_polygon_count(), 2);
+ CHECK_EQ(navigation_mesh->get_vertices().size(), 4);
+
+ SUBCASE("Map should emit signal and take newly baked navigation mesh into account") {
+ SIGNAL_WATCH(navigation_server, "map_changed");
+ SIGNAL_CHECK_FALSE("map_changed");
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ SIGNAL_CHECK("map_changed", build_array(build_array(map)));
+ SIGNAL_UNWATCH(navigation_server, "map_changed");
+ CHECK_NE(navigation_server->map_get_closest_point(map, Vector3(0, 0, 0)), Vector3(0, 0, 0));
+ }
+
+ navigation_server->free(region);
+ navigation_server->free(map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ memdelete(mesh_instance);
+ memdelete(node_3d);
+ }
+
+ // This test case uses only public APIs on purpose - other test cases use simplified baking.
+ TEST_CASE("[NavigationServer3D][SceneTree] Server should be able to bake map correctly") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ // Prepare scene tree with simple mesh to serve as an input geometry.
+ Node3D *node_3d = memnew(Node3D);
+ SceneTree::get_singleton()->get_root()->add_child(node_3d);
+ Ref<PlaneMesh> plane_mesh = memnew(PlaneMesh);
+ plane_mesh->set_size(Size2(10.0, 10.0));
+ MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
+ mesh_instance->set_mesh(plane_mesh);
+ node_3d->add_child(mesh_instance);
+
+ // Prepare anything necessary to bake navigation mesh.
+ RID map = navigation_server->map_create();
+ RID region = navigation_server->region_create();
+ Ref<NavigationMesh> navigation_mesh = memnew(NavigationMesh);
+ navigation_server->map_set_active(map, true);
+ navigation_server->region_set_map(region, map);
+ navigation_server->region_set_navigation_mesh(region, navigation_mesh);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+
+ CHECK_EQ(navigation_mesh->get_polygon_count(), 0);
+ CHECK_EQ(navigation_mesh->get_vertices().size(), 0);
+
+ Ref<NavigationMeshSourceGeometryData3D> source_geometry = memnew(NavigationMeshSourceGeometryData3D);
+ navigation_server->parse_source_geometry_data(navigation_mesh, source_geometry, node_3d);
+ navigation_server->bake_from_source_geometry_data(navigation_mesh, source_geometry, Callable());
+ // FIXME: The above line should trigger the update (line below) under the hood.
+ navigation_server->region_set_navigation_mesh(region, navigation_mesh); // Force update.
+ CHECK_EQ(navigation_mesh->get_polygon_count(), 2);
+ CHECK_EQ(navigation_mesh->get_vertices().size(), 4);
+
+ SUBCASE("Map should emit signal and take newly baked navigation mesh into account") {
+ SIGNAL_WATCH(navigation_server, "map_changed");
+ SIGNAL_CHECK_FALSE("map_changed");
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ SIGNAL_CHECK("map_changed", build_array(build_array(map)));
+ SIGNAL_UNWATCH(navigation_server, "map_changed");
+ CHECK_NE(navigation_server->map_get_closest_point(map, Vector3(0, 0, 0)), Vector3(0, 0, 0));
+ }
+
+ navigation_server->free(region);
+ navigation_server->free(map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ memdelete(mesh_instance);
+ memdelete(node_3d);
+ }
+
+ // This test case does not check precise values on purpose - to not be too sensitivte.
+ TEST_CASE("[NavigationServer3D] Server should respond to queries against valid map properly") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+ Ref<NavigationMesh> navigation_mesh = memnew(NavigationMesh);
+ Ref<NavigationMeshSourceGeometryData3D> source_geometry = memnew(NavigationMeshSourceGeometryData3D);
+
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(arr, Vector3(10.0, 0.001, 10.0));
+ source_geometry->add_mesh_array(arr, Transform3D());
+ navigation_server->bake_from_source_geometry_data(navigation_mesh, source_geometry, Callable());
+ CHECK_NE(navigation_mesh->get_polygon_count(), 0);
+ CHECK_NE(navigation_mesh->get_vertices().size(), 0);
+
+ RID map = navigation_server->map_create();
+ RID region = navigation_server->region_create();
+ navigation_server->map_set_active(map, true);
+ navigation_server->region_set_map(region, map);
+ navigation_server->region_set_navigation_mesh(region, navigation_mesh);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+
+ SUBCASE("Simple queries should return non-default values") {
+ CHECK_NE(navigation_server->map_get_closest_point(map, Vector3(0, 0, 0)), Vector3(0, 0, 0));
+ CHECK_NE(navigation_server->map_get_closest_point_normal(map, Vector3(0, 0, 0)), Vector3());
+ CHECK(navigation_server->map_get_closest_point_owner(map, Vector3(0, 0, 0)).is_valid());
+ // TODO: Test map_get_closest_point_to_segment() with p_use_collision=true as well.
+ CHECK_NE(navigation_server->map_get_closest_point_to_segment(map, Vector3(0, 0, 0), Vector3(1, 1, 1), false), Vector3());
+ CHECK_NE(navigation_server->map_get_path(map, Vector3(0, 0, 0), Vector3(10, 0, 10), true).size(), 0);
+ CHECK_NE(navigation_server->map_get_path(map, Vector3(0, 0, 0), Vector3(10, 0, 10), false).size(), 0);
+ }
+
+ SUBCASE("Elaborate query with 'CORRIDORFUNNEL' post-processing should yield non-empty result") {
+ Ref<NavigationPathQueryParameters3D> query_parameters = memnew(NavigationPathQueryParameters3D);
+ query_parameters->set_map(map);
+ query_parameters->set_start_position(Vector3(0, 0, 0));
+ query_parameters->set_target_position(Vector3(10, 0, 10));
+ query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PATH_POSTPROCESSING_CORRIDORFUNNEL);
+ Ref<NavigationPathQueryResult3D> query_result = memnew(NavigationPathQueryResult3D);
+ navigation_server->query_path(query_parameters, query_result);
+ CHECK_NE(query_result->get_path().size(), 0);
+ CHECK_NE(query_result->get_path_types().size(), 0);
+ CHECK_NE(query_result->get_path_rids().size(), 0);
+ CHECK_NE(query_result->get_path_owner_ids().size(), 0);
+ }
+
+ SUBCASE("Elaborate query with 'EDGECENTERED' post-processing should yield non-empty result") {
+ Ref<NavigationPathQueryParameters3D> query_parameters = memnew(NavigationPathQueryParameters3D);
+ query_parameters->set_map(map);
+ query_parameters->set_start_position(Vector3(10, 0, 10));
+ query_parameters->set_target_position(Vector3(0, 0, 0));
+ query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PATH_POSTPROCESSING_EDGECENTERED);
+ Ref<NavigationPathQueryResult3D> query_result = memnew(NavigationPathQueryResult3D);
+ navigation_server->query_path(query_parameters, query_result);
+ CHECK_NE(query_result->get_path().size(), 0);
+ CHECK_NE(query_result->get_path_types().size(), 0);
+ CHECK_NE(query_result->get_path_rids().size(), 0);
+ CHECK_NE(query_result->get_path_owner_ids().size(), 0);
+ }
+
+ SUBCASE("Elaborate query with non-matching navigation layer mask should yield empty result") {
+ Ref<NavigationPathQueryParameters3D> query_parameters = memnew(NavigationPathQueryParameters3D);
+ query_parameters->set_map(map);
+ query_parameters->set_start_position(Vector3(10, 0, 10));
+ query_parameters->set_target_position(Vector3(0, 0, 0));
+ query_parameters->set_navigation_layers(2);
+ Ref<NavigationPathQueryResult3D> query_result = memnew(NavigationPathQueryResult3D);
+ navigation_server->query_path(query_parameters, query_result);
+ CHECK_EQ(query_result->get_path().size(), 0);
+ CHECK_EQ(query_result->get_path_types().size(), 0);
+ CHECK_EQ(query_result->get_path_rids().size(), 0);
+ CHECK_EQ(query_result->get_path_owner_ids().size(), 0);
+ }
+
+ SUBCASE("Elaborate query without metadata flags should yield path only") {
+ Ref<NavigationPathQueryParameters3D> query_parameters = memnew(NavigationPathQueryParameters3D);
+ query_parameters->set_map(map);
+ query_parameters->set_start_position(Vector3(10, 0, 10));
+ query_parameters->set_target_position(Vector3(0, 0, 0));
+ query_parameters->set_metadata_flags(0);
+ Ref<NavigationPathQueryResult3D> query_result = memnew(NavigationPathQueryResult3D);
+ navigation_server->query_path(query_parameters, query_result);
+ CHECK_NE(query_result->get_path().size(), 0);
+ CHECK_EQ(query_result->get_path_types().size(), 0);
+ CHECK_EQ(query_result->get_path_rids().size(), 0);
+ CHECK_EQ(query_result->get_path_owner_ids().size(), 0);
+ }
+
+ navigation_server->free(region);
+ navigation_server->free(map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ }
}
} //namespace TestNavigationServer3D
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 2e99e6fdb6..96ee146e77 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -31,6 +31,7 @@
#include "test_main.h"
#include "tests/core/config/test_project_settings.h"
+#include "tests/core/input/test_input_event.h"
#include "tests/core/input/test_input_event_key.h"
#include "tests/core/input/test_input_event_mouse.h"
#include "tests/core/input/test_shortcut.h"
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 0d5f3dd4c4..a918acbe77 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -115,7 +115,7 @@ commits.
## enet
- Upstream: http://enet.bespin.org
-- Version: 1.3.17 (e0e7045b7e056b454b5093cb34df49dc4cee0bee, 2020)
+- Version: git (ea4607a90dbfbcf4da2669ea998585253d8e70b1, 2023)
- License: MIT
Files extracted from upstream source:
@@ -178,7 +178,7 @@ Files extracted from upstream source:
## freetype
- Upstream: https://www.freetype.org
-- Version: 2.13.0 (de8b92dd7ec634e9e2b25ef534c54a3537555c11, 2023)
+- Version: 2.13.1 (e4586d960f339cf75e2e0b34aee30a0ed8353c0d, 2023)
- License: FreeType License (BSD-like)
Files extracted from upstream source:
@@ -250,7 +250,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 7.3.0 (4584bcdc326564829d3cee3572386c90e4fd1974, 2023)
+- Version: 8.0.0 (b4305532a7746422e0b615eee6304119c1092fd8, 2023)
- License: MIT
Files extracted from upstream source:
@@ -258,13 +258,13 @@ Files extracted from upstream source:
- `AUTHORS`, `COPYING`, `THANKS`
- from the `src` folder, recursively
- all the `*.c`, `*.cc`, `*.h`, `*.hh` files
- - _except_ `main.cc`, `harfbuzz*.cc`, `failing-alloc.c`, `test*.cc`
+ - _except_ `main.cc`, `harfbuzz*.cc`, `failing-alloc.c`, `test*.cc`, `hb-wasm*.*`
## icu4c
- Upstream: https://github.com/unicode-org/icu
-- Version: 73.1 (5861e1fd52f1d7673eee38bc3c965aa18b336062, 2023)
+- Version: 73.2 (680f521746a3bd6a86f25f25ee50a62d88b489cf, 2023)
- License: Unicode
Files extracted from upstream source:
@@ -280,10 +280,11 @@ Files generated from upstream source:
https://github.com/unicode-org/icu/blob/master/docs/userguide/icu_data/buildtool.md
for instructions).
-- Step 1: Build ICU with default options - `./runConfigureICU {PLATFORM} && make`.
-- Step 2: Reconfigure ICU with custom data config - `ICU_DATA_FILTER_FILE={GODOT_SOURCE}/thirdparty/icu4c/godot_data.json ./runConfigureICU {PLATFORM} --with-data-packaging=common`.
-- Step 3: Delete `data/out` folder and rebuild data - `cd data && rm -rf ./out && make`.
-- Step 4: Copy `source/data/out/icudt73l.dat` to the `{GODOT_SOURCE}/thirdparty/icu4c/icudt73l.dat`.
+- Step 1: Download and extract both `icu4c-{version}-src.tgz` and `icu4c-{version}-data.zip` (replace `data` subfolder from the main source archive).
+- Step 2: Build ICU with default options - `./runConfigureICU {PLATFORM} && make`.
+- Step 3: Reconfigure ICU with custom data config - `ICU_DATA_FILTER_FILE={GODOT_SOURCE}/thirdparty/icu4c/godot_data.json ./runConfigureICU {PLATFORM} --with-data-packaging=common`.
+- Step 4: Delete `data/out` folder and rebuild data - `cd data && rm -rf ./out && make`.
+- Step 5: Copy `source/data/out/icudt73l.dat` to the `{GODOT_SOURCE}/thirdparty/icu4c/icudt73l.dat`.
## jpeg-compressor
@@ -582,7 +583,7 @@ Patch files are provided in `oidn/patches/`.
## openxr
- Upstream: https://github.com/KhronosGroup/OpenXR-SDK
-- Version: 1.0.26 (e2da9ce83a4388c9622da328bf48548471261290, 2022)
+- Version: 1.0.28 (f5beb0131f1bea8701ace744d1b50df9049bf331, 2023)
- License: Apache 2.0
Files extracted from upstream source:
@@ -600,7 +601,8 @@ Exclude:
- src/external/android-jni-wrappers and src/external/jnipp (not used yet)
- All CMake stuff: cmake/, CMakeLists.txt and *.cmake
- All Gradle stuff: *gradle*, AndroidManifest.xml
-- All following files (and their .license files): *.{def,in,json,map,pom,rc}
+- All following files (and their .license files): *.{def,expsym,in,json,map,pom,rc,txt}
+- All dotfiles
## pcre2
@@ -639,13 +641,13 @@ Files extracted from upstream source:
For 2D in `rvo2_2d` folder
- Upstream: https://github.com/snape/RVO2
-- Version: git (5961f05ed310f3a5e902aa70ad54e010ba6dcdfd, 2022)
+- Version: git (f7c5380235f6c9ac8d19cbf71fc94e2d4758b0a3, 2021)
- License: Apache 2.0
For 3D in `rvo2_3d` folder
- Upstream: https://github.com/snape/RVO2-3D
-- Version: git (8be355eb84dc763267b5acf7070d6d623d752e51, 2022)
+- Version: git (bfc048670a4e85066e86a1f923d8ea92e3add3b2, 2021)
- License: Apache 2.0
Files extracted from upstream source:
diff --git a/thirdparty/enet/enet/enet.h b/thirdparty/enet/enet/enet.h
index 77f8004b80..5232f8a869 100644
--- a/thirdparty/enet/enet/enet.h
+++ b/thirdparty/enet/enet/enet.h
@@ -68,7 +68,8 @@ typedef enum _ENetSocketOption
ENET_SOCKOPT_RCVTIMEO = 6,
ENET_SOCKOPT_SNDTIMEO = 7,
ENET_SOCKOPT_ERROR = 8,
- ENET_SOCKOPT_NODELAY = 9
+ ENET_SOCKOPT_NODELAY = 9,
+ ENET_SOCKOPT_TTL = 10
} ENetSocketOption;
typedef enum _ENetSocketShutdown
@@ -179,7 +180,7 @@ typedef struct _ENetOutgoingCommand
enet_uint16 unreliableSequenceNumber;
enet_uint32 sentTime;
enet_uint32 roundTripTimeout;
- enet_uint32 roundTripTimeoutLimit;
+ enet_uint32 queueTime;
enet_uint32 fragmentOffset;
enet_uint16 fragmentLength;
enet_uint16 sendAttempts;
@@ -222,7 +223,7 @@ enum
ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024,
ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024,
ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000,
- ENET_HOST_DEFAULT_MTU = 1400,
+ ENET_HOST_DEFAULT_MTU = 1392,
ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024,
ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024,
@@ -262,7 +263,8 @@ typedef struct _ENetChannel
typedef enum _ENetPeerFlag
{
- ENET_PEER_FLAG_NEEDS_DISPATCH = (1 << 0)
+ ENET_PEER_FLAG_NEEDS_DISPATCH = (1 << 0),
+ ENET_PEER_FLAG_CONTINUE_SENDING = (1 << 1)
} ENetPeerFlag;
/**
@@ -322,7 +324,7 @@ typedef struct _ENetPeer
enet_uint16 outgoingReliableSequenceNumber;
ENetList acknowledgements;
ENetList sentReliableCommands;
- ENetList sentUnreliableCommands;
+ ENetList outgoingSendReliableCommands;
ENetList outgoingCommands;
ENetList dispatchedCommands;
enet_uint16 flags;
@@ -385,7 +387,7 @@ typedef struct _ENetHost
size_t channelLimit; /**< maximum number of channels allowed for connected peers */
enet_uint32 serviceTime;
ENetList dispatchQueue;
- int continueSending;
+ enet_uint32 totalQueued;
size_t packetSize;
enet_uint16 headerFlags;
ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS];
@@ -585,6 +587,7 @@ ENET_API void enet_host_channel_limit (ENetHost *, size_t);
ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32);
extern void enet_host_bandwidth_throttle (ENetHost *);
extern enet_uint32 enet_host_random_seed (void);
+extern enet_uint32 enet_host_random (ENetHost *);
ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *);
ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID);
@@ -598,6 +601,7 @@ ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32
ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
extern int enet_peer_throttle (ENetPeer *, enet_uint32);
extern void enet_peer_reset_queues (ENetPeer *);
+extern int enet_peer_has_outgoing_commands (ENetPeer *);
extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *);
extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16);
extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32);
diff --git a/thirdparty/enet/godot.cpp b/thirdparty/enet/godot.cpp
index 2cbfe59fc6..9ce126a475 100644
--- a/thirdparty/enet/godot.cpp
+++ b/thirdparty/enet/godot.cpp
@@ -535,6 +535,10 @@ int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buf
if (err == ERR_BUSY) {
return 0;
}
+ if (err == ERR_OUT_OF_MEMORY) {
+ // A packet above the ENET_PROTOCOL_MAXIMUM_MTU was received.
+ return -2;
+ }
if (err != OK) {
return -1;
diff --git a/thirdparty/enet/host.c b/thirdparty/enet/host.c
index 21ab27e247..adb3533cf1 100644
--- a/thirdparty/enet/host.c
+++ b/thirdparty/enet/host.c
@@ -96,6 +96,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
host -> totalSentPackets = 0;
host -> totalReceivedData = 0;
host -> totalReceivedPackets = 0;
+ host -> totalQueued = 0;
host -> connectedPeers = 0;
host -> bandwidthLimitedPeers = 0;
@@ -123,8 +124,8 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
enet_list_clear (& currentPeer -> acknowledgements);
enet_list_clear (& currentPeer -> sentReliableCommands);
- enet_list_clear (& currentPeer -> sentUnreliableCommands);
enet_list_clear (& currentPeer -> outgoingCommands);
+ enet_list_clear (& currentPeer -> outgoingSendReliableCommands);
enet_list_clear (& currentPeer -> dispatchedCommands);
enet_peer_reset (currentPeer);
@@ -160,6 +161,16 @@ enet_host_destroy (ENetHost * host)
enet_free (host);
}
+enet_uint32
+enet_host_random (ENetHost * host)
+{
+ /* Mulberry32 by Tommy Ettinger */
+ enet_uint32 n = (host -> randomSeed += 0x6D2B79F5U);
+ n = (n ^ (n >> 15)) * (n | 1U);
+ n ^= n + (n ^ (n >> 7)) * (n | 61U);
+ return n ^ (n >> 14);
+}
+
/** Initiates a connection to a foreign host.
@param host host seeking the connection
@param address destination for the connection
@@ -199,7 +210,8 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC
currentPeer -> channelCount = channelCount;
currentPeer -> state = ENET_PEER_STATE_CONNECTING;
currentPeer -> address = * address;
- currentPeer -> connectID = ++ host -> randomSeed;
+ currentPeer -> connectID = enet_host_random (host);
+ currentPeer -> mtu = host -> mtu;
if (host -> outgoingBandwidth == 0)
currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
diff --git a/thirdparty/enet/packet.c b/thirdparty/enet/packet.c
index 5fa78b28ae..d51c640404 100644
--- a/thirdparty/enet/packet.c
+++ b/thirdparty/enet/packet.c
@@ -98,53 +98,46 @@ enet_packet_resize (ENetPacket * packet, size_t dataLength)
return 0;
}
-static int initializedCRC32 = 0;
-static enet_uint32 crcTable [256];
-
-static enet_uint32
-reflect_crc (int val, int bits)
+static const enet_uint32 crcTable [256] =
{
- int result = 0, bit;
-
- for (bit = 0; bit < bits; bit ++)
- {
- if(val & 1) result |= 1 << (bits - 1 - bit);
- val >>= 1;
- }
-
- return result;
-}
-
-static void
-initialize_crc32 (void)
-{
- int byte;
-
- for (byte = 0; byte < 256; ++ byte)
- {
- enet_uint32 crc = reflect_crc (byte, 8) << 24;
- int offset;
+ 0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x5005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0xBDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
- for(offset = 0; offset < 8; ++ offset)
- {
- if (crc & 0x80000000)
- crc = (crc << 1) ^ 0x04c11db7;
- else
- crc <<= 1;
- }
-
- crcTable [byte] = reflect_crc (crc, 32);
- }
-
- initializedCRC32 = 1;
-}
-
enet_uint32
enet_crc32 (const ENetBuffer * buffers, size_t bufferCount)
{
enet_uint32 crc = 0xFFFFFFFF;
-
- if (! initializedCRC32) initialize_crc32 ();
while (bufferCount -- > 0)
{
@@ -153,7 +146,7 @@ enet_crc32 (const ENetBuffer * buffers, size_t bufferCount)
while (data < dataEnd)
{
- crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++];
+ crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++];
}
++ buffers;
diff --git a/thirdparty/enet/peer.c b/thirdparty/enet/peer.c
index 9370ef4be1..a7ac012079 100644
--- a/thirdparty/enet/peer.c
+++ b/thirdparty/enet/peer.c
@@ -90,6 +90,13 @@ enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt)
}
/** Queues a packet to be sent.
+
+ On success, ENet will assume ownership of the packet, and so enet_packet_destroy
+ should not be called on it thereafter. On failure, the caller still must destroy
+ the packet on its own as ENet has not queued the packet. The caller can also
+ check the packet's referenceCount field after sending to check if ENet queued
+ the packet and thus incremented the referenceCount.
+
@param peer destination for the packet
@param channelID channel on which to send
@param packet packet to send
@@ -99,7 +106,7 @@ enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt)
int
enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
{
- ENetChannel * channel = & peer -> channels [channelID];
+ ENetChannel * channel;
ENetProtocol command;
size_t fragmentLength;
@@ -108,6 +115,7 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
packet -> dataLength > peer -> host -> maximumPacketSize)
return -1;
+ channel = & peer -> channels [channelID];
fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment);
if (peer -> host -> checksum != NULL)
fragmentLength -= sizeof(enet_uint32);
@@ -320,8 +328,8 @@ enet_peer_reset_queues (ENetPeer * peer)
enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements)));
enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands);
- enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands);
enet_peer_reset_outgoing_commands (& peer -> outgoingCommands);
+ enet_peer_reset_outgoing_commands (& peer -> outgoingSendReliableCommands);
enet_peer_reset_incoming_commands (& peer -> dispatchedCommands);
if (peer -> channels != NULL && peer -> channelCount > 0)
@@ -563,6 +571,17 @@ enet_peer_disconnect (ENetPeer * peer, enet_uint32 data)
}
}
+int
+enet_peer_has_outgoing_commands (ENetPeer * peer)
+{
+ if (enet_list_empty (& peer -> outgoingCommands) &&
+ enet_list_empty (& peer -> outgoingSendReliableCommands) &&
+ enet_list_empty (& peer -> sentReliableCommands))
+ return 0;
+
+ return 1;
+}
+
/** Request a disconnection from a peer, but only after all queued outgoing packets are sent.
@param peer peer to request a disconnection
@param data data describing the disconnection
@@ -573,8 +592,7 @@ void
enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data)
{
if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) &&
- ! (enet_list_empty (& peer -> outgoingCommands) &&
- enet_list_empty (& peer -> sentReliableCommands)))
+ enet_peer_has_outgoing_commands (peer))
{
peer -> state = ENET_PEER_STATE_DISCONNECT_LATER;
peer -> eventData = data;
@@ -618,8 +636,6 @@ enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command,
void
enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand)
{
- ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID];
-
peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength;
if (outgoingCommand -> command.header.channelID == 0xFF)
@@ -630,36 +646,40 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
outgoingCommand -> unreliableSequenceNumber = 0;
}
else
- if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
{
- ++ channel -> outgoingReliableSequenceNumber;
- channel -> outgoingUnreliableSequenceNumber = 0;
+ ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID];
- outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
- outgoingCommand -> unreliableSequenceNumber = 0;
- }
- else
- if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED)
- {
- ++ peer -> outgoingUnsequencedGroup;
+ if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
+ {
+ ++ channel -> outgoingReliableSequenceNumber;
+ channel -> outgoingUnreliableSequenceNumber = 0;
- outgoingCommand -> reliableSequenceNumber = 0;
- outgoingCommand -> unreliableSequenceNumber = 0;
- }
- else
- {
- if (outgoingCommand -> fragmentOffset == 0)
- ++ channel -> outgoingUnreliableSequenceNumber;
-
- outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
- outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber;
+ outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
+ outgoingCommand -> unreliableSequenceNumber = 0;
+ }
+ else
+ if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED)
+ {
+ ++ peer -> outgoingUnsequencedGroup;
+
+ outgoingCommand -> reliableSequenceNumber = 0;
+ outgoingCommand -> unreliableSequenceNumber = 0;
+ }
+ else
+ {
+ if (outgoingCommand -> fragmentOffset == 0)
+ ++ channel -> outgoingUnreliableSequenceNumber;
+
+ outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
+ outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber;
+ }
}
-
+
outgoingCommand -> sendAttempts = 0;
outgoingCommand -> sentTime = 0;
outgoingCommand -> roundTripTimeout = 0;
- outgoingCommand -> roundTripTimeoutLimit = 0;
outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber);
+ outgoingCommand -> queueTime = ++ peer -> host -> totalQueued;
switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK)
{
@@ -670,12 +690,16 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup);
break;
-
+
default:
break;
}
- enet_list_insert (enet_list_end (& peer -> outgoingCommands), outgoingCommand);
+ if ((outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0 &&
+ outgoingCommand -> packet != NULL)
+ enet_list_insert (enet_list_end (& peer -> outgoingSendReliableCommands), outgoingCommand);
+ else
+ enet_list_insert (enet_list_end (& peer -> outgoingCommands), outgoingCommand);
}
ENetOutgoingCommand *
diff --git a/thirdparty/enet/protocol.c b/thirdparty/enet/protocol.c
index d7fe80f117..af307af7e5 100644
--- a/thirdparty/enet/protocol.c
+++ b/thirdparty/enet/protocol.c
@@ -9,7 +9,7 @@
#include "enet/time.h"
#include "enet/enet.h"
-static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] =
+static const size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] =
{
0,
sizeof (ENetProtocolAcknowledge),
@@ -159,16 +159,16 @@ enet_protocol_notify_disconnect (ENetHost * host, ENetPeer * peer, ENetEvent * e
}
static void
-enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer)
+enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer, ENetList * sentUnreliableCommands)
{
ENetOutgoingCommand * outgoingCommand;
- if (enet_list_empty (& peer -> sentUnreliableCommands))
+ if (enet_list_empty (sentUnreliableCommands))
return;
do
{
- outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentUnreliableCommands);
+ outgoingCommand = (ENetOutgoingCommand *) enet_list_front (sentUnreliableCommands);
enet_list_remove (& outgoingCommand -> outgoingCommandList);
@@ -185,14 +185,38 @@ enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer)
}
enet_free (outgoingCommand);
- } while (! enet_list_empty (& peer -> sentUnreliableCommands));
+ } while (! enet_list_empty (sentUnreliableCommands));
if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER &&
- enet_list_empty (& peer -> outgoingCommands) &&
- enet_list_empty (& peer -> sentReliableCommands))
+ ! enet_peer_has_outgoing_commands (peer))
enet_peer_disconnect (peer, peer -> eventData);
}
+static ENetOutgoingCommand *
+enet_protocol_find_sent_reliable_command (ENetList * list, enet_uint16 reliableSequenceNumber, enet_uint8 channelID)
+{
+ ENetListIterator currentCommand;
+
+ for (currentCommand = enet_list_begin (list);
+ currentCommand != enet_list_end (list);
+ currentCommand = enet_list_next (currentCommand))
+ {
+ ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+
+ if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE))
+ continue;
+
+ if (outgoingCommand -> sendAttempts < 1)
+ break;
+
+ if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber &&
+ outgoingCommand -> command.header.channelID == channelID)
+ return outgoingCommand;
+ }
+
+ return NULL;
+}
+
static ENetProtocolCommand
enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID)
{
@@ -214,24 +238,9 @@ enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliabl
if (currentCommand == enet_list_end (& peer -> sentReliableCommands))
{
- for (currentCommand = enet_list_begin (& peer -> outgoingCommands);
- currentCommand != enet_list_end (& peer -> outgoingCommands);
- currentCommand = enet_list_next (currentCommand))
- {
- outgoingCommand = (ENetOutgoingCommand *) currentCommand;
-
- if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE))
- continue;
-
- if (outgoingCommand -> sendAttempts < 1) return ENET_PROTOCOL_COMMAND_NONE;
-
- if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber &&
- outgoingCommand -> command.header.channelID == channelID)
- break;
- }
-
- if (currentCommand == enet_list_end (& peer -> outgoingCommands))
- return ENET_PROTOCOL_COMMAND_NONE;
+ outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingCommands, reliableSequenceNumber, channelID);
+ if (outgoingCommand == NULL)
+ outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingSendReliableCommands, reliableSequenceNumber, channelID);
wasSent = 0;
}
@@ -331,6 +340,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT;
peer -> connectID = command -> connect.connectID;
peer -> address = host -> receivedAddress;
+ peer -> mtu = host -> mtu;
peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> connect.outgoingPeerID);
peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.incomingBandwidth);
peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.outgoingBandwidth);
@@ -375,7 +385,8 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
if (mtu > ENET_PROTOCOL_MAXIMUM_MTU)
mtu = ENET_PROTOCOL_MAXIMUM_MTU;
- peer -> mtu = mtu;
+ if (mtu < peer -> mtu)
+ peer -> mtu = mtu;
if (host -> outgoingBandwidth == 0 &&
peer -> incomingBandwidth == 0)
@@ -542,7 +553,8 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet
fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength);
* currentData += fragmentLength;
- if (fragmentLength > host -> maximumPacketSize ||
+ if (fragmentLength <= 0 ||
+ fragmentLength > host -> maximumPacketSize ||
* currentData < host -> receivedData ||
* currentData > & host -> receivedData [host -> receivedDataLength])
return -1;
@@ -566,6 +578,7 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet
if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
fragmentNumber >= fragmentCount ||
totalLength > host -> maximumPacketSize ||
+ totalLength < fragmentCount ||
fragmentOffset >= totalLength ||
fragmentLength > totalLength - fragmentOffset)
return -1;
@@ -921,8 +934,7 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer *
break;
case ENET_PEER_STATE_DISCONNECT_LATER:
- if (enet_list_empty (& peer -> outgoingCommands) &&
- enet_list_empty (& peer -> sentReliableCommands))
+ if (! enet_peer_has_outgoing_commands (peer))
enet_peer_disconnect (peer, peer -> eventData);
break;
@@ -1230,6 +1242,9 @@ enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event)
& buffer,
1);
+ if (receivedLength == -2)
+ continue;
+
if (receivedLength < 0)
return -1;
@@ -1293,7 +1308,7 @@ enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer)
buffer >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] ||
peer -> mtu - host -> packetSize < sizeof (ENetProtocolAcknowledge))
{
- host -> continueSending = 1;
+ peer -> flags |= ENET_PEER_FLAG_CONTINUE_SENDING;
break;
}
@@ -1333,10 +1348,11 @@ static int
enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event)
{
ENetOutgoingCommand * outgoingCommand;
- ENetListIterator currentCommand, insertPosition;
+ ENetListIterator currentCommand, insertPosition, insertSendReliablePosition;
currentCommand = enet_list_begin (& peer -> sentReliableCommands);
insertPosition = enet_list_begin (& peer -> outgoingCommands);
+ insertSendReliablePosition = enet_list_begin (& peer -> outgoingSendReliableCommands);
while (currentCommand != enet_list_end (& peer -> sentReliableCommands))
{
@@ -1353,7 +1369,7 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even
if (peer -> earliestTimeout != 0 &&
(ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMaximum ||
- (outgoingCommand -> roundTripTimeout >= outgoingCommand -> roundTripTimeoutLimit &&
+ ((1 << (outgoingCommand -> sendAttempts - 1)) >= peer -> timeoutLimit &&
ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMinimum)))
{
enet_protocol_notify_disconnect (host, peer, event);
@@ -1361,14 +1377,18 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even
return 1;
}
- if (outgoingCommand -> packet != NULL)
- peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength;
-
++ peer -> packetsLost;
outgoingCommand -> roundTripTimeout *= 2;
- enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList));
+ if (outgoingCommand -> packet != NULL)
+ {
+ peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength;
+
+ enet_list_insert (insertSendReliablePosition, enet_list_remove (& outgoingCommand -> outgoingCommandList));
+ }
+ else
+ enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList));
if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) &&
! enet_list_empty (& peer -> sentReliableCommands))
@@ -1383,22 +1403,41 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even
}
static int
-enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
+enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer, ENetList * sentUnreliableCommands)
{
ENetProtocol * command = & host -> commands [host -> commandCount];
ENetBuffer * buffer = & host -> buffers [host -> bufferCount];
ENetOutgoingCommand * outgoingCommand;
- ENetListIterator currentCommand;
- ENetChannel *channel;
- enet_uint16 reliableWindow;
+ ENetListIterator currentCommand, currentSendReliableCommand;
+ ENetChannel *channel = NULL;
+ enet_uint16 reliableWindow = 0;
size_t commandSize;
- int windowExceeded = 0, windowWrap = 0, canPing = 1;
+ int windowWrap = 0, canPing = 1;
currentCommand = enet_list_begin (& peer -> outgoingCommands);
-
- while (currentCommand != enet_list_end (& peer -> outgoingCommands))
+ currentSendReliableCommand = enet_list_begin (& peer -> outgoingSendReliableCommands);
+
+ for (;;)
{
- outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+ if (currentCommand != enet_list_end (& peer -> outgoingCommands))
+ {
+ outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+
+ if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands) &&
+ ENET_TIME_LESS (((ENetOutgoingCommand *) currentSendReliableCommand) -> queueTime, outgoingCommand -> queueTime))
+ goto useSendReliableCommand;
+
+ currentCommand = enet_list_next (currentCommand);
+ }
+ else
+ if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands))
+ {
+ useSendReliableCommand:
+ outgoingCommand = (ENetOutgoingCommand *) currentSendReliableCommand;
+ currentSendReliableCommand = enet_list_next (currentSendReliableCommand);
+ }
+ else
+ break;
if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
{
@@ -1406,33 +1445,29 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
if (channel != NULL)
{
- if (! windowWrap &&
- outgoingCommand -> sendAttempts < 1 &&
+ if (windowWrap)
+ continue;
+ else
+ if (outgoingCommand -> sendAttempts < 1 &&
! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) &&
(channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE ||
channel -> usedReliableWindows & ((((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) << reliableWindow) |
(((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow)))))
- windowWrap = 1;
- if (windowWrap)
{
- currentCommand = enet_list_next (currentCommand);
-
+ windowWrap = 1;
+ currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands);
+
continue;
}
}
-
+
if (outgoingCommand -> packet != NULL)
{
- if (! windowExceeded)
- {
- enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE;
-
- if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu))
- windowExceeded = 1;
- }
- if (windowExceeded)
+ enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE;
+
+ if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu))
{
- currentCommand = enet_list_next (currentCommand);
+ currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands);
continue;
}
@@ -1448,13 +1483,11 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
(outgoingCommand -> packet != NULL &&
(enet_uint16) (peer -> mtu - host -> packetSize) < (enet_uint16) (commandSize + outgoingCommand -> fragmentLength)))
{
- host -> continueSending = 1;
-
+ peer -> flags |= ENET_PEER_FLAG_CONTINUE_SENDING;
+
break;
}
- currentCommand = enet_list_next (currentCommand);
-
if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
{
if (channel != NULL && outgoingCommand -> sendAttempts < 1)
@@ -1466,10 +1499,7 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
++ outgoingCommand -> sendAttempts;
if (outgoingCommand -> roundTripTimeout == 0)
- {
- outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance;
- outgoingCommand -> roundTripTimeoutLimit = peer -> timeoutLimit * outgoingCommand -> roundTripTimeout;
- }
+ outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance;
if (enet_list_empty (& peer -> sentReliableCommands))
peer -> nextTimeout = host -> serviceTime + outgoingCommand -> roundTripTimeout;
@@ -1522,7 +1552,7 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
enet_list_remove (& outgoingCommand -> outgoingCommandList);
if (outgoingCommand -> packet != NULL)
- enet_list_insert (enet_list_end (& peer -> sentUnreliableCommands), outgoingCommand);
+ enet_list_insert (enet_list_end (sentUnreliableCommands), outgoingCommand);
}
buffer -> data = command;
@@ -1555,9 +1585,8 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
host -> bufferCount = buffer - host -> buffers;
if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER &&
- enet_list_empty (& peer -> outgoingCommands) &&
- enet_list_empty (& peer -> sentReliableCommands) &&
- enet_list_empty (& peer -> sentUnreliableCommands))
+ ! enet_peer_has_outgoing_commands (peer) &&
+ enet_list_empty (sentUnreliableCommands))
enet_peer_disconnect (peer, peer -> eventData);
return canPing;
@@ -1568,22 +1597,24 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
{
enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)];
ENetProtocolHeader * header = (ENetProtocolHeader *) headerData;
- ENetPeer * currentPeer;
- int sentLength;
+ int sentLength = 0;
size_t shouldCompress = 0;
-
- host -> continueSending = 1;
+ ENetList sentUnreliableCommands;
- while (host -> continueSending)
- for (host -> continueSending = 0,
- currentPeer = host -> peers;
+ enet_list_clear (& sentUnreliableCommands);
+
+ for (int sendPass = 0, continueSending = 0; sendPass <= continueSending; ++ sendPass)
+ for (ENetPeer * currentPeer = host -> peers;
currentPeer < & host -> peers [host -> peerCount];
++ currentPeer)
{
if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED ||
- currentPeer -> state == ENET_PEER_STATE_ZOMBIE)
+ currentPeer -> state == ENET_PEER_STATE_ZOMBIE ||
+ (sendPass > 0 && ! (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING)))
continue;
+ currentPeer -> flags &= ~ ENET_PEER_FLAG_CONTINUE_SENDING;
+
host -> headerFlags = 0;
host -> commandCount = 0;
host -> bufferCount = 1;
@@ -1600,21 +1631,22 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE)
return 1;
else
- continue;
+ goto nextPeer;
}
- if ((enet_list_empty (& currentPeer -> outgoingCommands) ||
- enet_protocol_check_outgoing_commands (host, currentPeer)) &&
+ if (((enet_list_empty (& currentPeer -> outgoingCommands) &&
+ enet_list_empty (& currentPeer -> outgoingSendReliableCommands)) ||
+ enet_protocol_check_outgoing_commands (host, currentPeer, & sentUnreliableCommands)) &&
enet_list_empty (& currentPeer -> sentReliableCommands) &&
ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= currentPeer -> pingInterval &&
currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing))
{
enet_peer_ping (currentPeer);
- enet_protocol_check_outgoing_commands (host, currentPeer);
+ enet_protocol_check_outgoing_commands (host, currentPeer, & sentUnreliableCommands);
}
if (host -> commandCount == 0)
- continue;
+ goto nextPeer;
if (currentPeer -> packetLossEpoch == 0)
currentPeer -> packetLossEpoch = host -> serviceTime;
@@ -1625,7 +1657,7 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent;
#ifdef ENET_DEBUG
- printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0);
+ printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingCommands) + enet_list_size (& currentPeer -> outgoingSendReliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0);
#endif
currentPeer -> packetLossVariance = (currentPeer -> packetLossVariance * 3 + ENET_DIFFERENCE (packetLoss, currentPeer -> packetLoss)) / 4;
@@ -1687,13 +1719,17 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount);
- enet_protocol_remove_sent_unreliable_commands (currentPeer);
+ enet_protocol_remove_sent_unreliable_commands (currentPeer, & sentUnreliableCommands);
if (sentLength < 0)
return -1;
host -> totalSentData += sentLength;
host -> totalSentPackets ++;
+
+ nextPeer:
+ if (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING)
+ continueSending = sendPass + 1;
}
return 0;
diff --git a/thirdparty/freetype/include/freetype/config/ftoption.h b/thirdparty/freetype/include/freetype/config/ftoption.h
index 9e03e1783b..1976b33af9 100644
--- a/thirdparty/freetype/include/freetype/config/ftoption.h
+++ b/thirdparty/freetype/include/freetype/config/ftoption.h
@@ -661,36 +661,12 @@ FT_BEGIN_HEADER
* not) instructions in a certain way so that all TrueType fonts look like
* they do in a Windows ClearType (DirectWrite) environment. See [1] for a
* technical overview on what this means. See `ttinterp.h` for more
- * details on the LEAN option.
+ * details on this option.
*
- * There are three possible values.
- *
- * Value 1:
- * This value is associated with the 'Infinality' moniker, contributed by
- * an individual nicknamed Infinality with the goal of making TrueType
- * fonts render better than on Windows. A high amount of configurability
- * and flexibility, down to rules for single glyphs in fonts, but also
- * very slow. Its experimental and slow nature and the original
- * developer losing interest meant that this option was never enabled in
- * default builds.
- *
- * The corresponding interpreter version is v38.
- *
- * Value 2:
- * The new default mode for the TrueType driver. The Infinality code
- * base was stripped to the bare minimum and all configurability removed
- * in the name of speed and simplicity. The configurability was mainly
- * aimed at legacy fonts like 'Arial', 'Times New Roman', or 'Courier'.
- * Legacy fonts are fonts that modify vertical stems to achieve clean
- * black-and-white bitmaps. The new mode focuses on applying a minimal
- * set of rules to all fonts indiscriminately so that modern and web
- * fonts render well while legacy fonts render okay.
- *
- * The corresponding interpreter version is v40.
- *
- * Value 3:
- * Compile both, making both v38 and v40 available (the latter is the
- * default).
+ * The new default mode focuses on applying a minimal set of rules to all
+ * fonts indiscriminately so that modern and web fonts render well while
+ * legacy fonts render okay. The corresponding interpreter version is v40.
+ * The so-called Infinality mode (v38) is no longer available in FreeType.
*
* By undefining these, you get rendering behavior like on Windows without
* ClearType, i.e., Windows XP without ClearType enabled and Win9x
@@ -705,9 +681,7 @@ FT_BEGIN_HEADER
* [1]
* https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx
*/
-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */
-#define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2
-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) */
+#define TT_CONFIG_OPTION_SUBPIXEL_HINTING
/**************************************************************************
@@ -977,22 +951,15 @@ FT_BEGIN_HEADER
/*
- * The next three macros are defined if native TrueType hinting is
+ * The next two macros are defined if native TrueType hinting is
* requested by the definitions above. Don't change this.
*/
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
#define TT_USE_BYTECODE_INTERPRETER
-
#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 1
-#define TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-#endif
-
-#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 2
#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
#endif
#endif
-#endif
/*
diff --git a/thirdparty/freetype/include/freetype/config/ftstdlib.h b/thirdparty/freetype/include/freetype/config/ftstdlib.h
index 3c9d2ae59a..f65148a902 100644
--- a/thirdparty/freetype/include/freetype/config/ftstdlib.h
+++ b/thirdparty/freetype/include/freetype/config/ftstdlib.h
@@ -111,13 +111,13 @@
#include <stdio.h>
-#define FT_FILE FILE
-#define ft_fclose fclose
-#define ft_fopen fopen
-#define ft_fread fread
-#define ft_fseek fseek
-#define ft_ftell ftell
-#define ft_sprintf sprintf
+#define FT_FILE FILE
+#define ft_fclose fclose
+#define ft_fopen fopen
+#define ft_fread fread
+#define ft_fseek fseek
+#define ft_ftell ftell
+#define ft_snprintf snprintf
/**************************************************************************
diff --git a/thirdparty/freetype/include/freetype/freetype.h b/thirdparty/freetype/include/freetype/freetype.h
index efff74fe39..4a074a4449 100644
--- a/thirdparty/freetype/include/freetype/freetype.h
+++ b/thirdparty/freetype/include/freetype/freetype.h
@@ -102,61 +102,25 @@ FT_BEGIN_HEADER
*/
-
- /*************************************************************************/
- /*************************************************************************/
- /* */
- /* B A S I C T Y P E S */
- /* */
- /*************************************************************************/
- /*************************************************************************/
-
-
/**************************************************************************
*
* @section:
- * base_interface
+ * font_testing_macros
*
* @title:
- * Base Interface
+ * Font Testing Macros
*
* @abstract:
- * The FreeType~2 base font interface.
+ * Macros to test various properties of fonts.
*
* @description:
- * This section describes the most important public high-level API
- * functions of FreeType~2.
+ * Macros to test the most important font properties.
*
- * @order:
- * FT_Library
- * FT_Face
- * FT_Size
- * FT_GlyphSlot
- * FT_CharMap
- * FT_Encoding
- * FT_ENC_TAG
- *
- * FT_FaceRec
- *
- * FT_FACE_FLAG_SCALABLE
- * FT_FACE_FLAG_FIXED_SIZES
- * FT_FACE_FLAG_FIXED_WIDTH
- * FT_FACE_FLAG_HORIZONTAL
- * FT_FACE_FLAG_VERTICAL
- * FT_FACE_FLAG_COLOR
- * FT_FACE_FLAG_SFNT
- * FT_FACE_FLAG_CID_KEYED
- * FT_FACE_FLAG_TRICKY
- * FT_FACE_FLAG_KERNING
- * FT_FACE_FLAG_MULTIPLE_MASTERS
- * FT_FACE_FLAG_VARIATION
- * FT_FACE_FLAG_GLYPH_NAMES
- * FT_FACE_FLAG_EXTERNAL_STREAM
- * FT_FACE_FLAG_HINTER
- * FT_FACE_FLAG_SVG
- * FT_FACE_FLAG_SBIX
- * FT_FACE_FLAG_SBIX_OVERLAY
+ * It is recommended to use these high-level macros instead of directly
+ * testing the corresponding flags, which are scattered over various
+ * structures.
*
+ * @order:
* FT_HAS_HORIZONTAL
* FT_HAS_VERTICAL
* FT_HAS_KERNING
@@ -176,21 +140,59 @@ FT_BEGIN_HEADER
* FT_IS_NAMED_INSTANCE
* FT_IS_VARIATION
*
- * FT_STYLE_FLAG_BOLD
- * FT_STYLE_FLAG_ITALIC
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * library_setup
*
- * FT_SizeRec
- * FT_Size_Metrics
+ * @title:
+ * Library Setup
*
- * FT_GlyphSlotRec
- * FT_Glyph_Metrics
- * FT_SubGlyph
+ * @abstract:
+ * Functions to start and end the usage of the FreeType library.
*
- * FT_Bitmap_Size
+ * @description:
+ * Functions to start and end the usage of the FreeType library.
+ *
+ * Note that @FT_Library_Version and @FREETYPE_XXX are of limited use
+ * because even a new release of FreeType with only documentation
+ * changes increases the version number.
*
+ * @order:
+ * FT_Library
* FT_Init_FreeType
* FT_Done_FreeType
*
+ * FT_Library_Version
+ * FREETYPE_XXX
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * face_creation
+ *
+ * @title:
+ * Face Creation
+ *
+ * @abstract:
+ * Functions to manage fonts.
+ *
+ * @description:
+ * The functions and structures collected in this section operate on
+ * fonts globally.
+ *
+ * @order:
+ * FT_Face
+ * FT_FaceRec
+ * FT_FACE_FLAG_XXX
+ * FT_STYLE_FLAG_XXX
+ *
* FT_New_Face
* FT_Done_Face
* FT_Reference_Face
@@ -198,10 +200,36 @@ FT_BEGIN_HEADER
* FT_Face_Properties
* FT_Open_Face
* FT_Open_Args
+ * FT_OPEN_XXX
* FT_Parameter
* FT_Attach_File
* FT_Attach_Stream
*
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * sizing_and_scaling
+ *
+ * @title:
+ * Sizing and Scaling
+ *
+ * @abstract:
+ * Functions to manage font sizes.
+ *
+ * @description:
+ * The functions and structures collected in this section are related to
+ * selecting and manipulating the size of a font globally.
+ *
+ * @order:
+ * FT_Size
+ * FT_SizeRec
+ * FT_Size_Metrics
+ *
+ * FT_Bitmap_Size
+ *
* FT_Set_Char_Size
* FT_Set_Pixel_Sizes
* FT_Request_Size
@@ -209,44 +237,37 @@ FT_BEGIN_HEADER
* FT_Size_Request_Type
* FT_Size_RequestRec
* FT_Size_Request
+ *
* FT_Set_Transform
* FT_Get_Transform
- * FT_Load_Glyph
- * FT_Get_Char_Index
- * FT_Get_First_Char
- * FT_Get_Next_Char
- * FT_Load_Char
*
- * FT_OPEN_MEMORY
- * FT_OPEN_STREAM
- * FT_OPEN_PATHNAME
- * FT_OPEN_DRIVER
- * FT_OPEN_PARAMS
- *
- * FT_LOAD_DEFAULT
- * FT_LOAD_RENDER
- * FT_LOAD_MONOCHROME
- * FT_LOAD_LINEAR_DESIGN
- * FT_LOAD_NO_SCALE
- * FT_LOAD_NO_HINTING
- * FT_LOAD_NO_BITMAP
- * FT_LOAD_SBITS_ONLY
- * FT_LOAD_NO_AUTOHINT
- * FT_LOAD_COLOR
- *
- * FT_LOAD_VERTICAL_LAYOUT
- * FT_LOAD_IGNORE_TRANSFORM
- * FT_LOAD_FORCE_AUTOHINT
- * FT_LOAD_NO_RECURSE
- * FT_LOAD_PEDANTIC
- *
- * FT_LOAD_TARGET_NORMAL
- * FT_LOAD_TARGET_LIGHT
- * FT_LOAD_TARGET_MONO
- * FT_LOAD_TARGET_LCD
- * FT_LOAD_TARGET_LCD_V
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * glyph_retrieval
+ *
+ * @title:
+ * Glyph Retrieval
+ *
+ * @abstract:
+ * Functions to manage glyphs.
+ *
+ * @description:
+ * The functions and structures collected in this section operate on
+ * single glyphs, of which @FT_Load_Glyph is most important.
*
+ * @order:
+ * FT_GlyphSlot
+ * FT_GlyphSlotRec
+ * FT_Glyph_Metrics
+ *
+ * FT_Load_Glyph
+ * FT_LOAD_XXX
* FT_LOAD_TARGET_MODE
+ * FT_LOAD_TARGET_XXX
*
* FT_Render_Glyph
* FT_Render_Mode
@@ -254,34 +275,121 @@ FT_BEGIN_HEADER
* FT_Kerning_Mode
* FT_Get_Track_Kerning
*
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * character_mapping
+ *
+ * @title:
+ * Character Mapping
+ *
+ * @abstract:
+ * Functions to manage character-to-glyph maps.
+ *
+ * @description:
+ * This section holds functions and structures that are related to
+ * mapping character input codes to glyph indices.
+ *
+ * Note that for many scripts the simplistic approach used by FreeType
+ * of mapping a single character to a single glyph is not valid or
+ * possible! In general, a higher-level library like HarfBuzz or ICU
+ * should be used for handling text strings.
+ *
+ * @order:
+ * FT_CharMap
* FT_CharMapRec
+ * FT_Encoding
+ * FT_ENC_TAG
+ *
* FT_Select_Charmap
* FT_Set_Charmap
* FT_Get_Charmap_Index
*
+ * FT_Get_Char_Index
+ * FT_Get_First_Char
+ * FT_Get_Next_Char
+ * FT_Load_Char
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * information_retrieval
+ *
+ * @title:
+ * Information Retrieval
+ *
+ * @abstract:
+ * Functions to retrieve font and glyph information.
+ *
+ * @description:
+ * Functions to retrieve font and glyph information. Only some very
+ * basic data is covered; see also the chapter on the format-specific
+ * API for more.
+ *
+ *
+ * @order:
* FT_Get_Name_Index
* FT_Get_Glyph_Name
* FT_Get_Postscript_Name
* FT_Get_FSType_Flags
+ * FT_FSTYPE_XXX
* FT_Get_SubGlyph_Info
+ * FT_SUBGLYPH_FLAG_XXX
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * other_api_data
+ *
+ * @title:
+ * Other API Data
+ *
+ * @abstract:
+ * Other structures, enumerations, and macros.
*
+ * @description:
+ * Other structures, enumerations, and macros. Deprecated functions are
+ * also listed here.
+ *
+ * @order:
* FT_Face_Internal
* FT_Size_Internal
* FT_Slot_Internal
*
- * FT_FACE_FLAG_XXX
- * FT_STYLE_FLAG_XXX
- * FT_OPEN_XXX
- * FT_LOAD_XXX
- * FT_LOAD_TARGET_XXX
- * FT_SUBGLYPH_FLAG_XXX
- * FT_FSTYPE_XXX
+ * FT_SubGlyph
*
* FT_HAS_FAST_GLYPHS
+ * FT_Face_CheckTrueTypePatents
+ * FT_Face_SetUnpatentedHinting
*
*/
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* B A S I C T Y P E S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
/**************************************************************************
*
* @struct:
@@ -351,6 +459,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_Bitmap_Size
*
@@ -411,6 +526,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * library_setup
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_Library
*
@@ -483,7 +605,7 @@ FT_BEGIN_HEADER
/**************************************************************************
*
* @section:
- * base_interface
+ * face_creation
*
*/
@@ -521,6 +643,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_Size
*
@@ -553,6 +682,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_GlyphSlot
*
@@ -572,6 +708,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * character_mapping
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_CharMap
*
@@ -879,6 +1022,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_Face_Internal
*
@@ -894,6 +1044,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * face_creation
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_FaceRec
*
@@ -918,7 +1075,7 @@ FT_BEGIN_HEADER
* If we have the third named instance of face~4, say, `face_index` is
* set to 0x00030004.
*
- * Bit 31 is always zero (this is, `face_index` is always a positive
+ * Bit 31 is always zero (that is, `face_index` is always a positive
* value).
*
* [Since 2.9] Changing the design coordinates with
@@ -936,7 +1093,7 @@ FT_BEGIN_HEADER
*
* [Since 2.6.1] Bits 16-30 hold the number of named instances
* available for the current face if we have a GX or OpenType variation
- * (sub)font. Bit 31 is always zero (this is, `style_flags` is always
+ * (sub)font. Bit 31 is always zero (that is, `style_flags` is always
* a positive value). Note that a variation font has always at least
* one named instance, namely the default instance.
*
@@ -1002,7 +1159,7 @@ FT_BEGIN_HEADER
* Note that the bounding box might be off by (at least) one pixel for
* hinted fonts. See @FT_Size_Metrics for further discussion.
*
- * Note that the bounding box does not vary in OpenType variable fonts
+ * Note that the bounding box does not vary in OpenType variation fonts
* and should only be used in relation to the default instance.
*
* units_per_EM ::
@@ -1090,9 +1247,9 @@ FT_BEGIN_HEADER
FT_Generic generic;
- /*# The following member variables (down to `underline_thickness`) */
- /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */
- /*# for bitmap fonts. */
+ /* The following member variables (down to `underline_thickness`) */
+ /* are only relevant to scalable outlines; cf. @FT_Bitmap_Size */
+ /* for bitmap fonts. */
FT_BBox bbox;
FT_UShort units_per_EM;
@@ -1110,7 +1267,7 @@ FT_BEGIN_HEADER
FT_Size size;
FT_CharMap charmap;
- /*@private begin */
+ /* private fields, internal to FreeType */
FT_Driver driver;
FT_Memory memory;
@@ -1123,8 +1280,6 @@ FT_BEGIN_HEADER
FT_Face_Internal internal;
- /*@private end */
-
} FT_FaceRec;
@@ -1207,13 +1362,13 @@ FT_BEGIN_HEADER
* successfully; in all other cases you get an
* `FT_Err_Invalid_Argument` error.
*
- * Note that CID-keyed fonts that are in an SFNT wrapper (this is, all
+ * Note that CID-keyed fonts that are in an SFNT wrapper (that is, all
* OpenType/CFF fonts) don't have this flag set since the glyphs are
* accessed in the normal way (using contiguous indices); the
* 'CID-ness' isn't visible to the application.
*
* FT_FACE_FLAG_TRICKY ::
- * The face is 'tricky', this is, it always needs the font format's
+ * The face is 'tricky', that is, it always needs the font format's
* native hinting engine to get a reasonable result. A typical example
* is the old Chinese font `mingli.ttf` (but not `mingliu.ttc`) that
* uses TrueType bytecode instructions to move and scale all of its
@@ -1235,8 +1390,8 @@ FT_BEGIN_HEADER
* FT_FACE_FLAG_VARIATION ::
* [Since 2.9] Set if the current face (or named instance) has been
* altered with @FT_Set_MM_Design_Coordinates,
- * @FT_Set_Var_Design_Coordinates, or @FT_Set_Var_Blend_Coordinates.
- * This flag is unset by a call to @FT_Set_Named_Instance.
+ * @FT_Set_Var_Design_Coordinates, @FT_Set_Var_Blend_Coordinates, or
+ * @FT_Set_MM_WeightVector to select a non-default instance.
*
* FT_FACE_FLAG_SVG ::
* [Since 2.12] The face has an 'SVG~' OpenType table.
@@ -1274,6 +1429,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * font_testing_macros
+ *
+ */
+
+ /**************************************************************************
+ *
* @macro:
* FT_HAS_HORIZONTAL
*
@@ -1383,6 +1545,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @macro:
* FT_HAS_FAST_GLYPHS
*
@@ -1395,6 +1564,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * font_testing_macros
+ *
+ */
+
+ /**************************************************************************
+ *
* @macro:
* FT_HAS_GLYPH_NAMES
*
@@ -1451,8 +1627,8 @@ FT_BEGIN_HEADER
*
* @description:
* A macro that returns true whenever a face object has been altered by
- * @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates, or
- * @FT_Set_Var_Blend_Coordinates.
+ * @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates,
+ * @FT_Set_Var_Blend_Coordinates, or @FT_Set_MM_WeightVector.
*
* @since:
* 2.9
@@ -1630,6 +1806,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * face_creation
+ *
+ */
+
+ /**************************************************************************
+ *
* @enum:
* FT_STYLE_FLAG_XXX
*
@@ -1656,6 +1839,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_Size_Internal
*
@@ -1668,6 +1858,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_Size_Metrics
*
@@ -1819,6 +2016,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_SubGlyph
*
@@ -1850,6 +2054,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_GlyphSlotRec
*
@@ -2094,6 +2305,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * library_setup
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Init_FreeType
*
@@ -2151,6 +2369,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * face_creation
+ *
+ */
+
+ /**************************************************************************
+ *
* @enum:
* FT_OPEN_XXX
*
@@ -2451,7 +2676,7 @@ FT_BEGIN_HEADER
* Each new face object created with this function also owns a default
* @FT_Size object, accessible as `face->size`.
*
- * One @FT_Library instance can have multiple face objects, this is,
+ * One @FT_Library instance can have multiple face objects, that is,
* @FT_Open_Face and its siblings can be called multiple times using the
* same `library` argument.
*
@@ -2652,6 +2877,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Select_Size
*
@@ -2679,7 +2911,7 @@ FT_BEGIN_HEADER
* silently uses outlines if there is no bitmap for a given glyph index.
*
* For GX and OpenType variation fonts, a bitmap strike makes sense only
- * if the default instance is active (this is, no glyph variation takes
+ * if the default instance is active (that is, no glyph variation takes
* place); otherwise, FreeType simply ignores bitmap strikes. The same
* is true for all named instances that are different from the default
* instance.
@@ -2944,6 +3176,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Load_Glyph
*
@@ -2976,7 +3215,7 @@ FT_BEGIN_HEADER
* glyph may be transformed. See @FT_Set_Transform for the details.
*
* For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument` is returned
- * for invalid CID values (this is, for CID values that don't have a
+ * for invalid CID values (that is, for CID values that don't have a
* corresponding glyph in the font). See the discussion of the
* @FT_FACE_FLAG_CID_KEYED flag for more details.
*
@@ -2992,6 +3231,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * character_mapping
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Load_Char
*
@@ -3035,6 +3281,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @enum:
* FT_LOAD_XXX
*
@@ -3172,10 +3425,11 @@ FT_BEGIN_HEADER
*
* [Since 2.12] If the glyph index maps to an entry in the face's
* 'SVG~' table, load the associated SVG document from this table and
- * set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG.
- * Note that FreeType itself can't render SVG documents; however, the
- * library provides hooks to seamlessly integrate an external renderer.
- * See sections @ot_svg_driver and @svg_fonts for more.
+ * set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG
+ * ([since 2.13.1] provided @FT_LOAD_NO_SVG is not set). Note that
+ * FreeType itself can't render SVG documents; however, the library
+ * provides hooks to seamlessly integrate an external renderer. See
+ * sections @ot_svg_driver and @svg_fonts for more.
*
* [Since 2.10, experimental] If the glyph index maps to an entry in
* the face's 'COLR' table with a 'CPAL' palette table (as defined in
@@ -3189,6 +3443,9 @@ FT_BEGIN_HEADER
* @FT_Palette_Select instead of setting @FT_LOAD_COLOR for rendering
* so that the client application can handle blending by itself.
*
+ * FT_LOAD_NO_SVG ::
+ * [Since 2.13.1] Ignore SVG glyph data when loading.
+ *
* FT_LOAD_COMPUTE_METRICS ::
* [Since 2.6.1] Compute glyph metrics from the glyph data, without the
* use of bundled metrics tables (for example, the 'hdmx' table in
@@ -3254,6 +3511,7 @@ FT_BEGIN_HEADER
#define FT_LOAD_COLOR ( 1L << 20 )
#define FT_LOAD_COMPUTE_METRICS ( 1L << 21 )
#define FT_LOAD_BITMAP_METRICS_ONLY ( 1L << 22 )
+#define FT_LOAD_NO_SVG ( 1L << 24 )
/* */
@@ -3374,6 +3632,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Set_Transform
*
@@ -3449,6 +3714,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @enum:
* FT_Render_Mode
*
@@ -3843,6 +4115,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * character_mapping
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Select_Charmap
*
@@ -4059,6 +4338,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * face_creation
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Face_Properties
*
@@ -4157,6 +4443,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * information_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Get_Name_Index
*
@@ -4266,9 +4559,10 @@ FT_BEGIN_HEADER
*
* [Since 2.9] Special PostScript names for named instances are only
* returned if the named instance is set with @FT_Set_Named_Instance (and
- * the font has corresponding entries in its 'fvar' table). If
- * @FT_IS_VARIATION returns true, the algorithmically derived PostScript
- * name is provided, not looking up special entries for named instances.
+ * the font has corresponding entries in its 'fvar' table or is the
+ * default named instance). If @FT_IS_VARIATION returns true, the
+ * algorithmically derived PostScript name is provided, not looking up
+ * special entries for named instances.
*/
FT_EXPORT( const char* )
FT_Get_Postscript_Name( FT_Face face );
@@ -4900,32 +5194,10 @@ FT_BEGIN_HEADER
/**************************************************************************
*
* @section:
- * version
- *
- * @title:
- * FreeType Version
- *
- * @abstract:
- * Functions and macros related to FreeType versions.
- *
- * @description:
- * Note that those functions and macros are of limited use because even a
- * new release of FreeType with only documentation changes increases the
- * version number.
- *
- * @order:
- * FT_Library_Version
- *
- * FREETYPE_MAJOR
- * FREETYPE_MINOR
- * FREETYPE_PATCH
- *
- * FT_Face_CheckTrueTypePatents
- * FT_Face_SetUnpatentedHinting
+ * library_setup
*
*/
-
/**************************************************************************
*
* @enum:
@@ -4950,7 +5222,7 @@ FT_BEGIN_HEADER
*/
#define FREETYPE_MAJOR 2
#define FREETYPE_MINOR 13
-#define FREETYPE_PATCH 0
+#define FREETYPE_PATCH 1
/**************************************************************************
@@ -4994,6 +5266,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Face_CheckTrueTypePatents
*
diff --git a/thirdparty/freetype/include/freetype/ftcache.h b/thirdparty/freetype/include/freetype/ftcache.h
index c76869545a..a2072e26b8 100644
--- a/thirdparty/freetype/include/freetype/ftcache.h
+++ b/thirdparty/freetype/include/freetype/ftcache.h
@@ -43,61 +43,61 @@ FT_BEGIN_HEADER
* objects, as well as caching information like character maps and glyph
* images while limiting their maximum memory usage.
*
- * Note that all types and functions begin with the `FTC_` prefix.
- *
- * The cache is highly portable and thus doesn't know anything about the
- * fonts installed on your system, or how to access them. This implies
- * the following scheme:
- *
- * First, available or installed font faces are uniquely identified by
- * @FTC_FaceID values, provided to the cache by the client. Note that
- * the cache only stores and compares these values, and doesn't try to
- * interpret them in any way.
- *
- * Second, the cache calls, only when needed, a client-provided function
- * to convert an @FTC_FaceID into a new @FT_Face object. The latter is
- * then completely managed by the cache, including its termination
- * through @FT_Done_Face. To monitor termination of face objects, the
- * finalizer callback in the `generic` field of the @FT_Face object can
- * be used, which might also be used to store the @FTC_FaceID of the
- * face.
- *
- * Clients are free to map face IDs to anything else. The most simple
- * usage is to associate them to a (pathname,face_index) pair that is
- * used to call @FT_New_Face. However, more complex schemes are also
- * possible.
+ * Note that all types and functions begin with the `FTC_` prefix rather
+ * than the usual `FT_` prefix in the rest of FreeType.
+ *
+ * The cache is highly portable and, thus, doesn't know anything about
+ * the fonts installed on your system, or how to access them. Therefore,
+ * it requires the following.
+ *
+ * * @FTC_FaceID, an arbitrary non-zero value that uniquely identifies
+ * available or installed font faces, has to be provided to the
+ * cache by the client. Note that the cache only stores and compares
+ * these values and doesn't try to interpret them in any way, but they
+ * have to be persistent on the client side.
+ *
+ * * @FTC_Face_Requester, a method to convert an @FTC_FaceID into a new
+ * @FT_Face object when necessary, has to be provided to the cache by
+ * the client. The @FT_Face object is completely managed by the cache,
+ * including its termination through @FT_Done_Face. To monitor
+ * termination of face objects, the finalizer callback in the `generic`
+ * field of the @FT_Face object can be used, which might also be used
+ * to store the @FTC_FaceID of the face.
+ *
+ * Clients are free to map face IDs to anything useful. The most simple
+ * usage is, for example, to associate them to a `{pathname,face_index}`
+ * pair that is then used by @FTC_Face_Requester to call @FT_New_Face.
+ * However, more complex schemes are also possible.
*
* Note that for the cache to work correctly, the face ID values must be
* **persistent**, which means that the contents they point to should not
* change at runtime, or that their value should not become invalid.
- *
* If this is unavoidable (e.g., when a font is uninstalled at runtime),
- * you should call @FTC_Manager_RemoveFaceID as soon as possible, to let
+ * you should call @FTC_Manager_RemoveFaceID as soon as possible to let
* the cache get rid of any references to the old @FTC_FaceID it may keep
* internally. Failure to do so will lead to incorrect behaviour or even
- * crashes.
+ * crashes in @FTC_Face_Requester.
*
* To use the cache, start with calling @FTC_Manager_New to create a new
* @FTC_Manager object, which models a single cache instance. You can
* then look up @FT_Face and @FT_Size objects with
- * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively.
- *
- * If you want to use the charmap caching, call @FTC_CMapCache_New, then
- * later use @FTC_CMapCache_Lookup to perform the equivalent of
- * @FT_Get_Char_Index, only much faster.
- *
- * If you want to use the @FT_Glyph caching, call @FTC_ImageCache_New,
- * then later use @FTC_ImageCache_Lookup to retrieve the corresponding
- * @FT_Glyph objects from the cache.
- *
- * If you need lots of small bitmaps, it is much more memory efficient to
- * call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This
- * returns @FTC_SBitRec structures, which are used to store small bitmaps
- * directly. (A small bitmap is one whose metrics and dimensions all fit
- * into 8-bit integers).
- *
- * We hope to also provide a kerning cache in the near future.
- *
+ * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively, and
+ * use them in any FreeType work stream. You can also cache other
+ * FreeType objects as follows.
+ *
+ * * If you want to use the charmap caching, call @FTC_CMapCache_New,
+ * then later use @FTC_CMapCache_Lookup to perform the equivalent of
+ * @FT_Get_Char_Index, only much faster.
+ *
+ * * If you want to use the @FT_Glyph caching, call @FTC_ImageCache_New,
+ * then later use @FTC_ImageCache_Lookup to retrieve the corresponding
+ * @FT_Glyph objects from the cache.
+ *
+ * * If you need lots of small bitmaps, it is much more memory-efficient
+ * to call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This
+ * returns @FTC_SBitRec structures, which are used to store small
+ * bitmaps directly. (A small bitmap is one whose metrics and
+ * dimensions all fit into 8-bit integers).
*
* @order:
* FTC_Manager
diff --git a/thirdparty/freetype/include/freetype/ftchapters.h b/thirdparty/freetype/include/freetype/ftchapters.h
index 6a9733ad7c..7566fbd10f 100644
--- a/thirdparty/freetype/include/freetype/ftchapters.h
+++ b/thirdparty/freetype/include/freetype/ftchapters.h
@@ -31,9 +31,28 @@
* Core API
*
* @sections:
- * version
* basic_types
- * base_interface
+ * library_setup
+ * face_creation
+ * font_testing_macros
+ * sizing_and_scaling
+ * glyph_retrieval
+ * character_mapping
+ * information_retrieval
+ * other_api_data
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * @chapter:
+ * extended_api
+ *
+ * @title:
+ * Extended API
+ *
+ * @sections:
* glyph_variants
* color_management
* layer_management
diff --git a/thirdparty/freetype/include/freetype/ftdriver.h b/thirdparty/freetype/include/freetype/ftdriver.h
index f90946fd17..7af7465bc7 100644
--- a/thirdparty/freetype/include/freetype/ftdriver.h
+++ b/thirdparty/freetype/include/freetype/ftdriver.h
@@ -134,7 +134,7 @@ FT_BEGIN_HEADER
* each being rounded to the nearest pixel edge, taking care of overshoot
* suppression at small sizes, stem darkening, and scaling.
*
- * Hstems (this is, hint values defined in the font to help align
+ * Hstems (that is, hint values defined in the font to help align
* horizontal features) that fall within a blue zone are said to be
* 'captured' and are aligned to that zone. Uncaptured stems are moved
* in one of four ways, top edge up or down, bottom edge up or down.
@@ -446,7 +446,7 @@ FT_BEGIN_HEADER
* at smaller sizes.
*
* For the auto-hinter, stem-darkening is experimental currently and thus
- * switched off by default (this is, `no-stem-darkening` is set to TRUE
+ * switched off by default (that is, `no-stem-darkening` is set to TRUE
* by default). Total consistency with the CFF driver is not achieved
* right now because the emboldening method differs and glyphs must be
* scaled down on the Y-axis to keep outline points inside their
@@ -651,11 +651,8 @@ FT_BEGIN_HEADER
* Windows~98; only grayscale and B/W rasterizing is supported.
*
* TT_INTERPRETER_VERSION_38 ::
- * Version~38 corresponds to MS rasterizer v.1.9; it is roughly
- * equivalent to the hinting provided by DirectWrite ClearType (as can
- * be found, for example, in the Internet Explorer~9 running on
- * Windows~7). It is used in FreeType to select the 'Infinality'
- * subpixel hinting code. The code may be removed in a future version.
+ * Version~38 is the same Version~40. The original 'Infinality' code is
+ * no longer available.
*
* TT_INTERPRETER_VERSION_40 ::
* Version~40 corresponds to MS rasterizer v.2.1; it is roughly
diff --git a/thirdparty/freetype/include/freetype/ftimage.h b/thirdparty/freetype/include/freetype/ftimage.h
index 2e8e6734cc..6baa812560 100644
--- a/thirdparty/freetype/include/freetype/ftimage.h
+++ b/thirdparty/freetype/include/freetype/ftimage.h
@@ -19,7 +19,7 @@
/**************************************************************************
*
* Note: A 'raster' is simply a scan-line converter, used to render
- * FT_Outlines into FT_Bitmaps.
+ * `FT_Outline`s into `FT_Bitmap`s.
*
*/
@@ -256,6 +256,12 @@ FT_BEGIN_HEADER
* palette ::
* A typeless pointer to the bitmap palette; this field is intended for
* paletted pixel modes. Not used currently.
+ *
+ * @note:
+ * `width` and `rows` refer to the *physical* size of the bitmap, not the
+ * *logical* one. For example, if @FT_Pixel_Mode is set to
+ * `FT_PIXEL_MODE_LCD`, the logical width is a just a third of the
+ * physical one.
*/
typedef struct FT_Bitmap_
{
@@ -856,7 +862,7 @@ FT_BEGIN_HEADER
* @FT_SpanFunc that takes the y~coordinate of the span as a parameter.
*
* The anti-aliased rasterizer produces coverage values from 0 to 255,
- * this is, from completely transparent to completely opaque.
+ * that is, from completely transparent to completely opaque.
*/
typedef struct FT_Span_
{
diff --git a/thirdparty/freetype/include/freetype/ftlogging.h b/thirdparty/freetype/include/freetype/ftlogging.h
index 2246dc8365..53b8b89642 100644
--- a/thirdparty/freetype/include/freetype/ftlogging.h
+++ b/thirdparty/freetype/include/freetype/ftlogging.h
@@ -62,7 +62,7 @@ FT_BEGIN_HEADER
* component.
*
* ```
- * FT_Trace_Set_Level( "any:7 memory:0 );
+ * FT_Trace_Set_Level( "any:7 memory:0" );
* ```
*
* @note:
diff --git a/thirdparty/freetype/include/freetype/ftmm.h b/thirdparty/freetype/include/freetype/ftmm.h
index e381ef3d30..d145128a9b 100644
--- a/thirdparty/freetype/include/freetype/ftmm.h
+++ b/thirdparty/freetype/include/freetype/ftmm.h
@@ -153,7 +153,7 @@ FT_BEGIN_HEADER
* @note:
* The fields `minimum`, `def`, and `maximum` are 16.16 fractional values
* for TrueType GX and OpenType variation fonts. For Adobe MM fonts, the
- * values are integers.
+ * values are whole numbers (i.e., the fractional part is zero).
*/
typedef struct FT_Var_Axis_
{
@@ -399,8 +399,8 @@ FT_BEGIN_HEADER
*
* @note:
* The design coordinates are 16.16 fractional values for TrueType GX and
- * OpenType variation fonts. For Adobe MM fonts, the values are
- * integers.
+ * OpenType variation fonts. For Adobe MM fonts, the values are supposed
+ * to be whole numbers (i.e., the fractional part is zero).
*
* [Since 2.8.1] To reset all axes to the default values, call the
* function with `num_coords` set to zero and `coords` set to `NULL`.
@@ -446,8 +446,8 @@ FT_BEGIN_HEADER
*
* @note:
* The design coordinates are 16.16 fractional values for TrueType GX and
- * OpenType variation fonts. For Adobe MM fonts, the values are
- * integers.
+ * OpenType variation fonts. For Adobe MM fonts, the values are whole
+ * numbers (i.e., the fractional part is zero).
*
* @since:
* 2.7.1
@@ -602,10 +602,12 @@ FT_BEGIN_HEADER
*
* @note:
* Adobe Multiple Master fonts limit the number of designs, and thus the
- * length of the weight vector to~16.
+ * length of the weight vector to 16~elements.
*
- * If `len` is zero and `weightvector` is `NULL`, the weight vector array
- * is reset to the default values.
+ * If `len` is larger than zero, this function sets the
+ * @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field (i.e.,
+ * @FT_IS_VARIATION will return true). If `len` is zero, this bit flag
+ * is unset and the weight vector array is reset to the default values.
*
* The Adobe documentation also states that the values in the
* WeightVector array must total 1.0 +/-~0.001. In practice this does
@@ -753,6 +755,45 @@ FT_BEGIN_HEADER
FT_Set_Named_Instance( FT_Face face,
FT_UInt instance_index );
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Get_Default_Named_Instance
+ *
+ * @description:
+ * Retrieve the index of the default named instance, to be used with
+ * @FT_Set_Named_Instance.
+ *
+ * The default instance of a variation font is that instance for which
+ * the nth axis coordinate is equal to `axis[n].def` (as specified in the
+ * @FT_MM_Var structure), with~n covering all axes.
+ *
+ * FreeType synthesizes a named instance for the default instance if the
+ * font does not contain such an entry.
+ *
+ * @input:
+ * face ::
+ * A handle to the source face.
+ *
+ * @output:
+ * instance_index ::
+ * The index of the default named instance.
+ *
+ * @return:
+ * FreeType error code. 0~means success.
+ *
+ * @note:
+ * For Adobe MM fonts (which don't have named instances) this function
+ * always returns zero for `instance_index`.
+ *
+ * @since:
+ * 2.13.1
+ */
+ FT_EXPORT( FT_Error )
+ FT_Get_Default_Named_Instance( FT_Face face,
+ FT_UInt *instance_index );
+
/* */
diff --git a/thirdparty/freetype/include/freetype/ftoutln.h b/thirdparty/freetype/include/freetype/ftoutln.h
index 54434b25f6..f9329ca40c 100644
--- a/thirdparty/freetype/include/freetype/ftoutln.h
+++ b/thirdparty/freetype/include/freetype/ftoutln.h
@@ -118,7 +118,7 @@ FT_BEGIN_HEADER
* attachement.
*
* Similarly, the function returns success for an empty outline also
- * (doing nothing, this is, not calling any emitter); if necessary, you
+ * (doing nothing, that is, not calling any emitter); if necessary, you
* should filter this out, too.
*/
FT_EXPORT( FT_Error )
diff --git a/thirdparty/freetype/include/freetype/ftrender.h b/thirdparty/freetype/include/freetype/ftrender.h
index a8576dab00..0b6fad32e8 100644
--- a/thirdparty/freetype/include/freetype/ftrender.h
+++ b/thirdparty/freetype/include/freetype/ftrender.h
@@ -158,7 +158,7 @@ FT_BEGIN_HEADER
FT_Renderer_GetCBoxFunc get_glyph_cbox;
FT_Renderer_SetModeFunc set_mode;
- FT_Raster_Funcs* raster_class;
+ const FT_Raster_Funcs* raster_class;
} FT_Renderer_Class;
diff --git a/thirdparty/freetype/include/freetype/ftsynth.h b/thirdparty/freetype/include/freetype/ftsynth.h
index 5d19697657..af90967dda 100644
--- a/thirdparty/freetype/include/freetype/ftsynth.h
+++ b/thirdparty/freetype/include/freetype/ftsynth.h
@@ -68,6 +68,18 @@ FT_BEGIN_HEADER
FT_EXPORT( void )
FT_GlyphSlot_Embolden( FT_GlyphSlot slot );
+ /* Precisely adjust the glyph weight either horizontally or vertically. */
+ /* The `xdelta` and `ydelta` values are fractions of the face Em size */
+ /* (in fixed-point format). Considering that a regular face would have */
+ /* stem widths on the order of 0.1 Em, a delta of 0.05 (0x0CCC) should */
+ /* be very noticeable. To increase or decrease the weight, use positive */
+ /* or negative values, respectively. */
+ FT_EXPORT( void )
+ FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot,
+ FT_Fixed xdelta,
+ FT_Fixed ydelta );
+
+
/* Slant an outline glyph to the right by about 12 degrees. */
FT_EXPORT( void )
FT_GlyphSlot_Oblique( FT_GlyphSlot slot );
diff --git a/thirdparty/freetype/include/freetype/ftsystem.h b/thirdparty/freetype/include/freetype/ftsystem.h
index a995b078de..3a08f4912c 100644
--- a/thirdparty/freetype/include/freetype/ftsystem.h
+++ b/thirdparty/freetype/include/freetype/ftsystem.h
@@ -229,8 +229,7 @@ FT_BEGIN_HEADER
* A handle to the source stream.
*
* offset ::
- * The offset from the start of the stream to seek to if this is a seek
- * operation (see note).
+ * The offset from the start of the stream to seek to.
*
* buffer ::
* The address of the read buffer.
@@ -239,16 +238,9 @@ FT_BEGIN_HEADER
* The number of bytes to read from the stream.
*
* @return:
- * The number of bytes effectively read by the stream.
- *
- * @note:
- * This function performs a seek *or* a read operation depending on the
- * argument values. If `count` is zero, the operation is a seek to
- * `offset` bytes. If `count` is >~0, the operation is a read of `count`
- * bytes from the current position in the stream, and the `offset` value
- * should be ignored.
- *
- * For seek operations, a non-zero return value indicates an error.
+ * If count >~0, return the number of bytes effectively read by the
+ * stream (after seeking to `offset`). If count ==~0, return the status
+ * of the seek operation (non-zero indicates an error).
*
*/
typedef unsigned long
diff --git a/thirdparty/freetype/include/freetype/internal/compiler-macros.h b/thirdparty/freetype/include/freetype/internal/compiler-macros.h
index 7883317fed..6f67650979 100644
--- a/thirdparty/freetype/include/freetype/internal/compiler-macros.h
+++ b/thirdparty/freetype/include/freetype/internal/compiler-macros.h
@@ -41,8 +41,11 @@ FT_BEGIN_HEADER
# if ( defined( __STDC_VERSION__ ) && __STDC_VERSION__ > 201710L ) || \
( defined( __cplusplus ) && __cplusplus > 201402L )
# define FALL_THROUGH [[__fallthrough__]]
-# elif ( defined( __GNUC__ ) && __GNUC__ >= 7 ) || \
- ( defined( __clang__ ) && __clang_major__ >= 10 )
+# elif ( defined( __GNUC__ ) && __GNUC__ >= 7 ) || \
+ ( defined( __clang__ ) && \
+ ( defined( __apple_build_version__ ) \
+ ? __apple_build_version__ >= 12000000 \
+ : __clang_major__ >= 10 ) )
# define FALL_THROUGH __attribute__(( __fallthrough__ ))
# else
# define FALL_THROUGH ( (void)0 )
diff --git a/thirdparty/freetype/include/freetype/internal/ftdrv.h b/thirdparty/freetype/include/freetype/internal/ftdrv.h
index f78912ca0c..9001c07ad0 100644
--- a/thirdparty/freetype/include/freetype/internal/ftdrv.h
+++ b/thirdparty/freetype/include/freetype/internal/ftdrv.h
@@ -157,6 +157,7 @@ FT_BEGIN_HEADER
* A handle to a function used to select a new fixed size. It is used
* only if @FT_FACE_FLAG_FIXED_SIZES is set. Can be set to 0 if the
* scaling done in the base layer suffices.
+ *
* @note:
* Most function pointers, with the exception of `load_glyph`, can be set
* to 0 to indicate a default behaviour.
diff --git a/thirdparty/freetype/include/freetype/internal/ftmmtypes.h b/thirdparty/freetype/include/freetype/internal/ftmmtypes.h
index b7c66c35de..c4b21d6144 100644
--- a/thirdparty/freetype/include/freetype/internal/ftmmtypes.h
+++ b/thirdparty/freetype/include/freetype/internal/ftmmtypes.h
@@ -28,13 +28,19 @@ FT_BEGIN_HEADER
typedef struct GX_ItemVarDataRec_
{
- FT_UInt itemCount; /* number of delta sets per item */
- FT_UInt regionIdxCount; /* number of region indices */
- FT_UInt* regionIndices; /* array of `regionCount' indices; */
- /* these index `varRegionList' */
- FT_ItemVarDelta* deltaSet; /* array of `itemCount' deltas */
- /* use `innerIndex' for this array */
-
+ FT_UInt itemCount; /* Number of delta sets per item. */
+ FT_UInt regionIdxCount; /* Number of region indices. */
+ FT_UInt* regionIndices; /* Array of `regionCount` indices; */
+ /* these index `varRegionList`. */
+ FT_Byte* deltaSet; /* Array of `itemCount` deltas; */
+ /* use `innerIndex` for this array. */
+ FT_UShort wordDeltaCount; /* Number of the first 32-bit ints */
+ /* or 16-bit ints of `deltaSet` */
+ /* depending on `longWords`. */
+ FT_Bool longWords; /* If true, `deltaSet` is a 32-bit */
+ /* array followed by a 16-bit */
+ /* array, otherwise a 16-bit array */
+ /* followed by an 8-bit array. */
} GX_ItemVarDataRec, *GX_ItemVarData;
diff --git a/thirdparty/freetype/include/freetype/internal/services/svmetric.h b/thirdparty/freetype/include/freetype/internal/services/svmetric.h
index e588ea4872..167617ebb3 100644
--- a/thirdparty/freetype/include/freetype/internal/services/svmetric.h
+++ b/thirdparty/freetype/include/freetype/internal/services/svmetric.h
@@ -77,6 +77,9 @@ FT_BEGIN_HEADER
typedef void
(*FT_Metrics_Adjust_Func)( FT_Face face );
+ typedef FT_Error
+ (*FT_Size_Reset_Func)( FT_Size size );
+
FT_DEFINE_SERVICE( MetricsVariations )
{
@@ -90,6 +93,7 @@ FT_BEGIN_HEADER
FT_VOrg_Adjust_Func vorg_adjust;
FT_Metrics_Adjust_Func metrics_adjust;
+ FT_Size_Reset_Func size_reset;
};
@@ -101,7 +105,8 @@ FT_BEGIN_HEADER
tsb_adjust_, \
bsb_adjust_, \
vorg_adjust_, \
- metrics_adjust_ ) \
+ metrics_adjust_, \
+ size_reset_ ) \
static const FT_Service_MetricsVariationsRec class_ = \
{ \
hadvance_adjust_, \
@@ -111,7 +116,8 @@ FT_BEGIN_HEADER
tsb_adjust_, \
bsb_adjust_, \
vorg_adjust_, \
- metrics_adjust_ \
+ metrics_adjust_, \
+ size_reset_ \
};
/* */
diff --git a/thirdparty/freetype/include/freetype/internal/services/svmm.h b/thirdparty/freetype/include/freetype/internal/services/svmm.h
index d94204232e..7e76ab8324 100644
--- a/thirdparty/freetype/include/freetype/internal/services/svmm.h
+++ b/thirdparty/freetype/include/freetype/internal/services/svmm.h
@@ -60,9 +60,9 @@ FT_BEGIN_HEADER
/* use return value -1 to indicate that the new coordinates */
/* are equal to the current ones; no changes are thus needed */
typedef FT_Error
- (*FT_Set_MM_Blend_Func)( FT_Face face,
- FT_UInt num_coords,
- FT_Long* coords );
+ (*FT_Set_MM_Blend_Func)( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
typedef FT_Error
(*FT_Get_Var_Design_Func)( FT_Face face,
@@ -70,13 +70,17 @@ FT_BEGIN_HEADER
FT_Fixed* coords );
typedef FT_Error
- (*FT_Set_Instance_Func)( FT_Face face,
- FT_UInt instance_index );
+ (*FT_Set_Named_Instance_Func)( FT_Face face,
+ FT_UInt instance_index );
typedef FT_Error
- (*FT_Get_MM_Blend_Func)( FT_Face face,
- FT_UInt num_coords,
- FT_Long* coords );
+ (*FT_Get_Default_Named_Instance_Func)( FT_Face face,
+ FT_UInt *instance_index );
+
+ typedef FT_Error
+ (*FT_Get_MM_Blend_Func)( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
typedef FT_Error
(*FT_Get_Var_Blend_Func)( FT_Face face,
@@ -86,7 +90,7 @@ FT_BEGIN_HEADER
FT_MM_Var* *mm_var );
typedef void
- (*FT_Done_Blend_Func)( FT_Face );
+ (*FT_Done_Blend_Func)( FT_Face face );
typedef FT_Error
(*FT_Set_MM_WeightVector_Func)( FT_Face face,
@@ -98,6 +102,9 @@ FT_BEGIN_HEADER
FT_UInt* len,
FT_Fixed* weight_vector );
+ typedef void
+ (*FT_Construct_PS_Name_Func)( FT_Face face );
+
typedef FT_Error
(*FT_Var_Load_Delta_Set_Idx_Map_Func)( FT_Face face,
FT_ULong offset,
@@ -134,11 +141,13 @@ FT_BEGIN_HEADER
FT_Get_MM_Var_Func get_mm_var;
FT_Set_Var_Design_Func set_var_design;
FT_Get_Var_Design_Func get_var_design;
- FT_Set_Instance_Func set_instance;
+ FT_Set_Named_Instance_Func set_named_instance;
+ FT_Get_Default_Named_Instance_Func get_default_named_instance;
FT_Set_MM_WeightVector_Func set_mm_weightvector;
FT_Get_MM_WeightVector_Func get_mm_weightvector;
/* for internal use; only needed for code sharing between modules */
+ FT_Construct_PS_Name_Func construct_ps_name;
FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map;
FT_Var_Load_Item_Var_Store_Func load_item_var_store;
FT_Var_Get_Item_Delta_Func get_item_delta;
@@ -149,43 +158,49 @@ FT_BEGIN_HEADER
};
-#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \
- get_mm_, \
- set_mm_design_, \
- set_mm_blend_, \
- get_mm_blend_, \
- get_mm_var_, \
- set_var_design_, \
- get_var_design_, \
- set_instance_, \
- set_weightvector_, \
- get_weightvector_, \
- load_delta_set_idx_map_, \
- load_item_var_store_, \
- get_item_delta_, \
- done_item_var_store_, \
- done_delta_set_idx_map_, \
- get_var_blend_, \
- done_blend_ ) \
- static const FT_Service_MultiMastersRec class_ = \
- { \
- get_mm_, \
- set_mm_design_, \
- set_mm_blend_, \
- get_mm_blend_, \
- get_mm_var_, \
- set_var_design_, \
- get_var_design_, \
- set_instance_, \
- set_weightvector_, \
- get_weightvector_, \
- load_delta_set_idx_map_, \
- load_item_var_store_, \
- get_item_delta_, \
- done_item_var_store_, \
- done_delta_set_idx_map_, \
- get_var_blend_, \
- done_blend_ \
+#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \
+ get_mm_, \
+ set_mm_design_, \
+ set_mm_blend_, \
+ get_mm_blend_, \
+ get_mm_var_, \
+ set_var_design_, \
+ get_var_design_, \
+ set_named_instance_, \
+ get_default_named_instance_, \
+ set_mm_weightvector_, \
+ get_mm_weightvector_, \
+ \
+ construct_ps_name_, \
+ load_delta_set_idx_map_, \
+ load_item_var_store_, \
+ get_item_delta_, \
+ done_item_var_store_, \
+ done_delta_set_idx_map_, \
+ get_var_blend_, \
+ done_blend_ ) \
+ static const FT_Service_MultiMastersRec class_ = \
+ { \
+ get_mm_, \
+ set_mm_design_, \
+ set_mm_blend_, \
+ get_mm_blend_, \
+ get_mm_var_, \
+ set_var_design_, \
+ get_var_design_, \
+ set_named_instance_, \
+ get_default_named_instance_, \
+ set_mm_weightvector_, \
+ get_mm_weightvector_, \
+ \
+ construct_ps_name_, \
+ load_delta_set_idx_map_, \
+ load_item_var_store_, \
+ get_item_delta_, \
+ done_item_var_store_, \
+ done_delta_set_idx_map_, \
+ get_var_blend_, \
+ done_blend_ \
};
/* */
diff --git a/thirdparty/freetype/include/freetype/internal/services/svpscmap.h b/thirdparty/freetype/include/freetype/internal/services/svpscmap.h
index fd99d857e4..6e599f3aab 100644
--- a/thirdparty/freetype/include/freetype/internal/services/svpscmap.h
+++ b/thirdparty/freetype/include/freetype/internal/services/svpscmap.h
@@ -97,7 +97,7 @@ FT_BEGIN_HEADER
(*PS_Unicodes_CharIndexFunc)( PS_Unicodes unicodes,
FT_UInt32 unicode );
- typedef FT_UInt32
+ typedef FT_UInt
(*PS_Unicodes_CharNextFunc)( PS_Unicodes unicodes,
FT_UInt32 *unicode );
diff --git a/thirdparty/freetype/include/freetype/internal/t1types.h b/thirdparty/freetype/include/freetype/internal/t1types.h
index 5a105c5879..b9c94398fd 100644
--- a/thirdparty/freetype/include/freetype/internal/t1types.h
+++ b/thirdparty/freetype/include/freetype/internal/t1types.h
@@ -201,30 +201,30 @@ FT_BEGIN_HEADER
typedef struct T1_FaceRec_
{
- FT_FaceRec root;
- T1_FontRec type1;
- const void* psnames;
- const void* psaux;
- const void* afm_data;
- FT_CharMapRec charmaprecs[2];
- FT_CharMap charmaps[2];
+ FT_FaceRec root;
+ T1_FontRec type1;
+ const void* psnames;
+ const void* psaux;
+ const void* afm_data;
+ FT_CharMapRec charmaprecs[2];
+ FT_CharMap charmaps[2];
/* support for Multiple Masters fonts */
- PS_Blend blend;
+ PS_Blend blend;
/* undocumented, optional: indices of subroutines that express */
/* the NormalizeDesignVector and the ConvertDesignVector procedure, */
/* respectively, as Type 2 charstrings; -1 if keywords not present */
- FT_Int ndv_idx;
- FT_Int cdv_idx;
+ FT_Int ndv_idx;
+ FT_Int cdv_idx;
/* undocumented, optional: has the same meaning as len_buildchar */
/* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25 */
- FT_UInt len_buildchar;
- FT_Long* buildchar;
+ FT_UInt len_buildchar;
+ FT_Long* buildchar;
/* since version 2.1 - interface to PostScript hinter */
- const void* pshinter;
+ const void* pshinter;
} T1_FaceRec;
diff --git a/thirdparty/freetype/include/freetype/internal/tttypes.h b/thirdparty/freetype/include/freetype/internal/tttypes.h
index 3b521924ca..984121a0e4 100644
--- a/thirdparty/freetype/include/freetype/internal/tttypes.h
+++ b/thirdparty/freetype/include/freetype/internal/tttypes.h
@@ -779,13 +779,15 @@ FT_BEGIN_HEADER
/**************************************************************************
*
* @struct:
- * TT_Post_20Rec
+ * TT_Post_NamesRec
*
* @description:
- * Postscript names sub-table, format 2.0. Stores the PS name of each
- * glyph in the font face.
+ * Postscript names table, either format 2.0 or 2.5.
*
* @fields:
+ * loaded ::
+ * A flag to indicate whether the PS names are loaded.
+ *
* num_glyphs ::
* The number of named glyphs in the table.
*
@@ -798,68 +800,13 @@ FT_BEGIN_HEADER
* glyph_names ::
* The PS names not in Mac Encoding.
*/
- typedef struct TT_Post_20Rec_
+ typedef struct TT_Post_NamesRec_
{
+ FT_Bool loaded;
FT_UShort num_glyphs;
FT_UShort num_names;
FT_UShort* glyph_indices;
- FT_Char** glyph_names;
-
- } TT_Post_20Rec, *TT_Post_20;
-
-
- /**************************************************************************
- *
- * @struct:
- * TT_Post_25Rec
- *
- * @description:
- * Postscript names sub-table, format 2.5. Stores the PS name of each
- * glyph in the font face.
- *
- * @fields:
- * num_glyphs ::
- * The number of glyphs in the table.
- *
- * offsets ::
- * An array of signed offsets in a normal Mac Postscript name encoding.
- */
- typedef struct TT_Post_25_
- {
- FT_UShort num_glyphs;
- FT_Char* offsets;
-
- } TT_Post_25Rec, *TT_Post_25;
-
-
- /**************************************************************************
- *
- * @struct:
- * TT_Post_NamesRec
- *
- * @description:
- * Postscript names table, either format 2.0 or 2.5.
- *
- * @fields:
- * loaded ::
- * A flag to indicate whether the PS names are loaded.
- *
- * format_20 ::
- * The sub-table used for format 2.0.
- *
- * format_25 ::
- * The sub-table used for format 2.5.
- */
- typedef struct TT_Post_NamesRec_
- {
- FT_Bool loaded;
-
- union
- {
- TT_Post_20Rec format_20;
- TT_Post_25Rec format_25;
-
- } names;
+ FT_Byte** glyph_names;
} TT_Post_NamesRec, *TT_Post_Names;
@@ -1253,12 +1200,16 @@ FT_BEGIN_HEADER
* mm ::
* A pointer to the Multiple Masters service.
*
- * var ::
- * A pointer to the Metrics Variations service.
+ * tt_var ::
+ * A pointer to the Metrics Variations service for the "truetype"
+ * driver.
*
- * hdmx ::
- * The face's horizontal device metrics ('hdmx' table). This table is
- * optional in TrueType/OpenType fonts.
+ * face_var ::
+ * A pointer to the Metrics Variations service for this `TT_Face`'s
+ * driver.
+ *
+ * psaux ::
+ * A pointer to the PostScript Auxiliary service.
*
* gasp ::
* The grid-fitting and scaling properties table ('gasp'). This table
@@ -1364,6 +1315,12 @@ FT_BEGIN_HEADER
* var_postscript_prefix_len ::
* The length of the `var_postscript_prefix` string.
*
+ * var_default_named_instance ::
+ * The index of the default named instance.
+ *
+ * non_var_style_name ::
+ * The non-variation style name, used as a backup.
+ *
* horz_metrics_size ::
* The size of the 'hmtx' table.
*
@@ -1410,14 +1367,6 @@ FT_BEGIN_HEADER
* A mapping between the strike indices exposed by the API and the
* indices used in the font's sbit table.
*
- * cpal ::
- * A pointer to data related to the 'CPAL' table. `NULL` if the table
- * is not available.
- *
- * colr ::
- * A pointer to data related to the 'COLR' table. `NULL` if the table
- * is not available.
- *
* kern_table ::
* A pointer to the 'kern' table.
*
@@ -1458,6 +1407,18 @@ FT_BEGIN_HEADER
*
* ebdt_size ::
* The size of the sbit data table.
+ *
+ * cpal ::
+ * A pointer to data related to the 'CPAL' table. `NULL` if the table
+ * is not available.
+ *
+ * colr ::
+ * A pointer to data related to the 'COLR' table. `NULL` if the table
+ * is not available.
+ *
+ * svg ::
+ * A pointer to data related to the 'SVG' table. `NULL` if the table
+ * is not available.
*/
typedef struct TT_FaceRec_
{
@@ -1508,8 +1469,14 @@ FT_BEGIN_HEADER
void* mm;
/* a typeless pointer to the FT_Service_MetricsVariationsRec table */
- /* used to handle the HVAR, VVAR, and MVAR OpenType tables */
- void* var;
+ /* used to handle the HVAR, VVAR, and MVAR OpenType tables by the */
+ /* "truetype" driver */
+ void* tt_var;
+
+ /* a typeless pointer to the FT_Service_MetricsVariationsRec table */
+ /* used to handle the HVAR, VVAR, and MVAR OpenType tables by this */
+ /* TT_Face's driver */
+ void* face_var; /* since 2.13.1 */
#endif
/* a typeless pointer to the PostScript Aux service */
@@ -1591,6 +1558,9 @@ FT_BEGIN_HEADER
const char* var_postscript_prefix; /* since 2.7.2 */
FT_UInt var_postscript_prefix_len; /* since 2.7.2 */
+ FT_UInt var_default_named_instance; /* since 2.13.1 */
+
+ const char* non_var_style_name; /* since 2.13.1 */
#endif
/* since version 2.2 */
diff --git a/thirdparty/freetype/src/autofit/afcjk.c b/thirdparty/freetype/src/autofit/afcjk.c
index 5daefff359..af775b190c 100644
--- a/thirdparty/freetype/src/autofit/afcjk.c
+++ b/thirdparty/freetype/src/autofit/afcjk.c
@@ -417,16 +417,14 @@
{
FT_Int nn;
- FT_Int first = 0;
- FT_Int last = -1;
+ FT_Int pp, first, last;
- for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
+ last = -1;
+ for ( nn = 0; nn < outline.n_contours; nn++ )
{
- FT_Int pp;
-
-
- last = outline.contours[nn];
+ first = last + 1;
+ last = outline.contours[nn];
/* Avoid single-point contours since they are never rasterized. */
/* In some fonts, they correspond to mark attachment points */
@@ -569,8 +567,8 @@
af_cjk_metrics_check_digits( AF_CJKMetrics metrics,
FT_Face face )
{
- FT_Bool started = 0, same_width = 1;
- FT_Fixed advance = 0, old_advance = 0;
+ FT_Bool started = 0, same_width = 1;
+ FT_Long advance = 0, old_advance = 0;
/* If HarfBuzz is not available, we need a pointer to a single */
/* unsigned long value. */
@@ -635,10 +633,11 @@
/* Initialize global metrics. */
FT_LOCAL_DEF( FT_Error )
- af_cjk_metrics_init( AF_CJKMetrics metrics,
- FT_Face face )
+ af_cjk_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ FT_Face face )
{
- FT_CharMap oldmap = face->charmap;
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+ FT_CharMap oldmap = face->charmap;
metrics->units_per_em = face->units_per_EM;
@@ -756,9 +755,12 @@
/* Scale global values in both directions. */
FT_LOCAL_DEF( void )
- af_cjk_metrics_scale( AF_CJKMetrics metrics,
- AF_Scaler scaler )
+ af_cjk_metrics_scale( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ AF_Scaler scaler )
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
+
/* we copy the whole structure since the x and y scaling values */
/* are not modified, contrary to e.g. the `latin' auto-hinter */
metrics->root.scaler = *scaler;
@@ -771,11 +773,14 @@
/* Extract standard_width from writing system/script specific */
/* metrics class. */
- FT_LOCAL_DEF( void )
- af_cjk_get_standard_widths( AF_CJKMetrics metrics,
- FT_Pos* stdHW,
- FT_Pos* stdVW )
+ FT_CALLBACK_DEF( void )
+ af_cjk_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ FT_Pos* stdHW,
+ FT_Pos* stdVW )
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
+
if ( stdHW )
*stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
@@ -1376,9 +1381,10 @@
/* Initalize hinting engine. */
FT_LOCAL_DEF( FT_Error )
- af_cjk_hints_init( AF_GlyphHints hints,
- AF_CJKMetrics metrics )
+ af_cjk_hints_init( AF_GlyphHints hints,
+ AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
FT_Render_Mode mode;
FT_UInt32 scaler_flags, other_flags;
@@ -2268,11 +2274,13 @@
/* Apply the complete hinting algorithm to a CJK glyph. */
FT_LOCAL_DEF( FT_Error )
- af_cjk_hints_apply( FT_UInt glyph_index,
- AF_GlyphHints hints,
- FT_Outline* outline,
- AF_CJKMetrics metrics )
+ af_cjk_hints_apply( FT_UInt glyph_index,
+ AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
FT_Error error;
int dim;
diff --git a/thirdparty/freetype/src/autofit/afcjk.h b/thirdparty/freetype/src/autofit/afcjk.h
index bd7b81b3e2..f380ef6e03 100644
--- a/thirdparty/freetype/src/autofit/afcjk.h
+++ b/thirdparty/freetype/src/autofit/afcjk.h
@@ -103,22 +103,22 @@ FT_BEGIN_HEADER
#ifdef AF_CONFIG_OPTION_CJK
FT_LOCAL( FT_Error )
- af_cjk_metrics_init( AF_CJKMetrics metrics,
- FT_Face face );
+ af_cjk_metrics_init( AF_StyleMetrics metrics,
+ FT_Face face );
FT_LOCAL( void )
- af_cjk_metrics_scale( AF_CJKMetrics metrics,
- AF_Scaler scaler );
+ af_cjk_metrics_scale( AF_StyleMetrics metrics,
+ AF_Scaler scaler );
FT_LOCAL( FT_Error )
- af_cjk_hints_init( AF_GlyphHints hints,
- AF_CJKMetrics metrics );
+ af_cjk_hints_init( AF_GlyphHints hints,
+ AF_StyleMetrics metrics );
FT_LOCAL( FT_Error )
- af_cjk_hints_apply( FT_UInt glyph_index,
- AF_GlyphHints hints,
- FT_Outline* outline,
- AF_CJKMetrics metrics );
+ af_cjk_hints_apply( FT_UInt glyph_index,
+ AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_StyleMetrics metrics );
/* shared; called from afindic.c */
FT_LOCAL( void )
diff --git a/thirdparty/freetype/src/autofit/afglobal.c b/thirdparty/freetype/src/autofit/afglobal.c
index ede27eb166..b1957570f0 100644
--- a/thirdparty/freetype/src/autofit/afglobal.c
+++ b/thirdparty/freetype/src/autofit/afglobal.c
@@ -376,8 +376,11 @@
FT_LOCAL_DEF( void )
- af_face_globals_free( AF_FaceGlobals globals )
+ af_face_globals_free( void* globals_ )
{
+ AF_FaceGlobals globals = (AF_FaceGlobals)globals_;
+
+
if ( globals )
{
FT_Memory memory = globals->face->memory;
diff --git a/thirdparty/freetype/src/autofit/afglobal.h b/thirdparty/freetype/src/autofit/afglobal.h
index 83a7c2ff15..66170e419d 100644
--- a/thirdparty/freetype/src/autofit/afglobal.h
+++ b/thirdparty/freetype/src/autofit/afglobal.h
@@ -156,7 +156,7 @@ FT_BEGIN_HEADER
AF_StyleMetrics *ametrics );
FT_LOCAL( void )
- af_face_globals_free( AF_FaceGlobals globals );
+ af_face_globals_free( void* globals );
FT_LOCAL( FT_Bool )
af_face_globals_is_digit( AF_FaceGlobals globals,
diff --git a/thirdparty/freetype/src/autofit/afhints.c b/thirdparty/freetype/src/autofit/afhints.c
index 6515af9f04..e4a378fbf7 100644
--- a/thirdparty/freetype/src/autofit/afhints.c
+++ b/thirdparty/freetype/src/autofit/afhints.c
@@ -320,8 +320,9 @@
static char*
- af_print_idx( char* p,
- int idx )
+ af_print_idx( char* p,
+ size_t n,
+ int idx )
{
if ( idx == -1 )
{
@@ -330,7 +331,7 @@
p[2] = '\0';
}
else
- ft_sprintf( p, "%d", idx );
+ ft_snprintf( p, n, "%d", idx );
return p;
}
@@ -457,12 +458,12 @@
" %5d %5d %7.2f %7.2f %7.2f %7.2f"
" %5s %5s %5s %5s\n",
point_idx,
- af_print_idx( buf1,
+ af_print_idx( buf1, 16,
af_get_edge_index( hints, segment_idx_1, 1 ) ),
- af_print_idx( buf2, segment_idx_1 ),
- af_print_idx( buf3,
+ af_print_idx( buf2, 16, segment_idx_1 ),
+ af_print_idx( buf3, 16,
af_get_edge_index( hints, segment_idx_0, 0 ) ),
- af_print_idx( buf4, segment_idx_0 ),
+ af_print_idx( buf4, 16, segment_idx_0 ),
( point->flags & AF_FLAG_NEAR )
? " near "
: ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
@@ -476,18 +477,22 @@
(double)point->x / 64,
(double)point->y / 64,
- af_print_idx( buf5, af_get_strong_edge_index( hints,
- point->before,
- 1 ) ),
- af_print_idx( buf6, af_get_strong_edge_index( hints,
- point->after,
- 1 ) ),
- af_print_idx( buf7, af_get_strong_edge_index( hints,
- point->before,
- 0 ) ),
- af_print_idx( buf8, af_get_strong_edge_index( hints,
- point->after,
- 0 ) ) ));
+ af_print_idx( buf5, 16,
+ af_get_strong_edge_index( hints,
+ point->before,
+ 1 ) ),
+ af_print_idx( buf6, 16,
+ af_get_strong_edge_index( hints,
+ point->after,
+ 1 ) ),
+ af_print_idx( buf7, 16,
+ af_get_strong_edge_index( hints,
+ point->before,
+ 0 ) ),
+ af_print_idx( buf8, 16,
+ af_get_strong_edge_index( hints,
+ point->after,
+ 0 ) ) ));
}
AF_DUMP(( "\n" ));
}
@@ -574,9 +579,12 @@
AF_INDEX_NUM( seg->first, points ),
AF_INDEX_NUM( seg->last, points ),
- af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ),
- af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ),
- af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ),
+ af_print_idx( buf1, 16,
+ AF_INDEX_NUM( seg->link, segments ) ),
+ af_print_idx( buf2, 16,
+ AF_INDEX_NUM( seg->serif, segments ) ),
+ af_print_idx( buf3, 16,
+ AF_INDEX_NUM( seg->edge, edges ) ),
seg->height,
seg->height - ( seg->max_coord - seg->min_coord ),
@@ -716,8 +724,10 @@
AF_INDEX_NUM( edge, edges ),
(double)(int)edge->opos / 64,
af_dir_str( (AF_Direction)edge->dir ),
- af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ),
- af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ),
+ af_print_idx( buf1, 16,
+ AF_INDEX_NUM( edge->link, edges ) ),
+ af_print_idx( buf2, 16,
+ AF_INDEX_NUM( edge->serif, edges ) ),
edge->blue_edge ? 'y' : 'n',
(double)edge->opos / 64,
diff --git a/thirdparty/freetype/src/autofit/afindic.c b/thirdparty/freetype/src/autofit/afindic.c
index 289a09d71d..7fb12c63d5 100644
--- a/thirdparty/freetype/src/autofit/afindic.c
+++ b/thirdparty/freetype/src/autofit/afindic.c
@@ -28,9 +28,12 @@
static FT_Error
- af_indic_metrics_init( AF_CJKMetrics metrics,
- FT_Face face )
+ af_indic_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ FT_Face face )
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
+
/* skip blue zone init in CJK routines */
FT_CharMap oldmap = face->charmap;
@@ -55,8 +58,8 @@
static void
- af_indic_metrics_scale( AF_CJKMetrics metrics,
- AF_Scaler scaler )
+ af_indic_metrics_scale( AF_StyleMetrics metrics,
+ AF_Scaler scaler )
{
/* use CJK routines */
af_cjk_metrics_scale( metrics, scaler );
@@ -64,8 +67,8 @@
static FT_Error
- af_indic_hints_init( AF_GlyphHints hints,
- AF_CJKMetrics metrics )
+ af_indic_hints_init( AF_GlyphHints hints,
+ AF_StyleMetrics metrics )
{
/* use CJK routines */
return af_cjk_hints_init( hints, metrics );
@@ -73,10 +76,10 @@
static FT_Error
- af_indic_hints_apply( FT_UInt glyph_index,
- AF_GlyphHints hints,
- FT_Outline* outline,
- AF_CJKMetrics metrics )
+ af_indic_hints_apply( FT_UInt glyph_index,
+ AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_StyleMetrics metrics )
{
/* use CJK routines */
return af_cjk_hints_apply( glyph_index, hints, outline, metrics );
@@ -87,10 +90,13 @@
/* metrics class. */
static void
- af_indic_get_standard_widths( AF_CJKMetrics metrics,
- FT_Pos* stdHW,
- FT_Pos* stdVW )
+ af_indic_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ FT_Pos* stdHW,
+ FT_Pos* stdVW )
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
+
if ( stdHW )
*stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
diff --git a/thirdparty/freetype/src/autofit/aflatin.c b/thirdparty/freetype/src/autofit/aflatin.c
index 4b3c59b3c3..46c6e450a8 100644
--- a/thirdparty/freetype/src/autofit/aflatin.c
+++ b/thirdparty/freetype/src/autofit/aflatin.c
@@ -496,23 +496,20 @@
/* now compute min or max point indices and coordinates */
points = outline.points;
best_point = -1;
+ best_contour_first = -1;
+ best_contour_last = -1;
best_y = 0; /* make compiler happy */
- best_contour_first = 0; /* ditto */
- best_contour_last = 0; /* ditto */
{
FT_Int nn;
- FT_Int first = 0;
- FT_Int last = -1;
+ FT_Int pp, first, last;
- for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
+ last = -1;
+ for ( nn = 0; nn < outline.n_contours; nn++ )
{
- FT_Int old_best_point = best_point;
- FT_Int pp;
-
-
- last = outline.contours[nn];
+ first = last + 1;
+ last = outline.contours[nn];
/* Avoid single-point contours since they are never */
/* rasterized. In some fonts, they correspond to mark */
@@ -551,7 +548,7 @@
}
}
- if ( best_point != old_best_point )
+ if ( best_point > best_contour_last )
{
best_contour_first = first;
best_contour_last = last;
@@ -1068,8 +1065,8 @@
af_latin_metrics_check_digits( AF_LatinMetrics metrics,
FT_Face face )
{
- FT_Bool started = 0, same_width = 1;
- FT_Fixed advance = 0, old_advance = 0;
+ FT_Bool started = 0, same_width = 1;
+ FT_Long advance = 0, old_advance = 0;
/* If HarfBuzz is not available, we need a pointer to a single */
/* unsigned long value. */
@@ -1134,9 +1131,11 @@
/* Initialize global metrics. */
FT_LOCAL_DEF( FT_Error )
- af_latin_metrics_init( AF_LatinMetrics metrics,
+ af_latin_metrics_init( AF_StyleMetrics metrics_, /* AF_LatinMetrics */
FT_Face face )
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
FT_Error error = FT_Err_Ok;
FT_CharMap oldmap = face->charmap;
@@ -1489,9 +1488,12 @@
/* Scale global values in both directions. */
FT_LOCAL_DEF( void )
- af_latin_metrics_scale( AF_LatinMetrics metrics,
+ af_latin_metrics_scale( AF_StyleMetrics metrics_, /* AF_LatinMetrics */
AF_Scaler scaler )
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
+
metrics->root.scaler.render_mode = scaler->render_mode;
metrics->root.scaler.face = scaler->face;
metrics->root.scaler.flags = scaler->flags;
@@ -1504,11 +1506,14 @@
/* Extract standard_width from writing system/script specific */
/* metrics class. */
- FT_LOCAL_DEF( void )
- af_latin_get_standard_widths( AF_LatinMetrics metrics,
+ FT_CALLBACK_DEF( void )
+ af_latin_get_standard_widths( AF_StyleMetrics metrics_, /* AF_LatinMetrics */
FT_Pos* stdHW,
FT_Pos* stdVW )
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
+
if ( stdHW )
*stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
@@ -2041,7 +2046,7 @@
max = seg2->max_coord;
/* compute maximum coordinate difference of the two segments */
- /* (this is, how much they overlap) */
+ /* (that is, how much they overlap) */
len = max - min;
if ( len >= len_threshold )
{
@@ -2610,8 +2615,10 @@
static FT_Error
af_latin_hints_init( AF_GlyphHints hints,
- AF_LatinMetrics metrics )
+ AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
FT_Render_Mode mode;
FT_UInt32 scaler_flags, other_flags;
FT_Face face = metrics->root.scaler.face;
@@ -3547,8 +3554,10 @@
af_latin_hints_apply( FT_UInt glyph_index,
AF_GlyphHints hints,
FT_Outline* outline,
- AF_LatinMetrics metrics )
+ AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
FT_Error error;
int dim;
diff --git a/thirdparty/freetype/src/autofit/aflatin.h b/thirdparty/freetype/src/autofit/aflatin.h
index 3c6a7ee4f6..31aa91d3bd 100644
--- a/thirdparty/freetype/src/autofit/aflatin.h
+++ b/thirdparty/freetype/src/autofit/aflatin.h
@@ -116,11 +116,11 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
- af_latin_metrics_init( AF_LatinMetrics metrics,
+ af_latin_metrics_init( AF_StyleMetrics metrics,
FT_Face face );
FT_LOCAL( void )
- af_latin_metrics_scale( AF_LatinMetrics metrics,
+ af_latin_metrics_scale( AF_StyleMetrics metrics,
AF_Scaler scaler );
FT_LOCAL( void )
diff --git a/thirdparty/freetype/src/autofit/afloader.c b/thirdparty/freetype/src/autofit/afloader.c
index c8082796fe..7c47d562af 100644
--- a/thirdparty/freetype/src/autofit/afloader.c
+++ b/thirdparty/freetype/src/autofit/afloader.c
@@ -55,10 +55,8 @@
error = af_face_globals_new( face, &loader->globals, module );
if ( !error )
{
- face->autohint.data =
- (FT_Pointer)loader->globals;
- face->autohint.finalizer =
- (FT_Generic_Finalizer)af_face_globals_free;
+ face->autohint.data = (FT_Pointer)loader->globals;
+ face->autohint.finalizer = af_face_globals_free;
}
}
diff --git a/thirdparty/freetype/src/autofit/afmodule.c b/thirdparty/freetype/src/autofit/afmodule.c
index 92e5156ab2..20a6b96bc4 100644
--- a/thirdparty/freetype/src/autofit/afmodule.c
+++ b/thirdparty/freetype/src/autofit/afmodule.c
@@ -89,10 +89,8 @@
error = af_face_globals_new( face, &globals, module );
if ( !error )
{
- face->autohint.data =
- (FT_Pointer)globals;
- face->autohint.finalizer =
- (FT_Generic_Finalizer)af_face_globals_free;
+ face->autohint.data = (FT_Pointer)globals;
+ face->autohint.finalizer = af_face_globals_free;
}
}
@@ -374,8 +372,9 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
af_service_properties,
- (FT_Properties_SetFunc)af_property_set, /* set_property */
- (FT_Properties_GetFunc)af_property_get ) /* get_property */
+ af_property_set, /* FT_Properties_SetFunc set_property */
+ af_property_get /* FT_Properties_GetFunc get_property */
+ )
FT_DEFINE_SERVICEDESCREC1(
@@ -430,12 +429,14 @@
FT_CALLBACK_DEF( FT_Error )
- af_autofitter_load_glyph( AF_Module module,
- FT_GlyphSlot slot,
- FT_Size size,
- FT_UInt glyph_index,
- FT_Int32 load_flags )
+ af_autofitter_load_glyph( FT_AutoHinter module_,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
{
+ AF_Module module = (AF_Module)module_;
+
FT_Error error = FT_Err_Ok;
FT_Memory memory = module->root.library->memory;
@@ -499,10 +500,10 @@
FT_DEFINE_AUTOHINTER_INTERFACE(
af_autofitter_interface,
- NULL, /* reset_face */
- NULL, /* get_global_hints */
- NULL, /* done_global_hints */
- (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph /* load_glyph */
+ NULL, /* FT_AutoHinter_GlobalResetFunc reset_face */
+ NULL, /* FT_AutoHinter_GlobalGetFunc get_global_hints */
+ NULL, /* FT_AutoHinter_GlobalDoneFunc done_global_hints */
+ af_autofitter_load_glyph /* FT_AutoHinter_GlyphLoadFunc load_glyph */
)
FT_DEFINE_MODULE(
@@ -517,9 +518,9 @@
(const void*)&af_autofitter_interface,
- (FT_Module_Constructor)af_autofitter_init, /* module_init */
- (FT_Module_Destructor) af_autofitter_done, /* module_done */
- (FT_Module_Requester) af_get_interface /* get_interface */
+ af_autofitter_init, /* FT_Module_Constructor module_init */
+ af_autofitter_done, /* FT_Module_Destructor module_done */
+ af_get_interface /* FT_Module_Requester get_interface */
)
diff --git a/thirdparty/freetype/src/autofit/afshaper.c b/thirdparty/freetype/src/autofit/afshaper.c
index 1b8b870e89..abc6f1d292 100644
--- a/thirdparty/freetype/src/autofit/afshaper.c
+++ b/thirdparty/freetype/src/autofit/afshaper.c
@@ -258,7 +258,7 @@
/*
* We now check whether we can construct blue zones, using glyphs
* covered by the feature only. In case there is not a single zone
- * (this is, not a single character is covered), we skip this coverage.
+ * (that is, not a single character is covered), we skip this coverage.
*
*/
if ( style_class->coverage != AF_COVERAGE_DEFAULT )
@@ -313,9 +313,9 @@
* hinted and usually rendered glyph.
*
* Consider the superscript feature of font `pala.ttf': Some of the
- * glyphs are `real', this is, they have a zero vertical offset, but
+ * glyphs are `real', that is, they have a zero vertical offset, but
* most of them are small caps glyphs shifted up to the superscript
- * position (this is, the `sups' feature is present in both the GSUB and
+ * position (that is, the `sups' feature is present in both the GSUB and
* GPOS tables). The code for blue zones computation actually uses a
* feature's y offset so that the `real' glyphs get correct hints. But
* later on it is impossible to decide whether a glyph index belongs to,
diff --git a/thirdparty/freetype/src/autofit/ft-hb.c b/thirdparty/freetype/src/autofit/ft-hb.c
index 09a8401c4a..71aee04550 100644
--- a/thirdparty/freetype/src/autofit/ft-hb.c
+++ b/thirdparty/freetype/src/autofit/ft-hb.c
@@ -108,7 +108,7 @@ hb_ft_font_create_ (FT_Face ft_face,
#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
/* ANSI C doesn't like empty source files */
-typedef int _ft_hb_dummy;
+typedef int ft_hb_dummy_;
#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
diff --git a/thirdparty/freetype/src/base/ftbbox.c b/thirdparty/freetype/src/base/ftbbox.c
index 7dd71882ea..385fea4040 100644
--- a/thirdparty/freetype/src/base/ftbbox.c
+++ b/thirdparty/freetype/src/base/ftbbox.c
@@ -82,10 +82,13 @@
* @Return:
* Always 0. Needed for the interface only.
*/
- static int
- BBox_Move_To( FT_Vector* to,
- TBBox_Rec* user )
+ FT_CALLBACK_DEF( int )
+ BBox_Move_To( const FT_Vector* to,
+ void* user_ )
{
+ TBBox_Rec* user = (TBBox_Rec*)user_;
+
+
FT_UPDATE_BBOX( to, user->bbox );
user->last = *to;
@@ -116,10 +119,13 @@
* @Return:
* Always 0. Needed for the interface only.
*/
- static int
- BBox_Line_To( FT_Vector* to,
- TBBox_Rec* user )
+ FT_CALLBACK_DEF( int )
+ BBox_Line_To( const FT_Vector* to,
+ void* user_ )
{
+ TBBox_Rec* user = (TBBox_Rec*)user_;
+
+
user->last = *to;
return 0;
@@ -205,11 +211,14 @@
* In the case of a non-monotonous arc, we compute directly the
* extremum coordinates, as it is sufficiently fast.
*/
- static int
- BBox_Conic_To( FT_Vector* control,
- FT_Vector* to,
- TBBox_Rec* user )
+ FT_CALLBACK_DEF( int )
+ BBox_Conic_To( const FT_Vector* control,
+ const FT_Vector* to,
+ void* user_ )
{
+ TBBox_Rec* user = (TBBox_Rec*)user_;
+
+
/* in case `to' is implicit and not included in bbox yet */
FT_UPDATE_BBOX( to, user->bbox );
@@ -410,12 +419,15 @@
* In the case of a non-monotonous arc, we don't compute directly
* extremum coordinates, we subdivide instead.
*/
- static int
- BBox_Cubic_To( FT_Vector* control1,
- FT_Vector* control2,
- FT_Vector* to,
- TBBox_Rec* user )
+ FT_CALLBACK_DEF( int )
+ BBox_Cubic_To( const FT_Vector* control1,
+ const FT_Vector* control2,
+ const FT_Vector* to,
+ void* user_ )
{
+ TBBox_Rec* user = (TBBox_Rec*)user_;
+
+
/* We don't need to check `to' since it is always an on-point, */
/* thus within the bbox. Only segments with an off-point outside */
/* the bbox can possibly reach new extreme values. */
diff --git a/thirdparty/freetype/src/base/ftcalc.c b/thirdparty/freetype/src/base/ftcalc.c
index 13e74f3353..442b08ddf9 100644
--- a/thirdparty/freetype/src/base/ftcalc.c
+++ b/thirdparty/freetype/src/base/ftcalc.c
@@ -1061,7 +1061,7 @@
/* */
/* This approach has the advantage that the angle between */
/* `in' and `out' is not checked. In case one of the two */
- /* vectors is `dominant', this is, much larger than the */
+ /* vectors is `dominant', that is, much larger than the */
/* other vector, we thus always have a flat corner. */
/* */
/* hypotenuse */
@@ -1103,7 +1103,7 @@
for ( i = 0; i < count; ++i )
temp += (FT_Int64)s[i] * f[i];
- return ( temp + 0x8000 ) >> 16;
+ return (FT_Int32)( ( temp + 0x8000 ) >> 16 );
#else
temp.hi = 0;
temp.lo = 0;
diff --git a/thirdparty/freetype/src/base/ftdbgmem.c b/thirdparty/freetype/src/base/ftdbgmem.c
index 6730c4c8d3..8fab50dd01 100644
--- a/thirdparty/freetype/src/base/ftdbgmem.c
+++ b/thirdparty/freetype/src/base/ftdbgmem.c
@@ -963,7 +963,7 @@
#else /* !FT_DEBUG_MEMORY */
/* ANSI C doesn't like empty source files */
- typedef int _debug_mem_dummy;
+ typedef int debug_mem_dummy_;
#endif /* !FT_DEBUG_MEMORY */
diff --git a/thirdparty/freetype/src/base/ftmac.c b/thirdparty/freetype/src/base/ftmac.c
index de34e834f2..492d055384 100644
--- a/thirdparty/freetype/src/base/ftmac.c
+++ b/thirdparty/freetype/src/base/ftmac.c
@@ -1082,7 +1082,7 @@
#else /* !FT_MACINTOSH */
/* ANSI C doesn't like empty source files */
- typedef int _ft_mac_dummy;
+ typedef int ft_mac_dummy_;
#endif /* !FT_MACINTOSH */
diff --git a/thirdparty/freetype/src/base/ftmm.c b/thirdparty/freetype/src/base/ftmm.c
index a2b4bd03d7..9e2dd7ee79 100644
--- a/thirdparty/freetype/src/base/ftmm.c
+++ b/thirdparty/freetype/src/base/ftmm.c
@@ -185,6 +185,14 @@
error = FT_ERR( Invalid_Argument );
if ( service->set_mm_design )
error = service->set_mm_design( face, num_coords, coords );
+
+ if ( !error )
+ {
+ if ( num_coords )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+ }
}
/* enforce recomputation of auto-hinting data */
@@ -220,6 +228,14 @@
error = FT_ERR( Invalid_Argument );
if ( service->set_mm_weightvector )
error = service->set_mm_weightvector( face, len, weightvector );
+
+ if ( !error )
+ {
+ if ( len )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+ }
}
/* enforce recomputation of auto-hinting data */
@@ -283,6 +299,30 @@
if ( service_mm->set_var_design )
error = service_mm->set_var_design( face, num_coords, coords );
+ if ( !error || error == -1 )
+ {
+ FT_Bool is_variation_old = FT_IS_VARIATION( face );
+
+
+ if ( num_coords )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+ if ( service_mm->construct_ps_name )
+ {
+ if ( error == -1 )
+ {
+ /* The PS name of a named instance and a non-named instance */
+ /* usually differs, even if the axis values are identical. */
+ if ( is_variation_old != FT_IS_VARIATION( face ) )
+ service_mm->construct_ps_name( face );
+ }
+ else
+ service_mm->construct_ps_name( face );
+ }
+ }
+
/* internal error code -1 means `no change'; we can exit immediately */
if ( error == -1 )
return FT_Err_Ok;
@@ -359,6 +399,30 @@
if ( service_mm->set_mm_blend )
error = service_mm->set_mm_blend( face, num_coords, coords );
+ if ( !error || error == -1 )
+ {
+ FT_Bool is_variation_old = FT_IS_VARIATION( face );
+
+
+ if ( num_coords )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+ if ( service_mm->construct_ps_name )
+ {
+ if ( error == -1 )
+ {
+ /* The PS name of a named instance and a non-named instance */
+ /* usually differs, even if the axis values are identical. */
+ if ( is_variation_old != FT_IS_VARIATION( face ) )
+ service_mm->construct_ps_name( face );
+ }
+ else
+ service_mm->construct_ps_name( face );
+ }
+ }
+
/* internal error code -1 means `no change'; we can exit immediately */
if ( error == -1 )
return FT_Err_Ok;
@@ -410,6 +474,30 @@
if ( service_mm->set_mm_blend )
error = service_mm->set_mm_blend( face, num_coords, coords );
+ if ( !error || error == -1 )
+ {
+ FT_Bool is_variation_old = FT_IS_VARIATION( face );
+
+
+ if ( num_coords )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+ if ( service_mm->construct_ps_name )
+ {
+ if ( error == -1 )
+ {
+ /* The PS name of a named instance and a non-named instance */
+ /* usually differs, even if the axis values are identical. */
+ if ( is_variation_old != FT_IS_VARIATION( face ) )
+ service_mm->construct_ps_name( face );
+ }
+ else
+ service_mm->construct_ps_name( face );
+ }
+ }
+
/* internal error code -1 means `no change'; we can exit immediately */
if ( error == -1 )
return FT_Err_Ok;
@@ -535,8 +623,35 @@
if ( !error )
{
error = FT_ERR( Invalid_Argument );
- if ( service_mm->set_instance )
- error = service_mm->set_instance( face, instance_index );
+ if ( service_mm->set_named_instance )
+ error = service_mm->set_named_instance( face, instance_index );
+
+ if ( !error || error == -1 )
+ {
+ FT_Bool is_variation_old = FT_IS_VARIATION( face );
+
+
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+ face->face_index = ( instance_index << 16 ) |
+ ( face->face_index & 0xFFFFL );
+
+ if ( service_mm->construct_ps_name )
+ {
+ if ( error == -1 )
+ {
+ /* The PS name of a named instance and a non-named instance */
+ /* usually differs, even if the axis values are identical. */
+ if ( is_variation_old != FT_IS_VARIATION( face ) )
+ service_mm->construct_ps_name( face );
+ }
+ else
+ service_mm->construct_ps_name( face );
+ }
+ }
+
+ /* internal error code -1 means `no change'; we can exit immediately */
+ if ( error == -1 )
+ return FT_Err_Ok;
}
if ( !error )
@@ -554,11 +669,32 @@
face->autohint.data = NULL;
}
+ return error;
+ }
+
+
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Default_Named_Instance( FT_Face face,
+ FT_UInt *instance_index )
+ {
+ FT_Error error;
+
+ FT_Service_MultiMasters service_mm = NULL;
+
+
+ /* check of `face' delayed to `ft_face_get_mm_service' */
+
+ error = ft_face_get_mm_service( face, &service_mm );
if ( !error )
{
- face->face_index = ( instance_index << 16 ) |
- ( face->face_index & 0xFFFFL );
- face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+ /* no error if `get_default_named_instance` is not available */
+ if ( service_mm->get_default_named_instance )
+ error = service_mm->get_default_named_instance( face,
+ instance_index );
+ else
+ error = FT_Err_Ok;
}
return error;
diff --git a/thirdparty/freetype/src/base/ftobjs.c b/thirdparty/freetype/src/base/ftobjs.c
index ad6ef0ae16..abfa3ab0e6 100644
--- a/thirdparty/freetype/src/base/ftobjs.c
+++ b/thirdparty/freetype/src/base/ftobjs.c
@@ -1019,7 +1019,8 @@
/* elegant. */
/* try to load SVG documents if available */
- if ( FT_HAS_SVG( face ) )
+ if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
+ FT_HAS_SVG( face ) )
{
error = driver->clazz->load_glyph( slot, face->size,
glyph_index,
@@ -1245,9 +1246,13 @@
/* destructor for sizes list */
static void
destroy_size( FT_Memory memory,
- FT_Size size,
- FT_Driver driver )
+ void* size_,
+ void* driver_ )
{
+ FT_Size size = (FT_Size)size_;
+ FT_Driver driver = (FT_Driver)driver_;
+
+
/* finalize client-specific data */
if ( size->generic.finalizer )
size->generic.finalizer( size );
@@ -1293,10 +1298,12 @@
/* destructor for faces list */
static void
destroy_face( FT_Memory memory,
- FT_Face face,
- FT_Driver driver )
+ void* face_,
+ void* driver_ )
{
- FT_Driver_Class clazz = driver->clazz;
+ FT_Face face = (FT_Face)face_;
+ FT_Driver driver = (FT_Driver)driver_;
+ FT_Driver_Class clazz = driver->clazz;
/* discard auto-hinting data */
@@ -1310,7 +1317,7 @@
/* discard all sizes for this face */
FT_List_Finalize( &face->sizes_list,
- (FT_List_Destructor)destroy_size,
+ destroy_size,
memory,
driver );
face->size = NULL;
@@ -1346,7 +1353,7 @@
Destroy_Driver( FT_Driver driver )
{
FT_List_Finalize( &driver->faces_list,
- (FT_List_Destructor)destroy_face,
+ destroy_face,
driver->root.memory,
driver );
}
diff --git a/thirdparty/freetype/src/base/ftoutln.c b/thirdparty/freetype/src/base/ftoutln.c
index 30ff21ff39..134f39d2b1 100644
--- a/thirdparty/freetype/src/base/ftoutln.c
+++ b/thirdparty/freetype/src/base/ftoutln.c
@@ -58,7 +58,9 @@
FT_Error error;
FT_Int n; /* index of contour in outline */
- FT_UInt first; /* index of first point in contour */
+ FT_Int first; /* index of first point in contour */
+ FT_Int last; /* index of last point in contour */
+
FT_Int tag; /* current point's state */
FT_Int shift;
@@ -73,18 +75,17 @@
shift = func_interface->shift;
delta = func_interface->delta;
- first = 0;
+ last = -1;
for ( n = 0; n < outline->n_contours; n++ )
{
- FT_Int last; /* index of last point in contour */
-
-
- FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
+ FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n ));
- last = outline->contours[n];
- if ( last < 0 )
+ first = last + 1;
+ last = outline->contours[n];
+ if ( last < first )
goto Invalid_Outline;
+
limit = outline->points + last;
v_start = outline->points[first];
@@ -282,8 +283,6 @@
Close:
if ( error )
goto Exit;
-
- first = (FT_UInt)last + 1;
}
FT_TRACE5(( "FT_Outline_Decompose: Done\n" ));
@@ -368,7 +367,7 @@
if ( n_points <= 0 || n_contours <= 0 )
goto Bad;
- end0 = end = -1;
+ end0 = -1;
for ( n = 0; n < n_contours; n++ )
{
end = outline->contours[n];
@@ -380,7 +379,7 @@
end0 = end;
}
- if ( end != n_points - 1 )
+ if ( end0 != n_points - 1 )
goto Bad;
/* XXX: check the tags array */
@@ -388,7 +387,7 @@
}
Bad:
- return FT_THROW( Invalid_Argument );
+ return FT_THROW( Invalid_Outline );
}
@@ -550,10 +549,12 @@
if ( !outline )
return;
- first = 0;
-
+ last = -1;
for ( n = 0; n < outline->n_contours; n++ )
{
+ /* keep the first contour point as is and swap points around it */
+ /* to guarantee that the cubic arches stay valid after reverse */
+ first = last + 2;
last = outline->contours[n];
/* reverse point table */
@@ -591,8 +592,6 @@
q--;
}
}
-
- first = last + 1;
}
outline->flags ^= FT_OUTLINE_REVERSE_FILL;
@@ -941,7 +940,7 @@
points = outline->points;
- first = 0;
+ last = -1;
for ( c = 0; c < outline->n_contours; c++ )
{
FT_Vector in, out, anchor, shift;
@@ -949,8 +948,9 @@
FT_Int i, j, k;
- l_in = 0;
- last = outline->contours[c];
+ first = last + 1;
+ last = outline->contours[c];
+ l_in = 0;
/* pacify compiler */
in.x = in.y = anchor.x = anchor.y = 0;
@@ -1037,8 +1037,6 @@
in = out;
l_in = l_out;
}
-
- first = last + 1;
}
return FT_Err_Ok;
@@ -1054,7 +1052,7 @@
FT_Int xshift, yshift;
FT_Vector* points;
FT_Vector v_prev, v_cur;
- FT_Int c, n, first;
+ FT_Int c, n, first, last;
FT_Pos area = 0;
@@ -1086,11 +1084,11 @@
points = outline->points;
- first = 0;
+ last = -1;
for ( c = 0; c < outline->n_contours; c++ )
{
- FT_Int last = outline->contours[c];
-
+ first = last + 1;
+ last = outline->contours[c];
v_prev.x = points[last].x >> xshift;
v_prev.y = points[last].y >> yshift;
@@ -1106,8 +1104,6 @@
v_prev = v_cur;
}
-
- first = last + 1;
}
if ( area > 0 )
diff --git a/thirdparty/freetype/src/base/ftstroke.c b/thirdparty/freetype/src/base/ftstroke.c
index db358e772e..92f1e43080 100644
--- a/thirdparty/freetype/src/base/ftstroke.c
+++ b/thirdparty/freetype/src/base/ftstroke.c
@@ -2055,7 +2055,9 @@
FT_Error error;
FT_Int n; /* index of contour in outline */
- FT_UInt first; /* index of first point in contour */
+ FT_Int first; /* index of first point in contour */
+ FT_Int last; /* index of last point in contour */
+
FT_Int tag; /* current point's state */
@@ -2067,22 +2069,17 @@
FT_Stroker_Rewind( stroker );
- first = 0;
-
+ last = -1;
for ( n = 0; n < outline->n_contours; n++ )
{
- FT_UInt last; /* index of last point in contour */
-
-
- last = (FT_UInt)outline->contours[n];
- limit = outline->points + last;
+ first = last + 1;
+ last = outline->contours[n];
/* skip empty points; we don't stroke these */
if ( last <= first )
- {
- first = last + 1;
continue;
- }
+
+ limit = outline->points + last;
v_start = outline->points[first];
v_last = outline->points[last];
@@ -2231,8 +2228,6 @@
if ( error )
goto Exit;
}
-
- first = last + 1;
}
return FT_Err_Ok;
diff --git a/thirdparty/freetype/src/base/ftsynth.c b/thirdparty/freetype/src/base/ftsynth.c
index 6ec25e13e4..f32edd3388 100644
--- a/thirdparty/freetype/src/base/ftsynth.c
+++ b/thirdparty/freetype/src/base/ftsynth.c
@@ -98,8 +98,17 @@
FT_EXPORT_DEF( void )
FT_GlyphSlot_Embolden( FT_GlyphSlot slot )
{
+ FT_GlyphSlot_AdjustWeight( slot, 0x0AAA, 0x0AAA );
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot,
+ FT_Fixed xdelta,
+ FT_Fixed ydelta )
+ {
FT_Library library;
- FT_Face face;
+ FT_Size size;
FT_Error error;
FT_Pos xstr, ystr;
@@ -108,16 +117,15 @@
return;
library = slot->library;
- face = slot->face;
+ size = slot->face->size;
if ( slot->format != FT_GLYPH_FORMAT_OUTLINE &&
slot->format != FT_GLYPH_FORMAT_BITMAP )
return;
- /* some reasonable strength */
- xstr = FT_MulFix( face->units_per_EM,
- face->size->metrics.y_scale ) / 24;
- ystr = xstr;
+ /* express deltas in pixels in 26.6 format */
+ xstr = (FT_Pos)size->metrics.x_ppem * xdelta / 1024;
+ ystr = (FT_Pos)size->metrics.y_ppem * ydelta / 1024;
if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
FT_Outline_EmboldenXY( &slot->outline, xstr, ystr );
diff --git a/thirdparty/freetype/src/base/ftsystem.c b/thirdparty/freetype/src/base/ftsystem.c
index fcd289d19f..61c99e3635 100644
--- a/thirdparty/freetype/src/base/ftsystem.c
+++ b/thirdparty/freetype/src/base/ftsystem.c
@@ -206,7 +206,7 @@
* The number of bytes to read from the stream.
*
* @Return:
- * The number of bytes actually read. If `count' is zero (this is,
+ * The number of bytes actually read. If `count' is zero (that is,
* the function is used for seeking), a non-zero return value
* indicates an error.
*/
@@ -219,7 +219,7 @@
FT_FILE* file;
- if ( !count && offset > stream->size )
+ if ( offset > stream->size && !count )
return 1;
file = STREAM_FILE( stream );
@@ -227,6 +227,11 @@
if ( stream->pos != offset )
ft_fseek( file, (long)offset, SEEK_SET );
+ /* Avoid calling `fread` with `buffer=NULL` and `count=0`, */
+ /* which is undefined behaviour. */
+ if ( !count )
+ return 0;
+
return (unsigned long)ft_fread( buffer, 1, count, file );
}
diff --git a/thirdparty/freetype/src/bdf/bdf.h b/thirdparty/freetype/src/bdf/bdf.h
index 5acbd5f2f9..e2cb52c10a 100644
--- a/thirdparty/freetype/src/bdf/bdf.h
+++ b/thirdparty/freetype/src/bdf/bdf.h
@@ -240,10 +240,6 @@ FT_BEGIN_HEADER
bdf_free_font( bdf_font_t* font );
FT_LOCAL( bdf_property_t * )
- bdf_get_property( char* name,
- bdf_font_t* font );
-
- FT_LOCAL( bdf_property_t * )
bdf_get_font_property( bdf_font_t* font,
const char* name );
diff --git a/thirdparty/freetype/src/bdf/bdfdrivr.c b/thirdparty/freetype/src/bdf/bdfdrivr.c
index d7e8e0efc5..e02a160930 100644
--- a/thirdparty/freetype/src/bdf/bdfdrivr.c
+++ b/thirdparty/freetype/src/bdf/bdfdrivr.c
@@ -311,9 +311,9 @@ THE SOFTWARE.
FT_CALLBACK_DEF( void )
- BDF_Face_Done( FT_Face bdfface ) /* BDF_Face */
+ BDF_Face_Done( FT_Face face ) /* BDF_Face */
{
- BDF_Face face = (BDF_Face)bdfface;
+ BDF_Face bdfface = (BDF_Face)face;
FT_Memory memory;
@@ -322,31 +322,31 @@ THE SOFTWARE.
memory = FT_FACE_MEMORY( face );
- bdf_free_font( face->bdffont );
+ bdf_free_font( bdfface->bdffont );
- FT_FREE( face->en_table );
+ FT_FREE( bdfface->en_table );
- FT_FREE( face->charset_encoding );
- FT_FREE( face->charset_registry );
- FT_FREE( bdfface->family_name );
- FT_FREE( bdfface->style_name );
+ FT_FREE( bdfface->charset_encoding );
+ FT_FREE( bdfface->charset_registry );
+ FT_FREE( face->family_name );
+ FT_FREE( face->style_name );
- FT_FREE( bdfface->available_sizes );
+ FT_FREE( face->available_sizes );
- FT_FREE( face->bdffont );
+ FT_FREE( bdfface->bdffont );
}
FT_CALLBACK_DEF( FT_Error )
BDF_Face_Init( FT_Stream stream,
- FT_Face bdfface, /* BDF_Face */
+ FT_Face face, /* BDF_Face */
FT_Int face_index,
FT_Int num_params,
FT_Parameter* params )
{
- FT_Error error = FT_Err_Ok;
- BDF_Face face = (BDF_Face)bdfface;
- FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_Error error = FT_Err_Ok;
+ BDF_Face bdfface = (BDF_Face)face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
bdf_font_t* font = NULL;
bdf_options_t options;
@@ -375,7 +375,7 @@ THE SOFTWARE.
goto Exit;
/* we have a bdf font: let's construct the face object */
- face->bdffont = font;
+ bdfface->bdffont = font;
/* BDF cannot have multiple faces in a single font file.
* XXX: non-zero face_index is already invalid argument, but
@@ -386,7 +386,7 @@ THE SOFTWARE.
if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
{
FT_ERROR(( "BDF_Face_Init: invalid face index\n" ));
- BDF_Face_Done( bdfface );
+ BDF_Face_Done( face );
return FT_THROW( Invalid_Argument );
}
@@ -401,18 +401,18 @@ THE SOFTWARE.
font->unencoded_size,
font->unencoded_used ));
- bdfface->num_faces = 1;
- bdfface->face_index = 0;
+ face->num_faces = 1;
+ face->face_index = 0;
- bdfface->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
- FT_FACE_FLAG_HORIZONTAL;
+ face->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
+ FT_FACE_FLAG_HORIZONTAL;
prop = bdf_get_font_property( font, "SPACING" );
if ( prop && prop->format == BDF_ATOM &&
prop->value.atom &&
( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' ||
*(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) )
- bdfface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+ face->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
/* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */
/* FZ XXX: I need a font to implement this */
@@ -420,26 +420,27 @@ THE SOFTWARE.
prop = bdf_get_font_property( font, "FAMILY_NAME" );
if ( prop && prop->value.atom )
{
- if ( FT_STRDUP( bdfface->family_name, prop->value.atom ) )
+ if ( FT_STRDUP( face->family_name, prop->value.atom ) )
goto Exit;
}
else
- bdfface->family_name = NULL;
+ face->family_name = NULL;
- if ( FT_SET_ERROR( bdf_interpret_style( face ) ) )
+ if ( FT_SET_ERROR( bdf_interpret_style( bdfface ) ) )
goto Exit;
/* the number of glyphs (with one slot for the undefined glyph */
/* at position 0 and all unencoded glyphs) */
- bdfface->num_glyphs = (FT_Long)( font->glyphs_size + 1 );
+ face->num_glyphs = (FT_Long)( font->glyphs_size + 1 );
- bdfface->num_fixed_sizes = 1;
- if ( FT_NEW( bdfface->available_sizes ) )
+ face->num_fixed_sizes = 1;
+ if ( FT_NEW( face->available_sizes ) )
goto Exit;
{
- FT_Bitmap_Size* bsize = bdfface->available_sizes;
- FT_Short resolution_x = 0, resolution_y = 0;
+ FT_Bitmap_Size* bsize = face->available_sizes;
+ FT_Short resolution_x = 0;
+ FT_Short resolution_y = 0;
long value;
@@ -598,20 +599,20 @@ THE SOFTWARE.
unsigned long n;
- if ( FT_QNEW_ARRAY( face->en_table, font->glyphs_size ) )
+ if ( FT_QNEW_ARRAY( bdfface->en_table, font->glyphs_size ) )
goto Exit;
- face->default_glyph = 0;
+ bdfface->default_glyph = 0;
for ( n = 0; n < font->glyphs_size; n++ )
{
- (face->en_table[n]).enc = cur[n].encoding;
+ (bdfface->en_table[n]).enc = cur[n].encoding;
FT_TRACE4(( " idx %ld, val 0x%lX\n", n, cur[n].encoding ));
- (face->en_table[n]).glyph = (FT_UShort)n;
+ (bdfface->en_table[n]).glyph = (FT_UShort)n;
if ( cur[n].encoding == font->default_char )
{
if ( n < FT_UINT_MAX )
- face->default_glyph = (FT_UInt)n;
+ bdfface->default_glyph = (FT_UInt)n;
else
FT_TRACE1(( "BDF_Face_Init:"
" idx %ld is too large for this system\n", n ));
@@ -639,27 +640,27 @@ THE SOFTWARE.
const char* s;
- if ( FT_STRDUP( face->charset_encoding,
+ if ( FT_STRDUP( bdfface->charset_encoding,
charset_encoding->value.atom ) ||
- FT_STRDUP( face->charset_registry,
+ FT_STRDUP( bdfface->charset_registry,
charset_registry->value.atom ) )
goto Exit;
/* Uh, oh, compare first letters manually to avoid dependency */
/* on locales. */
- s = face->charset_registry;
+ s = bdfface->charset_registry;
if ( ( s[0] == 'i' || s[0] == 'I' ) &&
( s[1] == 's' || s[1] == 'S' ) &&
( s[2] == 'o' || s[2] == 'O' ) )
{
s += 3;
- if ( !ft_strcmp( s, "10646" ) ||
- ( !ft_strcmp( s, "8859" ) &&
- !ft_strcmp( face->charset_encoding, "1" ) ) )
+ if ( !ft_strcmp( s, "10646" ) ||
+ ( !ft_strcmp( s, "8859" ) &&
+ !ft_strcmp( bdfface->charset_encoding, "1" ) ) )
unicode_charmap = 1;
/* another name for ASCII */
- else if ( !ft_strcmp( s, "646.1991" ) &&
- !ft_strcmp( face->charset_encoding, "IRV" ) )
+ else if ( !ft_strcmp( s, "646.1991" ) &&
+ !ft_strcmp( bdfface->charset_encoding, "IRV" ) )
unicode_charmap = 1;
}
@@ -667,7 +668,7 @@ THE SOFTWARE.
FT_CharMapRec charmap;
- charmap.face = FT_FACE( face );
+ charmap.face = face;
charmap.encoding = FT_ENCODING_NONE;
/* initial platform/encoding should indicate unset status? */
charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
@@ -693,7 +694,7 @@ THE SOFTWARE.
FT_CharMapRec charmap;
- charmap.face = FT_FACE( face );
+ charmap.face = face;
charmap.encoding = FT_ENCODING_ADOBE_STANDARD;
charmap.platform_id = TT_PLATFORM_ADOBE;
charmap.encoding_id = TT_ADOBE_ID_STANDARD;
@@ -701,8 +702,8 @@ THE SOFTWARE.
error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
/* Select default charmap */
- if ( bdfface->num_charmaps )
- bdfface->charmap = bdfface->charmaps[0];
+ if ( face->num_charmaps )
+ face->charmap = face->charmaps[0];
}
}
}
@@ -711,7 +712,7 @@ THE SOFTWARE.
return error;
Fail:
- BDF_Face_Done( bdfface );
+ BDF_Face_Done( face );
return FT_THROW( Unknown_File_Format );
}
@@ -868,17 +869,18 @@ THE SOFTWARE.
*
*/
- static FT_Error
- bdf_get_bdf_property( BDF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ bdf_get_bdf_property( FT_Face face, /* BDF_Face */
const char* prop_name,
BDF_PropertyRec *aproperty )
{
+ BDF_Face bdfface = (BDF_Face)face;
bdf_property_t* prop;
- FT_ASSERT( face && face->bdffont );
+ FT_ASSERT( bdfface && bdfface->bdffont );
- prop = bdf_get_font_property( face->bdffont, prop_name );
+ prop = bdf_get_font_property( bdfface->bdffont, prop_name );
if ( prop )
{
switch ( prop->format )
@@ -921,13 +923,16 @@ THE SOFTWARE.
}
- static FT_Error
- bdf_get_charset_id( BDF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ bdf_get_charset_id( FT_Face face, /* BDF_Face */
const char* *acharset_encoding,
const char* *acharset_registry )
{
- *acharset_encoding = face->charset_encoding;
- *acharset_registry = face->charset_registry;
+ BDF_Face bdfface = (BDF_Face)face;
+
+
+ *acharset_encoding = bdfface->charset_encoding;
+ *acharset_registry = bdfface->charset_registry;
return 0;
}
@@ -964,7 +969,6 @@ THE SOFTWARE.
}
-
FT_CALLBACK_TABLE_DEF
const FT_Driver_ClassRec bdf_driver_class =
{
diff --git a/thirdparty/freetype/src/bdf/bdflib.c b/thirdparty/freetype/src/bdf/bdflib.c
index 2224698fc0..0fa7e0a8c5 100644
--- a/thirdparty/freetype/src/bdf/bdflib.c
+++ b/thirdparty/freetype/src/bdf/bdflib.c
@@ -51,6 +51,9 @@
#define FT_COMPONENT bdflib
+#define BUFSIZE 128
+
+
/**************************************************************************
*
* Default BDF font options.
@@ -378,7 +381,7 @@
*alen = 0;
if ( list == NULL || list->used == 0 )
- return 0;
+ return NULL;
dp = list->field[0];
for ( i = j = 0; i < list->used; i++ )
@@ -887,18 +890,18 @@
}
- FT_LOCAL_DEF( bdf_property_t* )
- bdf_get_property( char* name,
+ static bdf_property_t*
+ bdf_get_property( const char* name,
bdf_font_t* font )
{
size_t* propid;
if ( name == NULL || *name == 0 )
- return 0;
+ return NULL;
if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
- return 0;
+ return NULL;
if ( *propid >= num_bdf_properties_ )
return font->user_props + ( *propid - num_bdf_properties_ );
@@ -944,7 +947,7 @@
static FT_Error
bdf_add_comment_( bdf_font_t* font,
- char* comment,
+ const char* comment,
unsigned long len )
{
char* cp;
@@ -1053,27 +1056,24 @@
bdf_property_t* p;
- *name = sp = ep = line;
+ sp = ep = line;
while ( *ep && *ep != ' ' && *ep != '\t' )
ep++;
- hold = -1;
- if ( *ep )
- {
- hold = *ep;
- *ep = 0;
- }
+ hold = *ep;
+ *ep = '\0';
p = bdf_get_property( sp, font );
- /* Restore the character that was saved before any return can happen. */
- if ( hold != -1 )
- *ep = (char)hold;
-
/* If the property exists and is not an atom, just return here. */
if ( p && p->format != BDF_ATOM )
+ {
+ *ep = (char)hold; /* Undo NUL-termination. */
return 0;
+ }
+
+ *name = sp;
/* The property is an atom. Trim all leading and trailing whitespace */
/* and double quotes for the atom value. */
@@ -1081,25 +1081,26 @@
ep = line + linelen;
/* Trim the leading whitespace if it exists. */
- if ( *sp )
- *sp++ = 0;
- while ( *sp &&
- ( *sp == ' ' || *sp == '\t' ) )
- sp++;
+ if ( sp < ep )
+ do
+ sp++;
+ while ( *sp == ' ' || *sp == '\t' );
/* Trim the leading double quote if it exists. */
if ( *sp == '"' )
sp++;
+
*value = sp;
/* Trim the trailing whitespace if it exists. */
- while ( ep > sp &&
- ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
- *--ep = 0;
+ if ( sp < ep )
+ do
+ *ep-- = '\0';
+ while ( *ep == ' ' || *ep == '\t' );
/* Trim the trailing double quote if it exists. */
- if ( ep > sp && *( ep - 1 ) == '"' )
- *--ep = 0;
+ if ( *ep == '"' )
+ *ep = '\0';
return 1;
}
@@ -1775,7 +1776,7 @@
bdf_parse_t_* p;
char* name;
char* value;
- char nbuf[128];
+ char nbuf[BUFSIZE];
FT_Error error = FT_Err_Ok;
FT_UNUSED( lineno );
@@ -1796,7 +1797,7 @@
if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
{
p->font->font_ascent = p->font->bbx.ascent;
- ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
+ ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
error = bdf_add_property_( p->font, "FONT_ASCENT",
nbuf, lineno );
if ( error )
@@ -1808,7 +1809,7 @@
if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
{
p->font->font_descent = p->font->bbx.descent;
- ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
+ ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
error = bdf_add_property_( p->font, "FONT_DESCENT",
nbuf, lineno );
if ( error )
@@ -2116,7 +2117,7 @@
/* Check for the CHARS field -- font properties are optional */
if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
{
- char nbuf[128];
+ char nbuf[BUFSIZE];
if ( !( p->flags & BDF_FONT_BBX_ ) )
@@ -2130,7 +2131,7 @@
/* Add the two standard X11 properties which are required */
/* for compiling fonts. */
p->font->font_ascent = p->font->bbx.ascent;
- ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
+ ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
error = bdf_add_property_( p->font, "FONT_ASCENT",
nbuf, lineno );
if ( error )
@@ -2138,7 +2139,7 @@
FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
p->font->font_descent = p->font->bbx.descent;
- ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
+ ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
error = bdf_add_property_( p->font, "FONT_DESCENT",
nbuf, lineno );
if ( error )
diff --git a/thirdparty/freetype/src/bzip2/ftbzip2.c b/thirdparty/freetype/src/bzip2/ftbzip2.c
index 6cf10678b7..ad342bd011 100644
--- a/thirdparty/freetype/src/bzip2/ftbzip2.c
+++ b/thirdparty/freetype/src/bzip2/ftbzip2.c
@@ -62,10 +62,12 @@
static void*
- ft_bzip2_alloc( FT_Memory memory,
- int items,
- int size )
+ ft_bzip2_alloc( void* memory_, /* FT_Memory */
+ int items,
+ int size )
{
+ FT_Memory memory = (FT_Memory)memory_;
+
FT_ULong sz = (FT_ULong)size * (FT_ULong)items;
FT_Error error;
FT_Pointer p = NULL;
@@ -77,9 +79,12 @@
static void
- ft_bzip2_free( FT_Memory memory,
- void* address )
+ ft_bzip2_free( void* memory_, /* FT_Memory */
+ void* address )
{
+ FT_Memory memory = (FT_Memory)memory_;
+
+
FT_MEM_FREE( address );
}
@@ -170,8 +175,8 @@
}
/* initialize bzlib */
- bzstream->bzalloc = (alloc_func)ft_bzip2_alloc;
- bzstream->bzfree = (free_func) ft_bzip2_free;
+ bzstream->bzalloc = ft_bzip2_alloc;
+ bzstream->bzfree = ft_bzip2_free;
bzstream->opaque = zip->memory;
bzstream->avail_in = 0;
diff --git a/thirdparty/freetype/src/cache/ftcbasic.c b/thirdparty/freetype/src/cache/ftcbasic.c
index 4c6d41b2cd..24a56c8d26 100644
--- a/thirdparty/freetype/src/cache/ftcbasic.c
+++ b/thirdparty/freetype/src/cache/ftcbasic.c
@@ -337,7 +337,7 @@
#if 1 /* inlining is about 50% faster! */
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
- FTC_GNode_Compare,
+ ftc_gnode_compare,
hash, gindex,
&query,
node,
@@ -411,7 +411,7 @@
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
- FTC_GNode_Compare,
+ ftc_gnode_compare,
hash, gindex,
&query,
node,
@@ -537,7 +537,7 @@
#if 1 /* inlining is about 50% faster! */
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
- FTC_SNode_Compare,
+ ftc_snode_compare,
hash, gindex,
&query,
node,
@@ -613,7 +613,7 @@
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
- FTC_SNode_Compare,
+ ftc_snode_compare,
hash, gindex,
&query,
node,
diff --git a/thirdparty/freetype/src/cache/ftccache.c b/thirdparty/freetype/src/cache/ftccache.c
index d54e68ca9a..e0698557b7 100644
--- a/thirdparty/freetype/src/cache/ftccache.c
+++ b/thirdparty/freetype/src/cache/ftccache.c
@@ -94,8 +94,8 @@
idx = hash & cache->mask;
- if ( idx < cache->p )
- idx = hash & ( 2 * cache->mask + 1 );
+ if ( idx >= cache->p )
+ idx = hash & ( cache->mask >> 1 );
return cache->buckets + idx;
}
@@ -113,9 +113,9 @@
for (;;)
{
FTC_Node node, *pnode;
- FT_UFast p = cache->p;
- FT_UFast mask = cache->mask;
- FT_UFast count = mask + p + 1; /* number of buckets */
+ FT_UFast p = cache->p;
+ FT_UFast size = cache->mask + 1; /* available size */
+ FT_UFast half = size >> 1;
/* do we need to expand the buckets array? */
@@ -127,20 +127,22 @@
/* try to expand the buckets array _before_ splitting
* the bucket lists
*/
- if ( p >= mask )
+ if ( p == size )
{
FT_Memory memory = cache->memory;
FT_Error error;
/* if we can't expand the array, leave immediately */
- if ( FT_RENEW_ARRAY( cache->buckets,
- ( mask + 1 ) * 2, ( mask + 1 ) * 4 ) )
+ if ( FT_QRENEW_ARRAY( cache->buckets, size, size * 2 ) )
break;
+
+ cache->mask = 2 * size - 1;
+ half = size;
}
- /* split a single bucket */
- pnode = cache->buckets + p;
+ /* the bucket to split */
+ pnode = cache->buckets + p - half;
for (;;)
{
@@ -148,7 +150,7 @@
if ( !node )
break;
- if ( node->hash & ( mask + 1 ) )
+ if ( node->hash & half )
{
*pnode = node->link;
node->link = new_list;
@@ -158,56 +160,50 @@
pnode = &node->link;
}
- cache->buckets[p + mask + 1] = new_list;
+ cache->buckets[p] = new_list;
cache->slack += FTC_HASH_MAX_LOAD;
+ cache->p = p + 1;
- if ( p >= mask )
- {
- cache->mask = 2 * mask + 1;
- cache->p = 0;
- }
- else
- cache->p = p + 1;
+ FT_TRACE2(( "ftc_cache_resize: cache %u increased to %u hashes\n",
+ cache->index, cache->p ));
}
/* do we need to shrink the buckets array? */
- else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD )
+ else if ( cache->slack > (FT_Long)p * FTC_HASH_SUB_LOAD )
{
- FT_UFast old_index = p + mask;
- FTC_Node* pold;
+ FTC_Node old_list = cache->buckets[--p];
- if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE )
+ if ( p < FTC_HASH_INITIAL_SIZE )
break;
- if ( p == 0 )
+ if ( p == half )
{
FT_Memory memory = cache->memory;
FT_Error error;
/* if we can't shrink the array, leave immediately */
- if ( FT_QRENEW_ARRAY( cache->buckets,
- ( mask + 1 ) * 2, mask + 1 ) )
+ if ( FT_QRENEW_ARRAY( cache->buckets, size, half ) )
break;
- cache->mask >>= 1;
- p = cache->mask;
+ cache->mask = half - 1;
}
- else
- p--;
- pnode = cache->buckets + p;
+ /* the bucket to merge */
+ pnode = cache->buckets + p - half;
+
while ( *pnode )
pnode = &(*pnode)->link;
- pold = cache->buckets + old_index;
- *pnode = *pold;
- *pold = NULL;
+ *pnode = old_list;
cache->slack -= FTC_HASH_MAX_LOAD;
cache->p = p;
+
+ FT_TRACE2(( "ftc_cache_resize: cache %u decreased to %u hashes\n",
+ cache->index, cache->p ));
}
/* otherwise, the hash table is balanced */
@@ -239,7 +235,7 @@
if ( node == node0 )
break;
- pnode = &(*pnode)->link;
+ pnode = &node->link;
}
*pnode = node0->link;
@@ -323,40 +319,41 @@
FT_LOCAL_DEF( FT_Error )
- FTC_Cache_Init( FTC_Cache cache )
- {
- return ftc_cache_init( cache );
- }
-
-
- FT_LOCAL_DEF( FT_Error )
ftc_cache_init( FTC_Cache cache )
{
FT_Memory memory = cache->memory;
FT_Error error;
- cache->p = 0;
+ cache->p = FTC_HASH_INITIAL_SIZE;
cache->mask = FTC_HASH_INITIAL_SIZE - 1;
cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
- FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 );
+ FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE );
return error;
}
- static void
- FTC_Cache_Clear( FTC_Cache cache )
+ FT_LOCAL_DEF( FT_Error )
+ FTC_Cache_Init( FTC_Cache cache )
{
- if ( cache && cache->buckets )
+ return ftc_cache_init( cache );
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ftc_cache_done( FTC_Cache cache )
+ {
+ FT_Memory memory = cache->memory;
+
+
+ if ( cache->buckets )
{
FTC_Manager manager = cache->manager;
+ FT_UFast count = cache->p;
FT_UFast i;
- FT_UFast count;
- count = cache->p + cache->mask + 1;
-
for ( i = 0; i < count; i++ )
{
FTC_Node node = cache->buckets[i], next;
@@ -376,30 +373,14 @@
cache->clazz.node_free( node, cache );
node = next;
}
- cache->buckets[i] = NULL;
}
- ftc_cache_resize( cache );
}
- }
+ FT_FREE( cache->buckets );
- FT_LOCAL_DEF( void )
- ftc_cache_done( FTC_Cache cache )
- {
- if ( cache->memory )
- {
- FT_Memory memory = cache->memory;
-
-
- FTC_Cache_Clear( cache );
-
- FT_FREE( cache->buckets );
- cache->mask = 0;
- cache->p = 0;
- cache->slack = 0;
-
- cache->memory = NULL;
- }
+ cache->p = 0;
+ cache->mask = 0;
+ cache->slack = 0;
}
@@ -562,12 +543,12 @@
FTC_Cache_RemoveFaceID( FTC_Cache cache,
FTC_FaceID face_id )
{
- FT_UFast i, count;
FTC_Manager manager = cache->manager;
FTC_Node frees = NULL;
+ FT_UFast count = cache->p;
+ FT_UFast i;
- count = cache->p + cache->mask + 1;
for ( i = 0; i < count; i++ )
{
FTC_Node* pnode = cache->buckets + i;
diff --git a/thirdparty/freetype/src/cache/ftccache.h b/thirdparty/freetype/src/cache/ftccache.h
index 23bcb65858..850d2554b5 100644
--- a/thirdparty/freetype/src/cache/ftccache.h
+++ b/thirdparty/freetype/src/cache/ftccache.h
@@ -72,11 +72,12 @@ FT_BEGIN_HEADER
#define FTC_NODE_NEXT( x ) FTC_NODE( (x)->mru.next )
#define FTC_NODE_PREV( x ) FTC_NODE( (x)->mru.prev )
+ /* address the hash table entries */
#ifdef FTC_INLINE
-#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \
- ( ( cache )->buckets + \
- ( ( ( ( hash ) & ( cache )->mask ) < ( cache )->p ) \
- ? ( ( hash ) & ( ( cache )->mask * 2 + 1 ) ) \
+#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \
+ ( ( cache )->buckets + \
+ ( ( ( ( hash ) & ( cache )->mask ) >= ( cache )->p ) \
+ ? ( ( hash ) & ( ( cache )->mask >> 1 ) ) \
: ( ( hash ) & ( cache )->mask ) ) )
#else
FT_LOCAL( FTC_Node* )
@@ -139,11 +140,13 @@ FT_BEGIN_HEADER
} FTC_CacheClassRec;
- /* each cache really implements a dynamic hash table to manage its nodes */
+ /* each cache really implements a hash table to manage its nodes */
+ /* the number of the table entries (buckets) can change dynamically */
+ /* each bucket contains a linked lists of nodes for a given hash */
typedef struct FTC_CacheRec_
{
- FT_UFast p;
- FT_UFast mask;
+ FT_UFast p; /* hash table counter */
+ FT_UFast mask; /* hash table index range */
FT_Long slack;
FTC_Node* buckets;
diff --git a/thirdparty/freetype/src/cache/ftcglyph.c b/thirdparty/freetype/src/cache/ftcglyph.c
index b3fb2f219c..d344733f37 100644
--- a/thirdparty/freetype/src/cache/ftcglyph.c
+++ b/thirdparty/freetype/src/cache/ftcglyph.c
@@ -79,20 +79,6 @@
}
-#ifdef FTC_INLINE
-
- FT_LOCAL_DEF( FT_Bool )
- FTC_GNode_Compare( FTC_GNode gnode,
- FTC_GQuery gquery,
- FTC_Cache cache,
- FT_Bool* list_changed )
- {
- return ftc_gnode_compare( FTC_NODE( gnode ), gquery,
- cache, list_changed );
- }
-
-#endif
-
/*************************************************************************/
/*************************************************************************/
/***** *****/
@@ -115,22 +101,22 @@
FT_LOCAL_DEF( FT_Error )
- ftc_gcache_init( FTC_Cache ftccache )
+ ftc_gcache_init( FTC_Cache cache )
{
- FTC_GCache cache = (FTC_GCache)ftccache;
+ FTC_GCache gcache = (FTC_GCache)cache;
FT_Error error;
- error = FTC_Cache_Init( FTC_CACHE( cache ) );
+ error = FTC_Cache_Init( cache );
if ( !error )
{
- FTC_GCacheClass clazz = (FTC_GCacheClass)FTC_CACHE( cache )->org_class;
+ FTC_GCacheClass clazz = (FTC_GCacheClass)cache->org_class;
- FTC_MruList_Init( &cache->families,
+ FTC_MruList_Init( &gcache->families,
clazz->family_class,
0, /* no maximum here! */
cache,
- FTC_CACHE( cache )->memory );
+ cache->memory );
}
return error;
@@ -140,31 +126,31 @@
#if 0
FT_LOCAL_DEF( FT_Error )
- FTC_GCache_Init( FTC_GCache cache )
+ FTC_GCache_Init( FTC_GCache gcache )
{
- return ftc_gcache_init( FTC_CACHE( cache ) );
+ return ftc_gcache_init( FTC_CACHE( gcache ) );
}
#endif /* 0 */
FT_LOCAL_DEF( void )
- ftc_gcache_done( FTC_Cache ftccache )
+ ftc_gcache_done( FTC_Cache cache )
{
- FTC_GCache cache = (FTC_GCache)ftccache;
+ FTC_GCache gcache = (FTC_GCache)cache;
- FTC_Cache_Done( (FTC_Cache)cache );
- FTC_MruList_Done( &cache->families );
+ FTC_Cache_Done( cache );
+ FTC_MruList_Done( &gcache->families );
}
#if 0
FT_LOCAL_DEF( void )
- FTC_GCache_Done( FTC_GCache cache )
+ FTC_GCache_Done( FTC_GCache gcache )
{
- ftc_gcache_done( FTC_CACHE( cache ) );
+ ftc_gcache_done( FTC_CACHE( gcache ) );
}
#endif /* 0 */
@@ -183,7 +169,7 @@
#ifndef FTC_INLINE
FT_LOCAL_DEF( FT_Error )
- FTC_GCache_Lookup( FTC_GCache cache,
+ FTC_GCache_Lookup( FTC_GCache gcache,
FT_Offset hash,
FT_UInt gindex,
FTC_GQuery query,
@@ -204,7 +190,7 @@
/* out-of-memory condition occurs during glyph node initialization. */
family->num_nodes++;
- error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query, anode );
+ error = FTC_Cache_Lookup( FTC_CACHE( gcache ), hash, query, anode );
if ( --family->num_nodes == 0 )
FTC_FAMILY_FREE( family, cache );
diff --git a/thirdparty/freetype/src/cache/ftcglyph.h b/thirdparty/freetype/src/cache/ftcglyph.h
index 728d4db1d6..0181e98166 100644
--- a/thirdparty/freetype/src/cache/ftcglyph.h
+++ b/thirdparty/freetype/src/cache/ftcglyph.h
@@ -58,7 +58,7 @@
* - FTC_GNode sub-class, e.g. MyNode, with relevant methods:
* my_node_new (must call FTC_GNode_Init)
* my_node_free (must call FTC_GNode_Done)
- * my_node_compare (must call FTC_GNode_Compare)
+ * my_node_compare (must call ftc_gnode_compare)
* my_node_remove_faceid (must call ftc_gnode_unselect in case
* of match)
*
@@ -179,19 +179,6 @@ FT_BEGIN_HEADER
FT_UInt gindex, /* glyph index for node */
FTC_Family family );
-#ifdef FTC_INLINE
-
- /* returns TRUE iff the query's glyph index correspond to the node; */
- /* this assumes that the `family' and `hash' fields of the query are */
- /* already correctly set */
- FT_LOCAL( FT_Bool )
- FTC_GNode_Compare( FTC_GNode gnode,
- FTC_GQuery gquery,
- FTC_Cache cache,
- FT_Bool* list_changed );
-
-#endif
-
/* call this function to clear a node's family -- this is necessary */
/* to implement the `node_remove_faceid' cache method correctly */
FT_LOCAL( void )
diff --git a/thirdparty/freetype/src/cache/ftcmanag.c b/thirdparty/freetype/src/cache/ftcmanag.c
index 6c84339100..94f8469c92 100644
--- a/thirdparty/freetype/src/cache/ftcmanag.c
+++ b/thirdparty/freetype/src/cache/ftcmanag.c
@@ -426,7 +426,7 @@
memory = manager->memory;
/* now discard all caches */
- for (idx = manager->num_caches; idx-- > 0; )
+ for ( idx = manager->num_caches; idx-- > 0; )
{
FTC_Cache cache = manager->caches[idx];
@@ -537,7 +537,7 @@
FT_LOCAL_DEF( void )
FTC_Manager_Compress( FTC_Manager manager )
{
- FTC_Node node, first;
+ FTC_Node node, prev, first;
if ( !manager )
@@ -557,20 +557,16 @@
return;
/* go to last node -- it's a circular list */
- node = FTC_NODE_PREV( first );
+ prev = FTC_NODE_PREV( first );
do
{
- FTC_Node prev;
-
-
- prev = ( node == first ) ? NULL : FTC_NODE_PREV( node );
+ node = prev;
+ prev = FTC_NODE_PREV( node );
if ( node->ref_count <= 0 )
ftc_node_destroy( node, manager );
- node = prev;
-
- } while ( node && manager->cur_weight > manager->max_weight );
+ } while ( node != first && manager->cur_weight > manager->max_weight );
}
@@ -633,20 +629,20 @@
FT_UInt count )
{
FTC_Node first = manager->nodes_list;
- FTC_Node node;
- FT_UInt result;
+ FTC_Node prev, node;
+ FT_UInt result = 0;
/* try to remove `count' nodes from the list */
- if ( !first ) /* empty list! */
- return 0;
+ if ( !first || !count )
+ return result;
- /* go to last node - it's a circular list */
- node = FTC_NODE_PREV(first);
- for ( result = 0; result < count; )
+ /* go to last node -- it's a circular list */
+ prev = FTC_NODE_PREV( first );
+ do
{
- FTC_Node prev = FTC_NODE_PREV( node );
-
+ node = prev;
+ prev = FTC_NODE_PREV( node );
/* don't touch locked nodes */
if ( node->ref_count <= 0 )
@@ -654,13 +650,9 @@
ftc_node_destroy( node, manager );
result++;
}
+ } while ( node != first && result < count );
- if ( node == first )
- break;
-
- node = prev;
- }
- return result;
+ return result;
}
diff --git a/thirdparty/freetype/src/cache/ftcmru.c b/thirdparty/freetype/src/cache/ftcmru.c
index 67227033e7..ad10a06bc4 100644
--- a/thirdparty/freetype/src/cache/ftcmru.c
+++ b/thirdparty/freetype/src/cache/ftcmru.c
@@ -329,29 +329,23 @@
FTC_MruNode_CompareFunc selection,
FT_Pointer key )
{
- FTC_MruNode first, node, next;
+ FTC_MruNode first = list->nodes;
+ FTC_MruNode prev, node;
- first = list->nodes;
- while ( first && ( !selection || selection( first, key ) ) )
- {
- FTC_MruList_Remove( list, first );
- first = list->nodes;
- }
+ if ( !first || !selection )
+ return;
- if ( first )
+ prev = first->prev;
+ do
{
- node = first->next;
- while ( node != first )
- {
- next = node->next;
+ node = prev;
+ prev = node->prev;
- if ( selection( node, key ) )
- FTC_MruList_Remove( list, node );
+ if ( selection( node, key ) )
+ FTC_MruList_Remove( list, node );
- node = next;
- }
- }
+ } while ( node != first );
}
diff --git a/thirdparty/freetype/src/cache/ftcsbits.c b/thirdparty/freetype/src/cache/ftcsbits.c
index ee9dab2632..9929a0bcc3 100644
--- a/thirdparty/freetype/src/cache/ftcsbits.c
+++ b/thirdparty/freetype/src/cache/ftcsbits.c
@@ -342,7 +342,7 @@
FT_Bool result;
- if (list_changed)
+ if ( list_changed )
*list_changed = FALSE;
result = FT_BOOL( gnode->family == gquery->family &&
gindex - gnode->gindex < snode->count );
@@ -411,19 +411,4 @@
return result;
}
-
-#ifdef FTC_INLINE
-
- FT_LOCAL_DEF( FT_Bool )
- FTC_SNode_Compare( FTC_SNode snode,
- FTC_GQuery gquery,
- FTC_Cache cache,
- FT_Bool* list_changed )
- {
- return ftc_snode_compare( FTC_NODE( snode ), gquery,
- cache, list_changed );
- }
-
-#endif
-
/* END */
diff --git a/thirdparty/freetype/src/cache/ftcsbits.h b/thirdparty/freetype/src/cache/ftcsbits.h
index 3473923f03..e833cb5c30 100644
--- a/thirdparty/freetype/src/cache/ftcsbits.h
+++ b/thirdparty/freetype/src/cache/ftcsbits.h
@@ -81,17 +81,6 @@ FT_BEGIN_HEADER
FTC_SNode_Weight( FTC_SNode inode );
#endif
-
-#ifdef FTC_INLINE
-
- FT_LOCAL( FT_Bool )
- FTC_SNode_Compare( FTC_SNode snode,
- FTC_GQuery gquery,
- FTC_Cache cache,
- FT_Bool* list_changed);
-
-#endif
-
/* */
FT_END_HEADER
diff --git a/thirdparty/freetype/src/cff/cffcmap.c b/thirdparty/freetype/src/cff/cffcmap.c
index 6ed3143222..10d287bc81 100644
--- a/thirdparty/freetype/src/cff/cffcmap.c
+++ b/thirdparty/freetype/src/cff/cffcmap.c
@@ -32,9 +32,10 @@
/*************************************************************************/
FT_CALLBACK_DEF( FT_Error )
- cff_cmap_encoding_init( CFF_CMapStd cmap,
- FT_Pointer pointer )
+ cff_cmap_encoding_init( FT_CMap cmap,
+ FT_Pointer pointer )
{
+ CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
CFF_Font cff = (CFF_Font)face->extra.data;
CFF_Encoding encoding = &cff->encoding;
@@ -42,63 +43,56 @@
FT_UNUSED( pointer );
- cmap->gids = encoding->codes;
+ cffcmap->gids = encoding->codes;
return 0;
}
FT_CALLBACK_DEF( void )
- cff_cmap_encoding_done( CFF_CMapStd cmap )
+ cff_cmap_encoding_done( FT_CMap cmap )
{
- cmap->gids = NULL;
+ CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
+
+
+ cffcmap->gids = NULL;
}
FT_CALLBACK_DEF( FT_UInt )
- cff_cmap_encoding_char_index( CFF_CMapStd cmap,
- FT_UInt32 char_code )
+ cff_cmap_encoding_char_index( FT_CMap cmap,
+ FT_UInt32 char_code )
{
- FT_UInt result = 0;
+ CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
+ FT_UInt result = 0;
if ( char_code < 256 )
- result = cmap->gids[char_code];
+ result = cffcmap->gids[char_code];
return result;
}
- FT_CALLBACK_DEF( FT_UInt32 )
- cff_cmap_encoding_char_next( CFF_CMapStd cmap,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_encoding_char_next( FT_CMap cmap,
+ FT_UInt32 *pchar_code )
{
- FT_UInt result = 0;
- FT_UInt32 char_code = *pchar_code;
+ CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code;
- *pchar_code = 0;
-
- if ( char_code < 255 )
+ while ( char_code < 255 )
{
- FT_UInt code = (FT_UInt)( char_code + 1 );
-
-
- for (;;)
+ result = cffcmap->gids[++char_code];
+ if ( result )
{
- if ( code >= 256 )
- break;
-
- result = cmap->gids[code];
- if ( result != 0 )
- {
- *pchar_code = code;
- break;
- }
-
- code++;
+ *pchar_code = char_code;
+ break;
}
}
+
return result;
}
@@ -130,9 +124,10 @@
/*************************************************************************/
FT_CALLBACK_DEF( const char* )
- cff_sid_to_glyph_name( TT_Face face,
+ cff_sid_to_glyph_name( void* face_, /* TT_Face */
FT_UInt idx )
{
+ TT_Face face = (TT_Face)face_;
CFF_Font cff = (CFF_Font)face->extra.data;
CFF_Charset charset = &cff->charset;
FT_UInt sid = charset->sids[idx];
@@ -143,14 +138,15 @@
FT_CALLBACK_DEF( FT_Error )
- cff_cmap_unicode_init( PS_Unicodes unicodes,
+ cff_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */
FT_Pointer pointer )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
- CFF_Font cff = (CFF_Font)face->extra.data;
- CFF_Charset charset = &cff->charset;
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ CFF_Charset charset = &cff->charset;
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
FT_UNUSED( pointer );
@@ -166,17 +162,18 @@
return psnames->unicodes_init( memory,
unicodes,
cff->num_glyphs,
- (PS_GetGlyphNameFunc)&cff_sid_to_glyph_name,
+ &cff_sid_to_glyph_name,
(PS_FreeGlyphNameFunc)NULL,
(FT_Pointer)face );
}
FT_CALLBACK_DEF( void )
- cff_cmap_unicode_done( PS_Unicodes unicodes )
+ cff_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */
{
- FT_Face face = FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_FREE( unicodes->maps );
@@ -185,25 +182,27 @@
FT_CALLBACK_DEF( FT_UInt )
- cff_cmap_unicode_char_index( PS_Unicodes unicodes,
- FT_UInt32 char_code )
+ cff_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 char_code )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- CFF_Font cff = (CFF_Font)face->extra.data;
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
return psnames->unicodes_char_index( unicodes, char_code );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- cff_cmap_unicode_char_next( PS_Unicodes unicodes,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 *pchar_code )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- CFF_Font cff = (CFF_Font)face->extra.data;
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
return psnames->unicodes_char_next( unicodes, pchar_code );
diff --git a/thirdparty/freetype/src/cff/cffdrivr.c b/thirdparty/freetype/src/cff/cffdrivr.c
index 4e2e0e00de..9898d625ca 100644
--- a/thirdparty/freetype/src/cff/cffdrivr.c
+++ b/thirdparty/freetype/src/cff/cffdrivr.c
@@ -108,20 +108,20 @@
* They can be implemented by format-specific interfaces.
*/
FT_CALLBACK_DEF( FT_Error )
- cff_get_kerning( FT_Face ttface, /* TT_Face */
+ cff_get_kerning( FT_Face face, /* CFF_Face */
FT_UInt left_glyph,
FT_UInt right_glyph,
FT_Vector* kerning )
{
- TT_Face face = (TT_Face)ttface;
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ CFF_Face cffface = (CFF_Face)face;
+ SFNT_Service sfnt = (SFNT_Service)cffface->sfnt;
kerning->x = 0;
kerning->y = 0;
if ( sfnt )
- kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph );
+ kerning->x = sfnt->get_kerning( cffface, left_glyph, right_glyph );
return FT_Err_Ok;
}
@@ -158,23 +158,23 @@
* FreeType error code. 0 means success.
*/
FT_CALLBACK_DEF( FT_Error )
- cff_glyph_load( FT_GlyphSlot cffslot, /* CFF_GlyphSlot */
- FT_Size cffsize, /* CFF_Size */
+ cff_glyph_load( FT_GlyphSlot slot, /* CFF_GlyphSlot */
+ FT_Size size, /* CFF_Size */
FT_UInt glyph_index,
FT_Int32 load_flags )
{
FT_Error error;
- CFF_GlyphSlot slot = (CFF_GlyphSlot)cffslot;
- CFF_Size size = (CFF_Size)cffsize;
+ CFF_GlyphSlot cffslot = (CFF_GlyphSlot)slot;
+ CFF_Size cffsize = (CFF_Size)size;
- if ( !slot )
+ if ( !cffslot )
return FT_THROW( Invalid_Slot_Handle );
FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index ));
/* check whether we want a scaled outline or bitmap */
- if ( !size )
+ if ( !cffsize )
load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
/* reset the size object if necessary */
@@ -184,12 +184,12 @@
if ( size )
{
/* these two objects must have the same parent */
- if ( cffsize->face != cffslot->face )
+ if ( size->face != slot->face )
return FT_THROW( Invalid_Face_Handle );
}
/* now load the glyph outline if necessary */
- error = cff_slot_load( slot, size, glyph_index, load_flags );
+ error = cff_slot_load( cffslot, cffsize, glyph_index, load_flags );
/* force drop-out mode to 2 - irrelevant now */
/* slot->outline.dropout_mode = 2; */
@@ -216,7 +216,7 @@
/* it is no longer necessary that those values are identical to */
/* the values in the `CFF' table */
- TT_Face ttface = (TT_Face)face;
+ CFF_Face cffface = (CFF_Face)face;
FT_Short dummy;
@@ -225,7 +225,7 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
/* no fast retrieval for blended MM fonts without VVAR table */
if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
- !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
+ !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
return FT_THROW( Unimplemented_Feature );
#endif
@@ -233,7 +233,7 @@
/* otherwise we extract the info from the CFF glyphstrings */
/* (instead of synthesizing a global value using the `OS/2' */
/* table) */
- if ( !ttface->vertical_info )
+ if ( !cffface->vertical_info )
goto Missing_Table;
for ( nn = 0; nn < count; nn++ )
@@ -241,11 +241,11 @@
FT_UShort ah;
- ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
- 1,
- start + nn,
- &dummy,
- &ah );
+ ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface,
+ 1,
+ start + nn,
+ &dummy,
+ &ah );
FT_TRACE5(( " idx %d: advance height %d font unit%s\n",
start + nn,
@@ -259,12 +259,12 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
/* no fast retrieval for blended MM fonts without HVAR table */
if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
- !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
+ !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
return FT_THROW( Unimplemented_Feature );
#endif
/* check whether we have data from the `hmtx' table at all */
- if ( !ttface->horizontal.number_Of_HMetrics )
+ if ( !cffface->horizontal.number_Of_HMetrics )
goto Missing_Table;
for ( nn = 0; nn < count; nn++ )
@@ -272,11 +272,11 @@
FT_UShort aw;
- ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
- 0,
- start + nn,
- &dummy,
- &aw );
+ ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface,
+ 0,
+ start + nn,
+ &dummy,
+ &aw );
FT_TRACE5(( " idx %d: advance width %d font unit%s\n",
start + nn,
@@ -312,13 +312,14 @@
*
*/
- static FT_Error
- cff_get_glyph_name( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_glyph_name( FT_Face face, /* CFF_Face */
FT_UInt glyph_index,
FT_Pointer buffer,
FT_UInt buffer_max )
{
- CFF_Font font = (CFF_Font)face->extra.data;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font font = (CFF_Font)cffface->extra.data;
FT_String* gname;
FT_UShort sid;
FT_Error error;
@@ -338,10 +339,7 @@
if ( service && service->get_name )
- return service->get_name( FT_FACE( face ),
- glyph_index,
- buffer,
- buffer_max );
+ return service->get_name( face, glyph_index, buffer, buffer_max );
else
{
FT_ERROR(( "cff_get_glyph_name:"
@@ -366,7 +364,7 @@
/* first, locate the sid in the charset table */
sid = font->charset.sids[glyph_index];
- /* now, lookup the name itself */
+ /* now, look up the name itself */
gname = cff_index_get_sid_string( font, sid );
if ( gname )
@@ -379,21 +377,19 @@
}
- static FT_UInt
- cff_get_name_index( CFF_Face face,
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_get_name_index( FT_Face face, /* CFF_Face */
const FT_String* glyph_name )
{
- CFF_Font cff;
- CFF_Charset charset;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
+ CFF_Charset charset = &cff->charset;
FT_Service_PsCMaps psnames;
FT_String* name;
FT_UShort sid;
FT_UInt i;
- cff = (CFF_FontRec *)face->extra.data;
- charset = &cff->charset;
-
/* CFF2 table does not have glyph names; */
/* we need to use `post' table method */
if ( cff->version_major == 2 )
@@ -408,7 +404,7 @@
if ( service && service->name_index )
- return service->name_index( FT_FACE( face ), glyph_name );
+ return service->name_index( face, glyph_name );
else
{
FT_ERROR(( "cff_get_name_index:"
@@ -446,8 +442,8 @@
FT_DEFINE_SERVICE_GLYPHDICTREC(
cff_service_glyph_dict,
- (FT_GlyphDict_GetNameFunc) cff_get_glyph_name, /* get_name */
- (FT_GlyphDict_NameIndexFunc)cff_get_name_index /* name_index */
+ cff_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */
+ cff_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */
)
@@ -456,25 +452,32 @@
*
*/
- static FT_Int
+ FT_CALLBACK_DEF( FT_Int )
cff_ps_has_glyph_names( FT_Face face )
{
return ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) > 0;
}
- static FT_Error
- cff_ps_get_font_info( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_ps_get_font_info( FT_Face face, /* CFF_Face */
PS_FontInfoRec* afont_info )
{
- CFF_Font cff = (CFF_Font)face->extra.data;
- FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
+ FT_Error error = FT_Err_Ok;
+ if ( cffface->is_cff2 )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Fail;
+ }
+
if ( cff && !cff->font_info )
{
CFF_FontRecDict dict = &cff->top_font.font_dict;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
PS_FontInfoRec* font_info = NULL;
@@ -507,18 +510,19 @@
}
- static FT_Error
- cff_ps_get_font_extra( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_ps_get_font_extra( FT_Face face, /* CFF_Face */
PS_FontExtraRec* afont_extra )
{
- CFF_Font cff = (CFF_Font)face->extra.data;
- FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
+ FT_Error error = FT_Err_Ok;
if ( cff && !cff->font_extra )
{
CFF_FontRecDict dict = &cff->top_font.font_dict;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
PS_FontExtraRec* font_extra = NULL;
FT_String* embedded_postscript;
@@ -588,13 +592,13 @@
FT_DEFINE_SERVICE_PSINFOREC(
cff_service_ps_info,
- (PS_GetFontInfoFunc) cff_ps_get_font_info, /* ps_get_font_info */
- (PS_GetFontExtraFunc) cff_ps_get_font_extra, /* ps_get_font_extra */
- (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names, /* ps_has_glyph_names */
+ cff_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */
+ cff_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */
+ cff_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */
/* unsupported with CFF fonts */
- (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */
+ NULL, /* PS_GetFontPrivateFunc ps_get_font_private */
/* not implemented */
- (PS_GetFontValueFunc) NULL /* ps_get_font_value */
+ NULL /* PS_GetFontValueFunc ps_get_font_value */
)
@@ -603,17 +607,18 @@
*
*/
- static const char*
- cff_get_ps_name( CFF_Face face )
+ FT_CALLBACK_DEF( const char* )
+ cff_get_ps_name( FT_Face face ) /* CFF_Face */
{
- CFF_Font cff = (CFF_Font)face->extra.data;
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
+ SFNT_Service sfnt = (SFNT_Service)cffface->sfnt;
/* following the OpenType specification 1.7, we return the name stored */
/* in the `name' table for a CFF wrapped into an SFNT container */
- if ( FT_IS_SFNT( FT_FACE( face ) ) && sfnt )
+ if ( FT_IS_SFNT( face ) && sfnt )
{
FT_Library library = FT_FACE_LIBRARY( face );
FT_Module sfnt_module = FT_Get_Module( library, "sfnt" );
@@ -625,17 +630,17 @@
if ( service && service->get_ps_font_name )
- return service->get_ps_font_name( FT_FACE( face ) );
+ return service->get_ps_font_name( face );
}
- return (const char*)cff->font_name;
+ return cff ? (const char*)cff->font_name : NULL;
}
FT_DEFINE_SERVICE_PSFONTNAMEREC(
cff_service_ps_name,
- (FT_PsName_GetFunc)cff_get_ps_name /* get_ps_font_name */
+ cff_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */
)
@@ -649,7 +654,7 @@
* Otherwise call the service function in the sfnt module.
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
cff_get_cmap_info( FT_CharMap charmap,
TT_CMapInfo *cmap_info )
{
@@ -683,7 +688,7 @@
FT_DEFINE_SERVICE_TTCMAPSREC(
cff_service_get_cmap_info,
- (TT_CMap_Info_GetFunc)cff_get_cmap_info /* get_cmap_info */
+ cff_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */
)
@@ -691,14 +696,15 @@
* CID INFO SERVICE
*
*/
- static FT_Error
- cff_get_ros( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_ros( FT_Face face, /* FT_Face */
const char* *registry,
const char* *ordering,
FT_Int *supplement )
{
- FT_Error error = FT_Err_Ok;
- CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
if ( cff )
@@ -748,12 +754,13 @@
}
- static FT_Error
- cff_get_is_cid( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_is_cid( FT_Face face, /* CFF_Face */
FT_Bool *is_cid )
{
- FT_Error error = FT_Err_Ok;
- CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
*is_cid = 0;
@@ -771,16 +778,15 @@
}
- static FT_Error
- cff_get_cid_from_glyph_index( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_cid_from_glyph_index( FT_Face face, /* CFF_Face */
FT_UInt glyph_index,
FT_UInt *cid )
{
- FT_Error error = FT_Err_Ok;
- CFF_Font cff;
-
+ FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
- cff = (CFF_Font)face->extra.data;
if ( cff )
{
@@ -814,12 +820,12 @@
FT_DEFINE_SERVICE_CIDREC(
cff_service_cid_info,
- (FT_CID_GetRegistryOrderingSupplementFunc)
- cff_get_ros, /* get_ros */
- (FT_CID_GetIsInternallyCIDKeyedFunc)
- cff_get_is_cid, /* get_is_cid */
- (FT_CID_GetCIDFromGlyphIndexFunc)
- cff_get_cid_from_glyph_index /* get_cid_from_glyph_index */
+ cff_get_ros,
+ /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */
+ cff_get_is_cid,
+ /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */
+ cff_get_cid_from_glyph_index
+ /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */
)
@@ -831,9 +837,9 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
cff_service_properties,
- (FT_Properties_SetFunc)ps_property_set, /* set_property */
- (FT_Properties_GetFunc)ps_property_get ) /* get_property */
-
+ ps_property_set, /* FT_Properties_SetFunc set_property */
+ ps_property_get /* FT_Properties_GetFunc get_property */
+ )
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
@@ -842,160 +848,195 @@
*
*/
- static FT_Error
- cff_set_mm_blend( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_set_mm_blend( FT_Face face, /* CFF_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->set_mm_blend( FT_FACE( face ), num_coords, coords );
+ return mm->set_mm_blend( face, num_coords, coords );
}
- static FT_Error
- cff_get_mm_blend( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_mm_blend( FT_Face face, /* CFF_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_mm_blend( FT_FACE( face ), num_coords, coords );
+ return mm->get_mm_blend( face, num_coords, coords );
}
- static FT_Error
- cff_set_mm_weightvector( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_set_mm_weightvector( FT_Face face, /* CFF_Face */
FT_UInt len,
FT_Fixed* weightvector )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->set_mm_weightvector( FT_FACE( face ), len, weightvector );
+ return mm->set_mm_weightvector( face, len, weightvector );
}
- static FT_Error
- cff_get_mm_weightvector( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_mm_weightvector( FT_Face face, /* CFF_Face */
FT_UInt* len,
FT_Fixed* weightvector )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_mm_weightvector( FT_FACE( face ), len, weightvector );
+ return mm->get_mm_weightvector( face, len, weightvector );
}
- static FT_Error
- cff_get_mm_var( CFF_Face face,
+ FT_CALLBACK_DEF( void )
+ cff_construct_ps_name( FT_Face face ) /* CFF_Face */
+ {
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
+
+
+ mm->construct_ps_name( face );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_mm_var( FT_Face face, /* CFF_Face */
FT_MM_Var* *master )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_mm_var( FT_FACE( face ), master );
+ return mm->get_mm_var( face, master );
}
- static FT_Error
- cff_set_var_design( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_set_var_design( FT_Face face, /* CFF_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->set_var_design( FT_FACE( face ), num_coords, coords );
+ return mm->set_var_design( face, num_coords, coords );
}
- static FT_Error
- cff_get_var_design( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_var_design( FT_Face face, /* CFF_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_var_design( FT_FACE( face ), num_coords, coords );
+ return mm->get_var_design( face, num_coords, coords );
}
- static FT_Error
- cff_set_instance( CFF_Face face,
- FT_UInt instance_index )
+ FT_CALLBACK_DEF( FT_Error )
+ cff_set_named_instance( FT_Face face, /* CFF_Face */
+ FT_UInt instance_index )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->set_instance( FT_FACE( face ), instance_index );
+ return mm->set_named_instance( face, instance_index );
}
- static FT_Error
- cff_load_item_variation_store( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_default_named_instance( FT_Face face, /* CFF_Face */
+ FT_UInt *instance_index )
+ {
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
+
+
+ return mm->get_default_named_instance( face, instance_index );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ cff_load_item_variation_store( FT_Face face, /* CFF_Face */
FT_ULong offset,
GX_ItemVarStore itemStore )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->load_item_var_store( FT_FACE(face), offset, itemStore );
+ return mm->load_item_var_store( face, offset, itemStore );
}
- static FT_Error
- cff_load_delta_set_index_mapping( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_load_delta_set_index_mapping( FT_Face face, /* CFF_Face */
FT_ULong offset,
GX_DeltaSetIdxMap map,
GX_ItemVarStore itemStore,
FT_ULong table_len )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->load_delta_set_idx_map( FT_FACE( face ), offset, map,
+ return mm->load_delta_set_idx_map( face, offset, map,
itemStore, table_len );
}
- static FT_Int
- cff_get_item_delta( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Int )
+ cff_get_item_delta( FT_Face face, /* CFF_Face */
GX_ItemVarStore itemStore,
FT_UInt outerIndex,
FT_UInt innerIndex )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_item_delta( FT_FACE( face ), itemStore,
- outerIndex, innerIndex );
+ return mm->get_item_delta( face, itemStore, outerIndex, innerIndex );
}
- static void
- cff_done_item_variation_store( CFF_Face face,
+ FT_CALLBACK_DEF( void )
+ cff_done_item_variation_store( FT_Face face, /* CFF_Face */
GX_ItemVarStore itemStore )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- mm->done_item_var_store( FT_FACE( face ), itemStore );
+ mm->done_item_var_store( face, itemStore );
}
- static void
- cff_done_delta_set_index_map( CFF_Face face,
+ FT_CALLBACK_DEF( void )
+ cff_done_delta_set_index_map( FT_Face face, /* CFF_Face */
GX_DeltaSetIdxMap deltaSetIdxMap )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- mm->done_delta_set_idx_map( FT_FACE ( face ), deltaSetIdxMap );
+ mm->done_delta_set_idx_map( face, deltaSetIdxMap );
}
@@ -1003,36 +1044,35 @@
FT_DEFINE_SERVICE_MULTIMASTERSREC(
cff_service_multi_masters,
- (FT_Get_MM_Func) NULL, /* get_mm */
- (FT_Set_MM_Design_Func) NULL, /* set_mm_design */
- (FT_Set_MM_Blend_Func) cff_set_mm_blend, /* set_mm_blend */
- (FT_Get_MM_Blend_Func) cff_get_mm_blend, /* get_mm_blend */
- (FT_Get_MM_Var_Func) cff_get_mm_var, /* get_mm_var */
- (FT_Set_Var_Design_Func)cff_set_var_design, /* set_var_design */
- (FT_Get_Var_Design_Func)cff_get_var_design, /* get_var_design */
- (FT_Set_Instance_Func) cff_set_instance, /* set_instance */
- (FT_Set_MM_WeightVector_Func)
- cff_set_mm_weightvector,
- /* set_mm_weightvector */
- (FT_Get_MM_WeightVector_Func)
- cff_get_mm_weightvector,
- /* get_mm_weightvector */
- (FT_Var_Load_Delta_Set_Idx_Map_Func)
- cff_load_delta_set_index_mapping,
- /* load_delta_set_idx_map */
- (FT_Var_Load_Item_Var_Store_Func)
- cff_load_item_variation_store,
- /* load_item_variation_store */
- (FT_Var_Get_Item_Delta_Func)
- cff_get_item_delta, /* get_item_delta */
- (FT_Var_Done_Item_Var_Store_Func)
- cff_done_item_variation_store,
- /* done_item_variation_store */
- (FT_Var_Done_Delta_Set_Idx_Map_Func)
- cff_done_delta_set_index_map,
- /* done_delta_set_index_map */
- (FT_Get_Var_Blend_Func) cff_get_var_blend, /* get_var_blend */
- (FT_Done_Blend_Func) cff_done_blend /* done_blend */
+ NULL, /* FT_Get_MM_Func get_mm */
+ NULL, /* FT_Set_MM_Design_Func set_mm_design */
+ cff_set_mm_blend, /* FT_Set_MM_Blend_Func set_mm_blend */
+ cff_get_mm_blend, /* FT_Get_MM_Blend_Func get_mm_blend */
+ cff_get_mm_var, /* FT_Get_MM_Var_Func get_mm_var */
+ cff_set_var_design, /* FT_Set_Var_Design_Func set_var_design */
+ cff_get_var_design, /* FT_Get_Var_Design_Func get_var_design */
+ cff_set_named_instance,
+ /* FT_Set_Named_Instance_Func set_named_instance */
+ cff_get_default_named_instance,
+ /* FT_Get_Default_Named_Instance_Func get_default_named_instance */
+ cff_set_mm_weightvector,
+ /* FT_Set_MM_WeightVector_Func set_mm_weightvector */
+ cff_get_mm_weightvector,
+ /* FT_Get_MM_WeightVector_Func get_mm_weightvector */
+ cff_construct_ps_name,
+ /* FT_Construct_PS_Name_Func construct_ps_name */
+ cff_load_delta_set_index_mapping,
+ /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */
+ cff_load_item_variation_store,
+ /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */
+ cff_get_item_delta,
+ /* FT_Var_Get_Item_Delta_Func get_item_delta */
+ cff_done_item_variation_store,
+ /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */
+ cff_done_delta_set_index_map,
+ /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */
+ cff_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */
+ cff_done_blend /* FT_Done_Blend_Func done_blend */
)
@@ -1041,41 +1081,46 @@
*
*/
- static FT_Error
- cff_hadvance_adjust( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_hadvance_adjust( FT_Face face, /* CFF_Face */
FT_UInt gindex,
FT_Int *avalue )
{
- FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MetricsVariations
+ var = (FT_Service_MetricsVariations)cffface->tt_var;
- return var->hadvance_adjust( FT_FACE( face ), gindex, avalue );
+ return var->hadvance_adjust( face, gindex, avalue );
}
- static void
- cff_metrics_adjust( CFF_Face face )
+ FT_CALLBACK_DEF( void )
+ cff_metrics_adjust( FT_Face face ) /* CFF_Face */
{
- FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MetricsVariations
+ var = (FT_Service_MetricsVariations)cffface->tt_var;
- var->metrics_adjust( FT_FACE( face ) );
+ var->metrics_adjust( face );
}
FT_DEFINE_SERVICE_METRICSVARIATIONSREC(
cff_service_metrics_variations,
- (FT_HAdvance_Adjust_Func)cff_hadvance_adjust, /* hadvance_adjust */
- (FT_LSB_Adjust_Func) NULL, /* lsb_adjust */
- (FT_RSB_Adjust_Func) NULL, /* rsb_adjust */
+ cff_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */
+ NULL, /* FT_LSB_Adjust_Func lsb_adjust */
+ NULL, /* FT_RSB_Adjust_Func rsb_adjust */
- (FT_VAdvance_Adjust_Func)NULL, /* vadvance_adjust */
- (FT_TSB_Adjust_Func) NULL, /* tsb_adjust */
- (FT_BSB_Adjust_Func) NULL, /* bsb_adjust */
- (FT_VOrg_Adjust_Func) NULL, /* vorg_adjust */
+ NULL, /* FT_VAdvance_Adjust_Func vadvance_adjust */
+ NULL, /* FT_TSB_Adjust_Func tsb_adjust */
+ NULL, /* FT_BSB_Adjust_Func bsb_adjust */
+ NULL, /* FT_VOrg_Adjust_Func vorg_adjust */
- (FT_Metrics_Adjust_Func) cff_metrics_adjust /* metrics_adjust */
+ cff_metrics_adjust, /* FT_Metrics_Adjust_Func metrics_adjust */
+ NULL /* FT_Size_Reset_Func size_reset */
)
#endif
@@ -1088,11 +1133,11 @@
FT_DEFINE_SERVICE_CFFLOADREC(
cff_service_cff_load,
- (FT_Get_Standard_Encoding_Func)cff_get_standard_encoding,
- (FT_Load_Private_Dict_Func) cff_load_private_dict,
- (FT_FD_Select_Get_Func) cff_fd_select_get,
- (FT_Blend_Check_Vector_Func) cff_blend_check_vector,
- (FT_Blend_Build_Vector_Func) cff_blend_build_vector
+ cff_get_standard_encoding, /* FT_Get_Standard_Encoding_Func get_standard_encoding */
+ cff_load_private_dict, /* FT_Load_Private_Dict_Func load_private_dict */
+ cff_fd_select_get, /* FT_FD_Select_Get_Func fd_select_get */
+ cff_blend_check_vector, /* FT_Blend_Check_Vector_Func blend_check_vector */
+ cff_blend_build_vector /* FT_Blend_Build_Vector_Func blend_build_vector */
)
diff --git a/thirdparty/freetype/src/cff/cffgload.c b/thirdparty/freetype/src/cff/cffgload.c
index cfa0aaf2b6..c483d1d1a5 100644
--- a/thirdparty/freetype/src/cff/cffgload.c
+++ b/thirdparty/freetype/src/cff/cffgload.c
@@ -356,14 +356,16 @@
#ifdef FT_CONFIG_OPTION_SVG
/* check for OT-SVG */
- if ( ( load_flags & FT_LOAD_COLOR ) && face->svg )
+ if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
+ ( load_flags & FT_LOAD_COLOR ) &&
+ face->svg )
{
/*
* We load the SVG document and try to grab the advances from the
* table. For the bearings we rely on the presetting hook to do that.
*/
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ SFNT_Service sfnt = (SFNT_Service)face->sfnt;
if ( size && (size->root.metrics.x_ppem < 1 ||
diff --git a/thirdparty/freetype/src/cff/cffload.c b/thirdparty/freetype/src/cff/cffload.c
index 4b8c6e16c5..f96002ec0b 100644
--- a/thirdparty/freetype/src/cff/cffload.c
+++ b/thirdparty/freetype/src/cff/cffload.c
@@ -400,7 +400,7 @@
/* Allocate a table containing pointers to an index's elements. */
/* The `pool' argument makes this function convert the index */
- /* entries to C-style strings (this is, null-terminated). */
+ /* entries to C-style strings (that is, null-terminated). */
static FT_Error
cff_index_get_pointers( CFF_Index idx,
FT_Byte*** table,
@@ -1589,16 +1589,17 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_LOCAL_DEF( FT_Error )
- cff_get_var_blend( CFF_Face face,
+ cff_get_var_blend( FT_Face face, /* CFF_Face */
FT_UInt *num_coords,
FT_Fixed* *coords,
FT_Fixed* *normalizedcoords,
FT_MM_Var* *mm_var )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_var_blend( FT_FACE( face ),
+ return mm->get_var_blend( face,
num_coords,
coords,
normalizedcoords,
@@ -1607,13 +1608,14 @@
FT_LOCAL_DEF( void )
- cff_done_blend( CFF_Face face )
+ cff_done_blend( FT_Face face ) /* CFF_Face */
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- if (mm)
- mm->done_blend( FT_FACE( face ) );
+ if ( mm )
+ mm->done_blend( face );
}
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
@@ -1650,13 +1652,6 @@
goto Exit;
}
- /* Zero out the code to gid/sid mappings. */
- for ( j = 0; j < 256; j++ )
- {
- encoding->sids [j] = 0;
- encoding->codes[j] = 0;
- }
-
/* Note: The encoding table in a CFF font is indexed by glyph index; */
/* the first encoded glyph index is 1. Hence, we read the character */
/* code (`glyph_code') at index j and make the assignment: */
@@ -1671,6 +1666,10 @@
if ( offset > 1 )
{
+ /* Zero out the code to gid/sid mappings. */
+ FT_ARRAY_ZERO( encoding->sids, 256 );
+ FT_ARRAY_ZERO( encoding->codes, 256 );
+
encoding->offset = base_offset + offset;
/* we need to parse the table to determine its size */
@@ -2012,7 +2011,7 @@
/* Top and Font DICTs are not allowed to have blend operators. */
error = cff_parser_init( &parser,
code,
- &subfont->font_dict,
+ top,
font->library,
stackSize,
0,
diff --git a/thirdparty/freetype/src/cff/cffload.h b/thirdparty/freetype/src/cff/cffload.h
index 5a41cdebc8..b5286b0c8c 100644
--- a/thirdparty/freetype/src/cff/cffload.h
+++ b/thirdparty/freetype/src/cff/cffload.h
@@ -105,14 +105,14 @@ FT_BEGIN_HEADER
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_LOCAL( FT_Error )
- cff_get_var_blend( CFF_Face face,
+ cff_get_var_blend( FT_Face face,
FT_UInt *num_coords,
FT_Fixed* *coords,
FT_Fixed* *normalizedcoords,
FT_MM_Var* *mm_var );
FT_LOCAL( void )
- cff_done_blend( CFF_Face face );
+ cff_done_blend( FT_Face face );
#endif
diff --git a/thirdparty/freetype/src/cff/cffobjs.c b/thirdparty/freetype/src/cff/cffobjs.c
index 40cd9bf917..6d08620c48 100644
--- a/thirdparty/freetype/src/cff/cffobjs.c
+++ b/thirdparty/freetype/src/cff/cffobjs.c
@@ -69,8 +69,8 @@
FT_Module module;
- module = FT_Get_Module( size->root.face->driver->root.library,
- "pshinter" );
+ module = FT_Get_Module( font->library, "pshinter" );
+
return ( module && pshinter && pshinter->get_globals_funcs )
? pshinter->get_globals_funcs( module )
: 0;
@@ -182,8 +182,7 @@
goto Exit;
cff_make_private_dict( &font->top_font, &priv );
- error = funcs->create( cffsize->face->memory, &priv,
- &internal->topfont );
+ error = funcs->create( memory, &priv, &internal->topfont );
if ( error )
goto Exit;
@@ -193,8 +192,7 @@
cff_make_private_dict( sub, &priv );
- error = funcs->create( cffsize->face->memory, &priv,
- &internal->subfonts[i - 1] );
+ error = funcs->create( memory, &priv, &internal->subfonts[i - 1] );
if ( error )
goto Exit;
}
@@ -381,8 +379,7 @@
FT_Module module;
- module = FT_Get_Module( slot->face->driver->root.library,
- "pshinter" );
+ module = FT_Get_Module( slot->library, "pshinter" );
if ( module )
{
T2_Hints_Funcs funcs;
@@ -722,22 +719,15 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
- FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var;
-
FT_UInt instance_index = (FT_UInt)face_index >> 16;
if ( FT_HAS_MULTIPLE_MASTERS( cffface ) &&
- mm &&
instance_index > 0 )
{
- error = mm->set_instance( cffface, instance_index );
+ error = FT_Set_Named_Instance( cffface, instance_index );
if ( error )
goto Exit;
-
- if ( var )
- var->metrics_adjust( cffface );
}
}
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
@@ -1160,7 +1150,7 @@
}
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- cff_done_blend( face );
+ cff_done_blend( cffface );
face->blend = NULL;
#endif
}
diff --git a/thirdparty/freetype/src/cff/cffparse.c b/thirdparty/freetype/src/cff/cffparse.c
index e16206fd55..c850dfc61e 100644
--- a/thirdparty/freetype/src/cff/cffparse.c
+++ b/thirdparty/freetype/src/cff/cffparse.c
@@ -63,10 +63,7 @@
/* allocate the stack buffer */
if ( FT_QNEW_ARRAY( parser->stack, stackSize ) )
- {
- FT_FREE( parser->stack );
goto Exit;
- }
parser->stackSize = stackSize;
parser->top = parser->stack; /* empty stack */
@@ -76,23 +73,6 @@
}
-#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
- static void
- finalize_t2_strings( FT_Memory memory,
- void* data,
- void* user )
- {
- CFF_T2_String t2 = (CFF_T2_String)data;
-
-
- FT_UNUSED( user );
-
- memory->free( memory, t2->start );
- memory->free( memory, data );
- }
-#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
-
-
FT_LOCAL_DEF( void )
cff_parser_done( CFF_Parser parser )
{
@@ -102,63 +82,19 @@
FT_FREE( parser->stack );
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
- FT_List_Finalize( &parser->t2_strings,
- finalize_t2_strings,
- memory,
- NULL );
+ FT_List_Finalize( &parser->t2_strings, NULL, memory, NULL );
#endif
}
- /* Assuming `first >= last'. */
-
- static FT_Error
- cff_parser_within_limits( CFF_Parser parser,
- FT_Byte* first,
- FT_Byte* last )
- {
-#ifndef CFF_CONFIG_OPTION_OLD_ENGINE
-
- /* Fast path for regular FreeType builds with the "new" engine; */
- /* `first >= parser->start' can be assumed. */
-
- FT_UNUSED( first );
-
- return last < parser->limit ? FT_Err_Ok : FT_THROW( Invalid_Argument );
-
-#else /* CFF_CONFIG_OPTION_OLD_ENGINE */
-
- FT_ListNode node;
-
-
- if ( first >= parser->start &&
- last < parser->limit )
- return FT_Err_Ok;
-
- node = parser->t2_strings.head;
-
- while ( node )
- {
- CFF_T2_String t2 = (CFF_T2_String)node->data;
-
-
- if ( first >= t2->start &&
- last < t2->limit )
- return FT_Err_Ok;
-
- node = node->next;
- }
-
- return FT_THROW( Invalid_Argument );
-
-#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
- }
-
+ /* The parser limit checks in the next two functions are supposed */
+ /* to detect the immediate crossing of the stream boundary. They */
+ /* shall not be triggered from the distant t2_strings buffers. */
/* read an integer */
static FT_Long
- cff_parse_integer( CFF_Parser parser,
- FT_Byte* start )
+ cff_parse_integer( FT_Byte* start,
+ FT_Byte* limit )
{
FT_Byte* p = start;
FT_Int v = *p++;
@@ -167,14 +103,14 @@
if ( v == 28 )
{
- if ( cff_parser_within_limits( parser, p, p + 1 ) )
+ if ( p + 2 > limit && limit >= p )
goto Bad;
val = (FT_Short)( ( (FT_UShort)p[0] << 8 ) | p[1] );
}
else if ( v == 29 )
{
- if ( cff_parser_within_limits( parser, p, p + 3 ) )
+ if ( p + 4 > limit && limit >= p )
goto Bad;
val = (FT_Long)( ( (FT_ULong)p[0] << 24 ) |
@@ -188,14 +124,14 @@
}
else if ( v < 251 )
{
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
val = ( v - 247 ) * 256 + p[0] + 108;
}
else
{
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
val = -( v - 251 ) * 256 - p[0] - 108;
@@ -244,10 +180,10 @@
/* read a real */
static FT_Fixed
- cff_parse_real( CFF_Parser parser,
- FT_Byte* start,
- FT_Long power_ten,
- FT_Long* scaling )
+ cff_parse_real( FT_Byte* start,
+ FT_Byte* limit,
+ FT_Long power_ten,
+ FT_Long* scaling )
{
FT_Byte* p = start;
FT_Int nib;
@@ -282,7 +218,7 @@
p++;
/* Make sure we don't read past the end. */
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
}
@@ -319,7 +255,7 @@
p++;
/* Make sure we don't read past the end. */
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
}
@@ -358,7 +294,7 @@
p++;
/* Make sure we don't read past the end. */
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
}
@@ -525,7 +461,7 @@
if ( **d == 30 )
{
/* binary-coded decimal is truncated to integer */
- return cff_parse_real( parser, *d, 0, NULL ) >> 16;
+ return cff_parse_real( *d, parser->limit, 0, NULL ) >> 16;
}
else if ( **d == 255 )
@@ -551,7 +487,7 @@
}
else
- return cff_parse_integer( parser, *d );
+ return cff_parse_integer( *d, parser->limit );
}
@@ -562,10 +498,10 @@
FT_Long scaling )
{
if ( **d == 30 )
- return cff_parse_real( parser, *d, scaling, NULL );
+ return cff_parse_real( *d, parser->limit, scaling, NULL );
else
{
- FT_Long val = cff_parse_integer( parser, *d );
+ FT_Long val = cff_parse_integer( *d, parser->limit );
if ( scaling )
@@ -630,14 +566,14 @@
FT_ASSERT( scaling );
if ( **d == 30 )
- return cff_parse_real( parser, *d, 0, scaling );
+ return cff_parse_real( *d, parser->limit, 0, scaling );
else
{
FT_Long number;
FT_Int integer_length;
- number = cff_parse_integer( parser, d[0] );
+ number = cff_parse_integer( *d, parser->limit );
if ( number > 0x7FFFL )
{
@@ -686,7 +622,7 @@
dict->has_font_matrix = TRUE;
- /* We expect a well-formed font matrix, this is, the matrix elements */
+ /* We expect a well-formed font matrix, that is, the matrix elements */
/* `xx' and `yy' are of approximately the same magnitude. To avoid */
/* loss of precision, we use the magnitude of the largest matrix */
/* element to scale all other elements. The scaling factor is then */
@@ -1264,11 +1200,8 @@
FT_Byte* charstring_base;
FT_ULong charstring_len;
- FT_Fixed* stack;
- FT_ListNode node;
- CFF_T2_String t2;
- FT_Fixed t2_size;
- FT_Byte* q;
+ FT_Fixed* stack;
+ FT_Byte* q = NULL;
charstring_base = ++p;
@@ -1309,39 +1242,18 @@
/* Now copy the stack data in the temporary decoder object, */
/* converting it back to charstring number representations */
/* (this is ugly, I know). */
+ /* The maximum required size is 5 bytes per stack element. */
+ if ( FT_QALLOC( q, (FT_Long)( 2 * sizeof ( FT_ListNode ) ) +
+ 5 * ( decoder.top - decoder.stack ) ) )
+ goto Exit;
- node = (FT_ListNode)memory->alloc( memory,
- sizeof ( FT_ListNodeRec ) );
- if ( !node )
- goto Out_Of_Memory_Error;
-
- FT_List_Add( &parser->t2_strings, node );
-
- t2 = (CFF_T2_String)memory->alloc( memory,
- sizeof ( CFF_T2_StringRec ) );
- if ( !t2 )
- goto Out_Of_Memory_Error;
-
- node->data = t2;
-
- /* `5' is the conservative upper bound of required bytes per stack */
- /* element. */
-
- t2_size = 5 * ( decoder.top - decoder.stack );
-
- q = (FT_Byte*)memory->alloc( memory, t2_size );
- if ( !q )
- goto Out_Of_Memory_Error;
-
- t2->start = q;
- t2->limit = q + t2_size;
+ FT_List_Add( &parser->t2_strings, (FT_ListNode)q );
- stack = decoder.stack;
+ q += 2 * sizeof ( FT_ListNode );
- while ( stack < decoder.top )
+ for ( stack = decoder.stack; stack < decoder.top; stack++ )
{
- FT_ULong num;
- FT_Bool neg;
+ FT_Long num = *stack;
if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize )
@@ -1349,69 +1261,37 @@
*parser->top++ = q;
- if ( *stack < 0 )
- {
- num = (FT_ULong)NEG_LONG( *stack );
- neg = 1;
- }
- else
- {
- num = (FT_ULong)*stack;
- neg = 0;
- }
-
if ( num & 0xFFFFU )
{
- if ( neg )
- num = (FT_ULong)-num;
-
*q++ = 255;
- *q++ = ( num & 0xFF000000U ) >> 24;
- *q++ = ( num & 0x00FF0000U ) >> 16;
- *q++ = ( num & 0x0000FF00U ) >> 8;
- *q++ = num & 0x000000FFU;
+ *q++ = (FT_Byte)( ( num >> 24 ) & 0xFF );
+ *q++ = (FT_Byte)( ( num >> 16 ) & 0xFF );
+ *q++ = (FT_Byte)( ( num >> 8 ) & 0xFF );
+ *q++ = (FT_Byte)( ( num ) & 0xFF );
}
else
{
num >>= 16;
- if ( neg )
+ if ( -107 <= num && num <= 107 )
+ *q++ = (FT_Byte)( num + 139 );
+ else if ( 108 <= num && num <= 1131 )
{
- if ( num <= 107 )
- *q++ = (FT_Byte)( 139 - num );
- else if ( num <= 1131 )
- {
- *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 251 );
- *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
- }
- else
- {
- num = (FT_ULong)-num;
-
- *q++ = 28;
- *q++ = (FT_Byte)( num >> 8 );
- *q++ = (FT_Byte)( num & 0xFF );
- }
+ *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 );
+ *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
+ }
+ else if ( -1131 <= num && num <= -108 )
+ {
+ *q++ = (FT_Byte)( ( ( -num - 108 ) >> 8 ) + 251 );
+ *q++ = (FT_Byte)( ( -num - 108) & 0xFF );
}
else
{
- if ( num <= 107 )
- *q++ = (FT_Byte)( num + 139 );
- else if ( num <= 1131 )
- {
- *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 );
- *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
- }
- else
- {
- *q++ = 28;
- *q++ = (FT_Byte)( num >> 8 );
- *q++ = (FT_Byte)( num & 0xFF );
- }
+ *q++ = 28;
+ *q++ = (FT_Byte)( num >> 8 );
+ *q++ = (FT_Byte)( num & 0xFF );
}
}
-
- stack++;
}
}
#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
@@ -1598,12 +1478,6 @@
Exit:
return error;
-#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
- Out_Of_Memory_Error:
- error = FT_THROW( Out_Of_Memory );
- goto Exit;
-#endif
-
Stack_Overflow:
error = FT_THROW( Invalid_Argument );
goto Exit;
diff --git a/thirdparty/freetype/src/cff/cffparse.h b/thirdparty/freetype/src/cff/cffparse.h
index 58d59fa4ac..b6378a8e8d 100644
--- a/thirdparty/freetype/src/cff/cffparse.h
+++ b/thirdparty/freetype/src/cff/cffparse.h
@@ -133,15 +133,6 @@ FT_BEGIN_HEADER
FT_END_HEADER
-#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
- typedef struct CFF_T2_String_
- {
- FT_Byte* start;
- FT_Byte* limit;
-
- } CFF_T2_StringRec, *CFF_T2_String;
-#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
-
#endif /* CFFPARSE_H_ */
diff --git a/thirdparty/freetype/src/cid/cidgload.c b/thirdparty/freetype/src/cid/cidgload.c
index ba4b7565d5..eaca765ad0 100644
--- a/thirdparty/freetype/src/cid/cidgload.c
+++ b/thirdparty/freetype/src/cid/cidgload.c
@@ -40,6 +40,117 @@
#define FT_COMPONENT cidgload
+ /*
+ * A helper function to compute FD number (`fd_select`), the offset to the
+ * head of the glyph data (`off1`), and the offset to the and of the glyph
+ * data (`off2`).
+ *
+ * The number how many times `cid_get_offset` is invoked can be controlled
+ * by the number of non-NULL arguments. If `fd_select` is non-NULL but
+ * `off1` and `off2` are NULL, `cid_get_offset` is invoked only for
+ * `fd_select`; `off1` and `off2` are not validated.
+ *
+ */
+ FT_LOCAL_DEF( FT_Error )
+ cid_compute_fd_and_offsets( CID_Face face,
+ FT_UInt glyph_index,
+ FT_ULong* fd_select_p,
+ FT_ULong* off1_p,
+ FT_ULong* off2_p )
+ {
+ FT_Error error = FT_Err_Ok;
+
+ CID_FaceInfo cid = &face->cid;
+ FT_Stream stream = face->cid_stream;
+ FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes;
+
+ FT_Byte* p;
+ FT_Bool need_frame_exit = 0;
+ FT_ULong fd_select, off1, off2;
+
+
+ /* For ordinary fonts, read the CID font dictionary index */
+ /* and charstring offset from the CIDMap. */
+
+ if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset +
+ glyph_index * entry_len ) ||
+ FT_FRAME_ENTER( 2 * entry_len ) )
+ goto Exit;
+
+ need_frame_exit = 1;
+
+ p = (FT_Byte*)stream->cursor;
+ fd_select = cid_get_offset( &p, cid->fd_bytes );
+ off1 = cid_get_offset( &p, cid->gd_bytes );
+
+ p += cid->fd_bytes;
+ off2 = cid_get_offset( &p, cid->gd_bytes );
+
+ if ( fd_select_p )
+ *fd_select_p = fd_select;
+ if ( off1_p )
+ *off1_p = off1;
+ if ( off2_p )
+ *off2_p = off2;
+
+ if ( fd_select >= cid->num_dicts )
+ {
+ /*
+ * fd_select == 0xFF is often used to indicate that the CID
+ * has no charstring to be rendered, similar to GID = 0xFFFF
+ * in TrueType fonts.
+ */
+ if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU ) ||
+ ( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) )
+ {
+ FT_TRACE1(( "cid_load_glyph: fail for glyph index %d:\n",
+ glyph_index ));
+ FT_TRACE1(( " FD number %ld is the maximum\n",
+ fd_select ));
+ FT_TRACE1(( " integer fitting into %d byte%s\n",
+ cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" ));
+ }
+ else
+ {
+ FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+ glyph_index ));
+ FT_TRACE0(( " FD number %ld is larger\n",
+ fd_select ));
+ FT_TRACE0(( " than number of dictionaries (%d)\n",
+ cid->num_dicts ));
+ }
+
+ error = FT_THROW( Invalid_Offset );
+ goto Exit;
+ }
+ else if ( off2 > stream->size )
+ {
+ FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+ glyph_index ));
+ FT_TRACE0(( " end of the glyph data\n" ));
+ FT_TRACE0(( " is beyond the data stream\n" ));
+
+ error = FT_THROW( Invalid_Offset );
+ goto Exit;
+ }
+ else if ( off1 > off2 )
+ {
+ FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+ glyph_index ));
+ FT_TRACE0(( " the end position of glyph data\n" ));
+ FT_TRACE0(( " is set before the start position\n" ));
+
+ error = FT_THROW( Invalid_Offset );
+ }
+
+ Exit:
+ if ( need_frame_exit )
+ FT_FRAME_EXIT();
+
+ return error;
+ }
+
+
FT_CALLBACK_DEF( FT_Error )
cid_load_glyph( T1_Decoder decoder,
FT_UInt glyph_index )
@@ -97,34 +208,14 @@
else
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
-
- /* For ordinary fonts read the CID font dictionary index */
- /* and charstring offset from the CIDMap. */
{
- FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes;
FT_ULong off1, off2;
- if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset +
- glyph_index * entry_len ) ||
- FT_FRAME_ENTER( 2 * entry_len ) )
- goto Exit;
-
- p = (FT_Byte*)stream->cursor;
- fd_select = cid_get_offset( &p, cid->fd_bytes );
- off1 = cid_get_offset( &p, cid->gd_bytes );
- p += cid->fd_bytes;
- off2 = cid_get_offset( &p, cid->gd_bytes );
- FT_FRAME_EXIT();
-
- if ( fd_select >= cid->num_dicts ||
- off2 > stream->size ||
- off1 > off2 )
- {
- FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" ));
- error = FT_THROW( Invalid_Offset );
+ error = cid_compute_fd_and_offsets( face, glyph_index,
+ &fd_select, &off1, &off2 );
+ if ( error )
goto Exit;
- }
glyph_length = off2 - off1;
@@ -161,7 +252,9 @@
cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0;
if ( cs_offset > glyph_length )
{
- FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" ));
+ FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, "
+ "offset to the charstring is beyond glyph length\n",
+ glyph_index ));
error = FT_THROW( Invalid_Offset );
goto Exit;
}
diff --git a/thirdparty/freetype/src/cid/cidgload.h b/thirdparty/freetype/src/cid/cidgload.h
index 97954d418f..edd6229234 100644
--- a/thirdparty/freetype/src/cid/cidgload.h
+++ b/thirdparty/freetype/src/cid/cidgload.h
@@ -42,6 +42,14 @@ FT_BEGIN_HEADER
FT_Int32 load_flags );
+ FT_LOCAL( FT_Error )
+ cid_compute_fd_and_offsets( CID_Face face,
+ FT_UInt glyph_index,
+ FT_ULong* fd_select_p,
+ FT_ULong* off1_p,
+ FT_ULong* off2_p );
+
+
FT_END_HEADER
#endif /* CIDGLOAD_H_ */
diff --git a/thirdparty/freetype/src/cid/cidload.c b/thirdparty/freetype/src/cid/cidload.c
index 26daa5da7f..a7da8ea39d 100644
--- a/thirdparty/freetype/src/cid/cidload.c
+++ b/thirdparty/freetype/src/cid/cidload.c
@@ -155,23 +155,24 @@
FT_CALLBACK_DEF( void )
- cid_parse_font_matrix( CID_Face face,
- CID_Parser* parser )
+ cid_parse_font_matrix( FT_Face face, /* CID_Face */
+ void* parser_ )
{
+ CID_Face cidface = (CID_Face)face;
+ CID_Parser* parser = (CID_Parser*)parser_;
CID_FaceDict dict;
- FT_Face root = (FT_Face)&face->root;
FT_Fixed temp[6];
FT_Fixed temp_scale;
- if ( parser->num_dict < face->cid.num_dicts )
+ if ( parser->num_dict < cidface->cid.num_dicts )
{
FT_Matrix* matrix;
FT_Vector* offset;
FT_Int result;
- dict = face->cid.font_dicts + parser->num_dict;
+ dict = cidface->cid.font_dicts + parser->num_dict;
matrix = &dict->font_matrix;
offset = &dict->font_offset;
@@ -204,7 +205,7 @@
if ( temp_scale != 0x10000L )
{
/* set units per EM based on FontMatrix values */
- root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
+ face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
temp[0] = FT_DivFix( temp[0], temp_scale );
temp[1] = FT_DivFix( temp[1], temp_scale );
@@ -237,13 +238,15 @@
FT_CALLBACK_DEF( void )
- parse_fd_array( CID_Face face,
- CID_Parser* parser )
+ parse_fd_array( FT_Face face, /* CID_Face */
+ void* parser_ )
{
- CID_FaceInfo cid = &face->cid;
- FT_Memory memory = face->root.memory;
- FT_Stream stream = parser->stream;
- FT_Error error = FT_Err_Ok;
+ CID_Face cidface = (CID_Face)face;
+ CID_Parser* parser = (CID_Parser*)parser_;
+ CID_FaceInfo cid = &cidface->cid;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_Stream stream = parser->stream;
+ FT_Error error = FT_Err_Ok;
FT_Long num_dicts, max_dicts;
@@ -313,18 +316,20 @@
/* By mistake, `expansion_factor' appears both in PS_PrivateRec */
/* and CID_FaceDictRec (both are public header files and can't */
- /* changed). We simply copy the value. */
+ /* be thus changed). We simply copy the value. */
FT_CALLBACK_DEF( void )
- parse_expansion_factor( CID_Face face,
- CID_Parser* parser )
+ parse_expansion_factor( FT_Face face, /* CID_Face */
+ void* parser_ )
{
+ CID_Face cidface = (CID_Face)face;
+ CID_Parser* parser = (CID_Parser*)parser_;
CID_FaceDict dict;
- if ( parser->num_dict < face->cid.num_dicts )
+ if ( parser->num_dict < cidface->cid.num_dicts )
{
- dict = face->cid.font_dicts + parser->num_dict;
+ dict = cidface->cid.font_dicts + parser->num_dict;
dict->expansion_factor = cid_parser_to_fixed( parser, 0 );
dict->private_dict.expansion_factor = dict->expansion_factor;
@@ -341,11 +346,15 @@
/* to catch it for producing better trace output. */
FT_CALLBACK_DEF( void )
- parse_font_name( CID_Face face,
- CID_Parser* parser )
+ parse_font_name( FT_Face face, /* CID_Face */
+ void* parser_ )
{
#ifdef FT_DEBUG_LEVEL_TRACE
- if ( parser->num_dict < face->cid.num_dicts )
+ CID_Face cidface = (CID_Face)face;
+ CID_Parser* parser = (CID_Parser*)parser_;
+
+
+ if ( parser->num_dict < cidface->cid.num_dicts )
{
T1_TokenRec token;
FT_UInt len;
@@ -361,7 +370,7 @@
}
#else
FT_UNUSED( face );
- FT_UNUSED( parser );
+ FT_UNUSED( parser_ );
#endif
return;
diff --git a/thirdparty/freetype/src/cid/cidobjs.c b/thirdparty/freetype/src/cid/cidobjs.c
index 06b2139a93..f698a41928 100644
--- a/thirdparty/freetype/src/cid/cidobjs.c
+++ b/thirdparty/freetype/src/cid/cidobjs.c
@@ -69,8 +69,7 @@
FT_Module module;
- module = FT_Get_Module( slot->face->driver->root.library,
- "pshinter" );
+ module = FT_Get_Module( slot->library, "pshinter" );
if ( module )
{
T1_Hints_Funcs funcs;
@@ -268,7 +267,8 @@
*
* @Input:
* stream ::
- * The source font stream.
+ * Dummy argument for compatibility with the `FT_Face_InitFunc` API.
+ * Ignored. The stream should be passed through `face->root.stream`.
*
* face_index ::
* The index of the font face in the resource.
@@ -375,6 +375,14 @@
if ( info->is_fixed_pitch )
cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+ /*
+ * For the sfnt-wrapped CID fonts for MacOS, currently,
+ * its `cmap' tables are ignored, and the content in
+ * its `CID ' table is treated the same as naked CID-keyed
+ * font. See ft_lookup_PS_in_sfnt_stream().
+ */
+ cidface->face_flags |= FT_FACE_FLAG_CID_KEYED;
+
/* XXX: TODO: add kerning with .afm support */
/* get style name -- be careful, some broken fonts only */
diff --git a/thirdparty/freetype/src/cid/cidparse.c b/thirdparty/freetype/src/cid/cidparse.c
index 16889db9b6..171a886215 100644
--- a/thirdparty/freetype/src/cid/cidparse.c
+++ b/thirdparty/freetype/src/cid/cidparse.c
@@ -214,18 +214,24 @@
cur <= limit - STARTDATA_LEN &&
ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 )
{
- if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 )
- {
- FT_Long tmp = ft_strtol( (const char *)arg2, NULL, 10 );
+ T1_TokenRec type_token;
+ FT_Long binary_length;
- if ( tmp < 0 )
+ parser->root.cursor = arg1;
+ cid_parser_to_token( parser, &type_token );
+ if ( type_token.limit - type_token.start == 5 &&
+ ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 )
+ {
+ parser->root.cursor = arg2;
+ binary_length = cid_parser_to_int( parser );
+ if ( binary_length < 0 )
{
FT_ERROR(( "cid_parser_new: invalid length of hex data\n" ));
error = FT_THROW( Invalid_File_Format );
}
else
- parser->binary_length = (FT_ULong)tmp;
+ parser->binary_length = (FT_ULong)binary_length;
}
goto Exit;
diff --git a/thirdparty/freetype/src/cid/cidriver.c b/thirdparty/freetype/src/cid/cidriver.c
index f7499237d7..99e7b11839 100644
--- a/thirdparty/freetype/src/cid/cidriver.c
+++ b/thirdparty/freetype/src/cid/cidriver.c
@@ -48,10 +48,11 @@
*
*/
- static const char*
- cid_get_postscript_name( CID_Face face )
+ FT_CALLBACK_DEF( const char* )
+ cid_get_postscript_name( FT_Face face ) /* CID_Face */
{
- const char* result = face->cid.cid_font_name;
+ CID_Face cidface = (CID_Face)face;
+ const char* result = cidface->cid.cid_font_name;
if ( result && result[0] == '/' )
@@ -72,34 +73,36 @@
*
*/
- static FT_Error
- cid_ps_get_font_info( FT_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cid_ps_get_font_info( FT_Face face, /* CID_Face */
PS_FontInfoRec* afont_info )
{
- *afont_info = ((CID_Face)face)->cid.font_info;
+ *afont_info = ( (CID_Face)face )->cid.font_info;
return FT_Err_Ok;
}
- static FT_Error
- cid_ps_get_font_extra( FT_Face face,
- PS_FontExtraRec* afont_extra )
+
+ FT_CALLBACK_DEF( FT_Error )
+ cid_ps_get_font_extra( FT_Face face, /* CID_Face */
+ PS_FontExtraRec* afont_extra )
{
- *afont_extra = ((CID_Face)face)->font_extra;
+ *afont_extra = ( (CID_Face)face )->font_extra;
return FT_Err_Ok;
}
+
static const FT_Service_PsInfoRec cid_service_ps_info =
{
- (PS_GetFontInfoFunc) cid_ps_get_font_info, /* ps_get_font_info */
- (PS_GetFontExtraFunc) cid_ps_get_font_extra, /* ps_get_font_extra */
+ cid_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */
+ cid_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */
/* unsupported with CID fonts */
- (PS_HasGlyphNamesFunc) NULL, /* ps_has_glyph_names */
+ NULL, /* PS_HasGlyphNamesFunc ps_has_glyph_names */
/* unsupported */
- (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */
+ NULL, /* PS_GetFontPrivateFunc ps_get_font_private */
/* not implemented */
- (PS_GetFontValueFunc) NULL /* ps_get_font_value */
+ NULL /* PS_GetFontValueFunc ps_get_font_value */
};
@@ -107,13 +110,14 @@
* CID INFO SERVICE
*
*/
- static FT_Error
- cid_get_ros( CID_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cid_get_ros( FT_Face face, /* CID_Face */
const char* *registry,
const char* *ordering,
FT_Int *supplement )
{
- CID_FaceInfo cid = &face->cid;
+ CID_Face cidface = (CID_Face)face;
+ CID_FaceInfo cid = &cidface->cid;
if ( registry )
@@ -129,32 +133,48 @@
}
- static FT_Error
- cid_get_is_cid( CID_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cid_get_is_cid( FT_Face face, /* CID_Face */
FT_Bool *is_cid )
{
FT_Error error = FT_Err_Ok;
FT_UNUSED( face );
+ /*
+ * XXX: If the ROS is Adobe-Identity-H or -V,
+ * the font has no reliable information about
+ * its glyph collection. Should we not set
+ * *is_cid in such cases?
+ */
if ( is_cid )
- *is_cid = 1; /* cid driver is only used for CID keyed fonts */
+ *is_cid = 1;
return error;
}
- static FT_Error
- cid_get_cid_from_glyph_index( CID_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cid_get_cid_from_glyph_index( FT_Face face, /* CID_Face */
FT_UInt glyph_index,
FT_UInt *cid )
{
- FT_Error error = FT_Err_Ok;
- FT_UNUSED( face );
-
-
- if ( cid )
- *cid = glyph_index; /* identity mapping */
+ FT_Error error = FT_Err_Ok;
+ CID_Face cidface = (CID_Face)face;
+
+
+ /*
+ * Currently, FreeType does not support incrementally-defined, CID-keyed
+ * fonts that store the glyph description data in a `/GlyphDirectory`
+ * array or dictionary. Fonts loaded by the incremental loading feature
+ * are thus not handled here.
+ */
+ error = cid_compute_fd_and_offsets( cidface, glyph_index,
+ NULL, NULL, NULL );
+ if ( error )
+ *cid = 0;
+ else
+ *cid = glyph_index;
return error;
}
@@ -162,12 +182,12 @@
static const FT_Service_CIDRec cid_service_cid_info =
{
- (FT_CID_GetRegistryOrderingSupplementFunc)
- cid_get_ros, /* get_ros */
- (FT_CID_GetIsInternallyCIDKeyedFunc)
- cid_get_is_cid, /* get_is_cid */
- (FT_CID_GetCIDFromGlyphIndexFunc)
- cid_get_cid_from_glyph_index /* get_cid_from_glyph_index */
+ cid_get_ros,
+ /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */
+ cid_get_is_cid,
+ /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */
+ cid_get_cid_from_glyph_index
+ /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */
};
@@ -179,9 +199,9 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
cid_service_properties,
- (FT_Properties_SetFunc)ps_property_set, /* set_property */
- (FT_Properties_GetFunc)ps_property_get ) /* get_property */
-
+ ps_property_set, /* FT_Properties_SetFunc set_property */
+ ps_property_get /* FT_Properties_GetFunc get_property */
+ )
/*
* SERVICE LIST
@@ -209,7 +229,6 @@
}
-
FT_CALLBACK_TABLE_DEF
const FT_Driver_ClassRec t1cid_driver_class =
{
diff --git a/thirdparty/freetype/src/gxvalid/gxvfgen.c b/thirdparty/freetype/src/gxvalid/gxvfgen.c
index 1153542286..cf98bb36c3 100644
--- a/thirdparty/freetype/src/gxvalid/gxvfgen.c
+++ b/thirdparty/freetype/src/gxvalid/gxvfgen.c
@@ -97,7 +97,8 @@
#define EMPTYFEAT {0, 0, {NULL}}
- static GX_Feature_RegistryRec featreg_table[] = {
+ static GX_Feature_RegistryRec featreg_table[] =
+ {
{ /* 0 */
"All Typographic Features",
0,
diff --git a/thirdparty/freetype/src/gzip/ftgzip.c b/thirdparty/freetype/src/gzip/ftgzip.c
index 48da6ff9c7..ca6a2aabe6 100644
--- a/thirdparty/freetype/src/gzip/ftgzip.c
+++ b/thirdparty/freetype/src/gzip/ftgzip.c
@@ -70,10 +70,9 @@
/* so that configuration with `FT_CONFIG_OPTION_SYSTEM_ZLIB' might */
/* include the wrong `zconf.h' file, leading to errors. */
-#if defined( __GNUC__ ) || defined( __clang__ )
#define ZEXPORT
-#define ZEXTERN static
-#endif
+ /* prevent zlib functions from being visible outside their object files */
+#define ZEXTERN static
#define HAVE_MEMCPY 1
#define Z_SOLO 1
diff --git a/thirdparty/freetype/src/gzip/infback.c b/thirdparty/freetype/src/gzip/infback.c
deleted file mode 100644
index 264c14e0df..0000000000
--- a/thirdparty/freetype/src/gzip/infback.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/* infback.c -- inflate using a call-back interface
- * Copyright (C) 1995-2022 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/*
- This code is largely copied from inflate.c. Normally either infback.o or
- inflate.o would be linked into an application--not both. The interface
- with inffast.c is retained so that optimized assembler-coded versions of
- inflate_fast() can be used with either inflate.c or infback.c.
- */
-
-#include "zutil.h"
-#include "inftrees.h"
-#include "inflate.h"
-#include "inffast.h"
-
-/* function prototypes */
-local void fixedtables OF((struct inflate_state FAR *state));
-
-/*
- strm provides memory allocation functions in zalloc and zfree, or
- Z_NULL to use the library memory allocation functions.
-
- windowBits is in the range 8..15, and window is a user-supplied
- window and output buffer that is 2**windowBits bytes.
- */
-int ZEXPORT inflateBackInit_(
- z_streamp strm,
- int windowBits,
- unsigned char FAR *window,
- const char *version,
- int stream_size)
-{
- struct inflate_state FAR *state;
-
- if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
- stream_size != (int)(sizeof(z_stream)))
- return Z_VERSION_ERROR;
- if (strm == Z_NULL || window == Z_NULL ||
- windowBits < 8 || windowBits > 15)
- return Z_STREAM_ERROR;
- strm->msg = Z_NULL; /* in case we return an error */
- if (strm->zalloc == (alloc_func)0) {
-#ifdef Z_SOLO
- return Z_STREAM_ERROR;
-#else
- strm->zalloc = zcalloc;
- strm->opaque = (voidpf)0;
-#endif
- }
- if (strm->zfree == (free_func)0)
-#ifdef Z_SOLO
- return Z_STREAM_ERROR;
-#else
- strm->zfree = zcfree;
-#endif
- state = (struct inflate_state FAR *)ZALLOC(strm, 1,
- sizeof(struct inflate_state));
- if (state == Z_NULL) return Z_MEM_ERROR;
- Tracev((stderr, "inflate: allocated\n"));
- strm->state = (struct internal_state FAR *)state;
- state->dmax = 32768U;
- state->wbits = (uInt)windowBits;
- state->wsize = 1U << windowBits;
- state->window = window;
- state->wnext = 0;
- state->whave = 0;
- state->sane = 1;
- return Z_OK;
-}
-
-/*
- Return state with length and distance decoding tables and index sizes set to
- fixed code decoding. Normally this returns fixed tables from inffixed.h.
- If BUILDFIXED is defined, then instead this routine builds the tables the
- first time it's called, and returns those tables the first time and
- thereafter. This reduces the size of the code by about 2K bytes, in
- exchange for a little execution time. However, BUILDFIXED should not be
- used for threaded applications, since the rewriting of the tables and virgin
- may not be thread-safe.
- */
-local void fixedtables(
- struct inflate_state FAR *state)
-{
-#ifdef BUILDFIXED
- static int virgin = 1;
- static code *lenfix, *distfix;
- static code fixed[544];
-
- /* build fixed huffman tables if first call (may not be thread safe) */
- if (virgin) {
- unsigned sym, bits;
- static code *next;
-
- /* literal/length table */
- sym = 0;
- while (sym < 144) state->lens[sym++] = 8;
- while (sym < 256) state->lens[sym++] = 9;
- while (sym < 280) state->lens[sym++] = 7;
- while (sym < 288) state->lens[sym++] = 8;
- next = fixed;
- lenfix = next;
- bits = 9;
- inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
-
- /* distance table */
- sym = 0;
- while (sym < 32) state->lens[sym++] = 5;
- distfix = next;
- bits = 5;
- inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
-
- /* do this just once */
- virgin = 0;
- }
-#else /* !BUILDFIXED */
-# include "inffixed.h"
-#endif /* BUILDFIXED */
- state->lencode = lenfix;
- state->lenbits = 9;
- state->distcode = distfix;
- state->distbits = 5;
-}
-
-/* Macros for inflateBack(): */
-
-/* Load returned state from inflate_fast() */
-#define LOAD() \
- do { \
- put = strm->next_out; \
- left = strm->avail_out; \
- next = strm->next_in; \
- have = strm->avail_in; \
- hold = state->hold; \
- bits = state->bits; \
- } while (0)
-
-/* Set state from registers for inflate_fast() */
-#define RESTORE() \
- do { \
- strm->next_out = put; \
- strm->avail_out = left; \
- strm->next_in = next; \
- strm->avail_in = have; \
- state->hold = hold; \
- state->bits = bits; \
- } while (0)
-
-/* Clear the input bit accumulator */
-#define INITBITS() \
- do { \
- hold = 0; \
- bits = 0; \
- } while (0)
-
-/* Assure that some input is available. If input is requested, but denied,
- then return a Z_BUF_ERROR from inflateBack(). */
-#define PULL() \
- do { \
- if (have == 0) { \
- have = in(in_desc, &next); \
- if (have == 0) { \
- next = Z_NULL; \
- ret = Z_BUF_ERROR; \
- goto inf_leave; \
- } \
- } \
- } while (0)
-
-/* Get a byte of input into the bit accumulator, or return from inflateBack()
- with an error if there is no input available. */
-#define PULLBYTE() \
- do { \
- PULL(); \
- have--; \
- hold += (unsigned long)(*next++) << bits; \
- bits += 8; \
- } while (0)
-
-/* Assure that there are at least n bits in the bit accumulator. If there is
- not enough available input to do that, then return from inflateBack() with
- an error. */
-#define NEEDBITS(n) \
- do { \
- while (bits < (unsigned)(n)) \
- PULLBYTE(); \
- } while (0)
-
-/* Return the low n bits of the bit accumulator (n < 16) */
-#define BITS(n) \
- ((unsigned)hold & ((1U << (n)) - 1))
-
-/* Remove n bits from the bit accumulator */
-#define DROPBITS(n) \
- do { \
- hold >>= (n); \
- bits -= (unsigned)(n); \
- } while (0)
-
-/* Remove zero to seven bits as needed to go to a byte boundary */
-#define BYTEBITS() \
- do { \
- hold >>= bits & 7; \
- bits -= bits & 7; \
- } while (0)
-
-/* Assure that some output space is available, by writing out the window
- if it's full. If the write fails, return from inflateBack() with a
- Z_BUF_ERROR. */
-#define ROOM() \
- do { \
- if (left == 0) { \
- put = state->window; \
- left = state->wsize; \
- state->whave = left; \
- if (out(out_desc, put, left)) { \
- ret = Z_BUF_ERROR; \
- goto inf_leave; \
- } \
- } \
- } while (0)
-
-/*
- strm provides the memory allocation functions and window buffer on input,
- and provides information on the unused input on return. For Z_DATA_ERROR
- returns, strm will also provide an error message.
-
- in() and out() are the call-back input and output functions. When
- inflateBack() needs more input, it calls in(). When inflateBack() has
- filled the window with output, or when it completes with data in the
- window, it calls out() to write out the data. The application must not
- change the provided input until in() is called again or inflateBack()
- returns. The application must not change the window/output buffer until
- inflateBack() returns.
-
- in() and out() are called with a descriptor parameter provided in the
- inflateBack() call. This parameter can be a structure that provides the
- information required to do the read or write, as well as accumulated
- information on the input and output such as totals and check values.
-
- in() should return zero on failure. out() should return non-zero on
- failure. If either in() or out() fails, than inflateBack() returns a
- Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
- was in() or out() that caused in the error. Otherwise, inflateBack()
- returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
- error, or Z_MEM_ERROR if it could not allocate memory for the state.
- inflateBack() can also return Z_STREAM_ERROR if the input parameters
- are not correct, i.e. strm is Z_NULL or the state was not initialized.
- */
-int ZEXPORT inflateBack(
- z_streamp strm,
- in_func in,
- void FAR *in_desc,
- out_func out,
- void FAR *out_desc)
-{
- struct inflate_state FAR *state;
- z_const unsigned char FAR *next; /* next input */
- unsigned char FAR *put; /* next output */
- unsigned have, left; /* available input and output */
- unsigned long hold; /* bit buffer */
- unsigned bits; /* bits in bit buffer */
- unsigned copy; /* number of stored or match bytes to copy */
- unsigned char FAR *from; /* where to copy match bytes from */
- code here; /* current decoding table entry */
- code last; /* parent table entry */
- unsigned len; /* length to copy for repeats, bits to drop */
- int ret; /* return code */
- static const unsigned short order[19] = /* permutation of code lengths */
- {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
- /* Check that the strm exists and that the state was initialized */
- if (strm == Z_NULL || strm->state == Z_NULL)
- return Z_STREAM_ERROR;
- state = (struct inflate_state FAR *)strm->state;
-
- /* Reset the state */
- strm->msg = Z_NULL;
- state->mode = TYPE;
- state->last = 0;
- state->whave = 0;
- next = strm->next_in;
- have = next != Z_NULL ? strm->avail_in : 0;
- hold = 0;
- bits = 0;
- put = state->window;
- left = state->wsize;
-
- /* Inflate until end of block marked as last */
- for (;;)
- switch (state->mode) {
- case TYPE:
- /* determine and dispatch block type */
- if (state->last) {
- BYTEBITS();
- state->mode = DONE;
- break;
- }
- NEEDBITS(3);
- state->last = BITS(1);
- DROPBITS(1);
- switch (BITS(2)) {
- case 0: /* stored block */
- Tracev((stderr, "inflate: stored block%s\n",
- state->last ? " (last)" : ""));
- state->mode = STORED;
- break;
- case 1: /* fixed block */
- fixedtables(state);
- Tracev((stderr, "inflate: fixed codes block%s\n",
- state->last ? " (last)" : ""));
- state->mode = LEN; /* decode codes */
- break;
- case 2: /* dynamic block */
- Tracev((stderr, "inflate: dynamic codes block%s\n",
- state->last ? " (last)" : ""));
- state->mode = TABLE;
- break;
- case 3:
- strm->msg = (char *)"invalid block type";
- state->mode = BAD;
- }
- DROPBITS(2);
- break;
-
- case STORED:
- /* get and verify stored block length */
- BYTEBITS(); /* go to byte boundary */
- NEEDBITS(32);
- if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
- strm->msg = (char *)"invalid stored block lengths";
- state->mode = BAD;
- break;
- }
- state->length = (unsigned)hold & 0xffff;
- Tracev((stderr, "inflate: stored length %u\n",
- state->length));
- INITBITS();
-
- /* copy stored block from input to output */
- while (state->length != 0) {
- copy = state->length;
- PULL();
- ROOM();
- if (copy > have) copy = have;
- if (copy > left) copy = left;
- zmemcpy(put, next, copy);
- have -= copy;
- next += copy;
- left -= copy;
- put += copy;
- state->length -= copy;
- }
- Tracev((stderr, "inflate: stored end\n"));
- state->mode = TYPE;
- break;
-
- case TABLE:
- /* get dynamic table entries descriptor */
- NEEDBITS(14);
- state->nlen = BITS(5) + 257;
- DROPBITS(5);
- state->ndist = BITS(5) + 1;
- DROPBITS(5);
- state->ncode = BITS(4) + 4;
- DROPBITS(4);
-#ifndef PKZIP_BUG_WORKAROUND
- if (state->nlen > 286 || state->ndist > 30) {
- strm->msg = (char *)"too many length or distance symbols";
- state->mode = BAD;
- break;
- }
-#endif
- Tracev((stderr, "inflate: table sizes ok\n"));
-
- /* get code length code lengths (not a typo) */
- state->have = 0;
- while (state->have < state->ncode) {
- NEEDBITS(3);
- state->lens[order[state->have++]] = (unsigned short)BITS(3);
- DROPBITS(3);
- }
- while (state->have < 19)
- state->lens[order[state->have++]] = 0;
- state->next = state->codes;
- state->lencode = (code const FAR *)(state->next);
- state->lenbits = 7;
- ret = inflate_table(CODES, state->lens, 19, &(state->next),
- &(state->lenbits), state->work);
- if (ret) {
- strm->msg = (char *)"invalid code lengths set";
- state->mode = BAD;
- break;
- }
- Tracev((stderr, "inflate: code lengths ok\n"));
-
- /* get length and distance code code lengths */
- state->have = 0;
- while (state->have < state->nlen + state->ndist) {
- for (;;) {
- here = state->lencode[BITS(state->lenbits)];
- if ((unsigned)(here.bits) <= bits) break;
- PULLBYTE();
- }
- if (here.val < 16) {
- DROPBITS(here.bits);
- state->lens[state->have++] = here.val;
- }
- else {
- if (here.val == 16) {
- NEEDBITS(here.bits + 2);
- DROPBITS(here.bits);
- if (state->have == 0) {
- strm->msg = (char *)"invalid bit length repeat";
- state->mode = BAD;
- break;
- }
- len = (unsigned)(state->lens[state->have - 1]);
- copy = 3 + BITS(2);
- DROPBITS(2);
- }
- else if (here.val == 17) {
- NEEDBITS(here.bits + 3);
- DROPBITS(here.bits);
- len = 0;
- copy = 3 + BITS(3);
- DROPBITS(3);
- }
- else {
- NEEDBITS(here.bits + 7);
- DROPBITS(here.bits);
- len = 0;
- copy = 11 + BITS(7);
- DROPBITS(7);
- }
- if (state->have + copy > state->nlen + state->ndist) {
- strm->msg = (char *)"invalid bit length repeat";
- state->mode = BAD;
- break;
- }
- while (copy--)
- state->lens[state->have++] = (unsigned short)len;
- }
- }
-
- /* handle error breaks in while */
- if (state->mode == BAD) break;
-
- /* check for end-of-block code (better have one) */
- if (state->lens[256] == 0) {
- strm->msg = (char *)"invalid code -- missing end-of-block";
- state->mode = BAD;
- break;
- }
-
- /* build code tables -- note: do not change the lenbits or distbits
- values here (9 and 6) without reading the comments in inftrees.h
- concerning the ENOUGH constants, which depend on those values */
- state->next = state->codes;
- state->lencode = (code const FAR *)(state->next);
- state->lenbits = 9;
- ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
- &(state->lenbits), state->work);
- if (ret) {
- strm->msg = (char *)"invalid literal/lengths set";
- state->mode = BAD;
- break;
- }
- state->distcode = (code const FAR *)(state->next);
- state->distbits = 6;
- ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
- &(state->next), &(state->distbits), state->work);
- if (ret) {
- strm->msg = (char *)"invalid distances set";
- state->mode = BAD;
- break;
- }
- Tracev((stderr, "inflate: codes ok\n"));
- state->mode = LEN;
- /* fallthrough */
-
- case LEN:
- /* use inflate_fast() if we have enough input and output */
- if (have >= 6 && left >= 258) {
- RESTORE();
- if (state->whave < state->wsize)
- state->whave = state->wsize - left;
- inflate_fast(strm, state->wsize);
- LOAD();
- break;
- }
-
- /* get a literal, length, or end-of-block code */
- for (;;) {
- here = state->lencode[BITS(state->lenbits)];
- if ((unsigned)(here.bits) <= bits) break;
- PULLBYTE();
- }
- if (here.op && (here.op & 0xf0) == 0) {
- last = here;
- for (;;) {
- here = state->lencode[last.val +
- (BITS(last.bits + last.op) >> last.bits)];
- if ((unsigned)(last.bits + here.bits) <= bits) break;
- PULLBYTE();
- }
- DROPBITS(last.bits);
- }
- DROPBITS(here.bits);
- state->length = (unsigned)here.val;
-
- /* process literal */
- if (here.op == 0) {
- Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
- "inflate: literal '%c'\n" :
- "inflate: literal 0x%02x\n", here.val));
- ROOM();
- *put++ = (unsigned char)(state->length);
- left--;
- state->mode = LEN;
- break;
- }
-
- /* process end of block */
- if (here.op & 32) {
- Tracevv((stderr, "inflate: end of block\n"));
- state->mode = TYPE;
- break;
- }
-
- /* invalid code */
- if (here.op & 64) {
- strm->msg = (char *)"invalid literal/length code";
- state->mode = BAD;
- break;
- }
-
- /* length code -- get extra bits, if any */
- state->extra = (unsigned)(here.op) & 15;
- if (state->extra != 0) {
- NEEDBITS(state->extra);
- state->length += BITS(state->extra);
- DROPBITS(state->extra);
- }
- Tracevv((stderr, "inflate: length %u\n", state->length));
-
- /* get distance code */
- for (;;) {
- here = state->distcode[BITS(state->distbits)];
- if ((unsigned)(here.bits) <= bits) break;
- PULLBYTE();
- }
- if ((here.op & 0xf0) == 0) {
- last = here;
- for (;;) {
- here = state->distcode[last.val +
- (BITS(last.bits + last.op) >> last.bits)];
- if ((unsigned)(last.bits + here.bits) <= bits) break;
- PULLBYTE();
- }
- DROPBITS(last.bits);
- }
- DROPBITS(here.bits);
- if (here.op & 64) {
- strm->msg = (char *)"invalid distance code";
- state->mode = BAD;
- break;
- }
- state->offset = (unsigned)here.val;
-
- /* get distance extra bits, if any */
- state->extra = (unsigned)(here.op) & 15;
- if (state->extra != 0) {
- NEEDBITS(state->extra);
- state->offset += BITS(state->extra);
- DROPBITS(state->extra);
- }
- if (state->offset > state->wsize - (state->whave < state->wsize ?
- left : 0)) {
- strm->msg = (char *)"invalid distance too far back";
- state->mode = BAD;
- break;
- }
- Tracevv((stderr, "inflate: distance %u\n", state->offset));
-
- /* copy match from window to output */
- do {
- ROOM();
- copy = state->wsize - state->offset;
- if (copy < left) {
- from = put + copy;
- copy = left - copy;
- }
- else {
- from = put - state->offset;
- copy = left;
- }
- if (copy > state->length) copy = state->length;
- state->length -= copy;
- left -= copy;
- do {
- *put++ = *from++;
- } while (--copy);
- } while (state->length != 0);
- break;
-
- case DONE:
- /* inflate stream terminated properly */
- ret = Z_STREAM_END;
- goto inf_leave;
-
- case BAD:
- ret = Z_DATA_ERROR;
- goto inf_leave;
-
- default:
- /* can't happen, but makes compilers happy */
- ret = Z_STREAM_ERROR;
- goto inf_leave;
- }
-
- /* Write leftover output and return unused input */
- inf_leave:
- if (left < state->wsize) {
- if (out(out_desc, state->window, state->wsize - left) &&
- ret == Z_STREAM_END)
- ret = Z_BUF_ERROR;
- }
- strm->next_in = next;
- strm->avail_in = have;
- return ret;
-}
-
-int ZEXPORT inflateBackEnd(
- z_streamp strm)
-{
- if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
- return Z_STREAM_ERROR;
- ZFREE(strm, strm->state);
- strm->state = Z_NULL;
- Tracev((stderr, "inflate: end\n"));
- return Z_OK;
-}
diff --git a/thirdparty/freetype/src/pcf/pcfdrivr.c b/thirdparty/freetype/src/pcf/pcfdrivr.c
index bfa6eacca4..f1dba02404 100644
--- a/thirdparty/freetype/src/pcf/pcfdrivr.c
+++ b/thirdparty/freetype/src/pcf/pcfdrivr.c
@@ -75,36 +75,36 @@ THE SOFTWARE.
FT_CALLBACK_DEF( FT_Error )
- pcf_cmap_init( FT_CMap pcfcmap, /* PCF_CMap */
+ pcf_cmap_init( FT_CMap cmap, /* PCF_CMap */
FT_Pointer init_data )
{
- PCF_CMap cmap = (PCF_CMap)pcfcmap;
- PCF_Face face = (PCF_Face)FT_CMAP_FACE( pcfcmap );
+ PCF_CMap pcfcmap = (PCF_CMap)cmap;
+ PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap );
FT_UNUSED( init_data );
- cmap->enc = &face->enc;
+ pcfcmap->enc = &face->enc;
return FT_Err_Ok;
}
FT_CALLBACK_DEF( void )
- pcf_cmap_done( FT_CMap pcfcmap ) /* PCF_CMap */
+ pcf_cmap_done( FT_CMap cmap ) /* PCF_CMap */
{
- PCF_CMap cmap = (PCF_CMap)pcfcmap;
+ PCF_CMap pcfcmap = (PCF_CMap)cmap;
- cmap->enc = NULL;
+ pcfcmap->enc = NULL;
}
FT_CALLBACK_DEF( FT_UInt )
- pcf_cmap_char_index( FT_CMap pcfcmap, /* PCF_CMap */
+ pcf_cmap_char_index( FT_CMap cmap, /* PCF_CMap */
FT_UInt32 charcode )
{
- PCF_Enc enc = ( (PCF_CMap)pcfcmap )->enc;
+ PCF_Enc enc = ( (PCF_CMap)cmap )->enc;
FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow;
FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol;
@@ -121,10 +121,10 @@ THE SOFTWARE.
FT_CALLBACK_DEF( FT_UInt )
- pcf_cmap_char_next( FT_CMap pcfcmap, /* PCF_CMap */
+ pcf_cmap_char_next( FT_CMap cmap, /* PCF_CMap */
FT_UInt32 *acharcode )
{
- PCF_Enc enc = ( (PCF_CMap)pcfcmap )->enc;
+ PCF_Enc enc = ( (PCF_CMap)cmap )->enc;
FT_UInt32 charcode = *acharcode + 1;
FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow;
@@ -170,9 +170,9 @@ THE SOFTWARE.
FT_CALLBACK_DEF( void )
- PCF_Face_Done( FT_Face pcfface ) /* PCF_Face */
+ PCF_Face_Done( FT_Face face ) /* PCF_Face */
{
- PCF_Face face = (PCF_Face)pcfface;
+ PCF_Face pcfface = (PCF_Face)face;
FT_Memory memory;
@@ -181,18 +181,18 @@ THE SOFTWARE.
memory = FT_FACE_MEMORY( face );
- FT_FREE( face->metrics );
- FT_FREE( face->enc.offset );
+ FT_FREE( pcfface->metrics );
+ FT_FREE( pcfface->enc.offset );
/* free properties */
- if ( face->properties )
+ if ( pcfface->properties )
{
FT_Int i;
- for ( i = 0; i < face->nprops; i++ )
+ for ( i = 0; i < pcfface->nprops; i++ )
{
- PCF_Property prop = &face->properties[i];
+ PCF_Property prop = &pcfface->properties[i];
if ( prop )
@@ -203,33 +203,33 @@ THE SOFTWARE.
}
}
- FT_FREE( face->properties );
+ FT_FREE( pcfface->properties );
}
- FT_FREE( face->toc.tables );
- FT_FREE( pcfface->family_name );
- FT_FREE( pcfface->style_name );
- FT_FREE( pcfface->available_sizes );
- FT_FREE( face->charset_encoding );
- FT_FREE( face->charset_registry );
+ FT_FREE( pcfface->toc.tables );
+ FT_FREE( face->family_name );
+ FT_FREE( face->style_name );
+ FT_FREE( face->available_sizes );
+ FT_FREE( pcfface->charset_encoding );
+ FT_FREE( pcfface->charset_registry );
/* close compressed stream if any */
- if ( pcfface->stream == &face->comp_stream )
+ if ( face->stream == &pcfface->comp_stream )
{
- FT_Stream_Close( &face->comp_stream );
- pcfface->stream = face->comp_source;
+ FT_Stream_Close( &pcfface->comp_stream );
+ face->stream = pcfface->comp_source;
}
}
FT_CALLBACK_DEF( FT_Error )
PCF_Face_Init( FT_Stream stream,
- FT_Face pcfface, /* PCF_Face */
+ FT_Face face, /* PCF_Face */
FT_Int face_index,
FT_Int num_params,
FT_Parameter* params )
{
- PCF_Face face = (PCF_Face)pcfface;
+ PCF_Face pcfface = (PCF_Face)face;
FT_Error error;
FT_UNUSED( num_params );
@@ -238,10 +238,10 @@ THE SOFTWARE.
FT_TRACE2(( "PCF driver\n" ));
- error = pcf_load_font( stream, face, face_index );
+ error = pcf_load_font( stream, pcfface, face_index );
if ( error )
{
- PCF_Face_Done( pcfface );
+ PCF_Face_Done( face );
#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \
defined( FT_CONFIG_OPTION_USE_LZW ) || \
@@ -254,7 +254,7 @@ THE SOFTWARE.
/* this didn't work, try gzip support! */
FT_TRACE2(( " ... try gzip stream\n" ));
- error2 = FT_Stream_OpenGzip( &face->comp_stream, stream );
+ error2 = FT_Stream_OpenGzip( &pcfface->comp_stream, stream );
if ( FT_ERR_EQ( error2, Unimplemented_Feature ) )
goto Fail;
@@ -270,7 +270,7 @@ THE SOFTWARE.
/* this didn't work, try LZW support! */
FT_TRACE2(( " ... try LZW stream\n" ));
- error3 = FT_Stream_OpenLZW( &face->comp_stream, stream );
+ error3 = FT_Stream_OpenLZW( &pcfface->comp_stream, stream );
if ( FT_ERR_EQ( error3, Unimplemented_Feature ) )
goto Fail;
@@ -286,7 +286,7 @@ THE SOFTWARE.
/* this didn't work, try Bzip2 support! */
FT_TRACE2(( " ... try Bzip2 stream\n" ));
- error4 = FT_Stream_OpenBzip2( &face->comp_stream, stream );
+ error4 = FT_Stream_OpenBzip2( &pcfface->comp_stream, stream );
if ( FT_ERR_EQ( error4, Unimplemented_Feature ) )
goto Fail;
@@ -297,12 +297,12 @@ THE SOFTWARE.
if ( error )
goto Fail;
- face->comp_source = stream;
- pcfface->stream = &face->comp_stream;
+ pcfface->comp_source = stream;
+ face->stream = &pcfface->comp_stream;
- stream = pcfface->stream;
+ stream = face->stream;
- error = pcf_load_font( stream, face, face_index );
+ error = pcf_load_font( stream, pcfface, face_index );
if ( error )
goto Fail;
@@ -326,14 +326,14 @@ THE SOFTWARE.
else if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
{
FT_ERROR(( "PCF_Face_Init: invalid face index\n" ));
- PCF_Face_Done( pcfface );
+ PCF_Face_Done( face );
return FT_THROW( Invalid_Argument );
}
/* set up charmap */
{
- FT_String *charset_registry = face->charset_registry;
- FT_String *charset_encoding = face->charset_encoding;
+ FT_String *charset_registry = pcfface->charset_registry;
+ FT_String *charset_encoding = pcfface->charset_encoding;
FT_Bool unicode_charmap = 0;
@@ -349,13 +349,13 @@ THE SOFTWARE.
( s[2] == 'o' || s[2] == 'O' ) )
{
s += 3;
- if ( !ft_strcmp( s, "10646" ) ||
- ( !ft_strcmp( s, "8859" ) &&
- !ft_strcmp( face->charset_encoding, "1" ) ) )
+ if ( !ft_strcmp( s, "10646" ) ||
+ ( !ft_strcmp( s, "8859" ) &&
+ !ft_strcmp( pcfface->charset_encoding, "1" ) ) )
unicode_charmap = 1;
/* another name for ASCII */
- else if ( !ft_strcmp( s, "646.1991" ) &&
- !ft_strcmp( face->charset_encoding, "IRV" ) )
+ else if ( !ft_strcmp( s, "646.1991" ) &&
+ !ft_strcmp( pcfface->charset_encoding, "IRV" ) )
unicode_charmap = 1;
}
}
@@ -364,7 +364,7 @@ THE SOFTWARE.
FT_CharMapRec charmap;
- charmap.face = FT_FACE( face );
+ charmap.face = face;
charmap.encoding = FT_ENCODING_NONE;
/* initial platform/encoding should indicate unset status? */
charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
@@ -386,7 +386,7 @@ THE SOFTWARE.
Fail:
FT_TRACE2(( " not a PCF file\n" ));
- PCF_Face_Done( pcfface );
+ PCF_Face_Done( face );
error = FT_THROW( Unknown_File_Format ); /* error */
goto Exit;
}
@@ -569,15 +569,16 @@ THE SOFTWARE.
*
*/
- static FT_Error
- pcf_get_bdf_property( PCF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ pcf_get_bdf_property( FT_Face face, /* PCF_Face */
const char* prop_name,
BDF_PropertyRec *aproperty )
{
+ PCF_Face pcfface = (PCF_Face)face;
PCF_Property prop;
- prop = pcf_find_property( face, prop_name );
+ prop = pcf_find_property( pcfface, prop_name );
if ( prop )
{
if ( prop->isString )
@@ -611,13 +612,16 @@ THE SOFTWARE.
}
- static FT_Error
- pcf_get_charset_id( PCF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ pcf_get_charset_id( FT_Face face, /* PCF_Face */
const char* *acharset_encoding,
const char* *acharset_registry )
{
- *acharset_encoding = face->charset_encoding;
- *acharset_registry = face->charset_registry;
+ PCF_Face pcfface = (PCF_Face)face;
+
+
+ *acharset_encoding = pcfface->charset_encoding;
+ *acharset_registry = pcfface->charset_registry;
return FT_Err_Ok;
}
@@ -634,7 +638,7 @@ THE SOFTWARE.
* PROPERTY SERVICE
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
pcf_property_set( FT_Module module, /* PCF_Driver */
const char* property_name,
const void* value,
@@ -695,10 +699,10 @@ THE SOFTWARE.
}
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
pcf_property_get( FT_Module module, /* PCF_Driver */
const char* property_name,
- const void* value )
+ void* value )
{
#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
diff --git a/thirdparty/freetype/src/pfr/pfrcmap.c b/thirdparty/freetype/src/pfr/pfrcmap.c
index 312a9ffe17..08fe41d54e 100644
--- a/thirdparty/freetype/src/pfr/pfrcmap.c
+++ b/thirdparty/freetype/src/pfr/pfrcmap.c
@@ -24,17 +24,18 @@
FT_CALLBACK_DEF( FT_Error )
- pfr_cmap_init( PFR_CMap cmap,
+ pfr_cmap_init( FT_CMap cmap, /* PFR_CMap */
FT_Pointer pointer )
{
- FT_Error error = FT_Err_Ok;
- PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap );
+ PFR_CMap pfrcmap = (PFR_CMap)cmap;
+ FT_Error error = FT_Err_Ok;
+ PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap );
FT_UNUSED( pointer );
- cmap->num_chars = face->phy_font.num_chars;
- cmap->chars = face->phy_font.chars;
+ pfrcmap->num_chars = face->phy_font.num_chars;
+ pfrcmap->chars = face->phy_font.chars;
/* just for safety, check that the character entries are correctly */
/* sorted in increasing character code order */
@@ -42,9 +43,9 @@
FT_UInt n;
- for ( n = 1; n < cmap->num_chars; n++ )
+ for ( n = 1; n < pfrcmap->num_chars; n++ )
{
- if ( cmap->chars[n - 1].char_code >= cmap->chars[n].char_code )
+ if ( pfrcmap->chars[n - 1].char_code >= pfrcmap->chars[n].char_code )
{
error = FT_THROW( Invalid_Table );
goto Exit;
@@ -58,26 +59,30 @@
FT_CALLBACK_DEF( void )
- pfr_cmap_done( PFR_CMap cmap )
+ pfr_cmap_done( FT_CMap cmap ) /* PFR_CMap */
{
- cmap->chars = NULL;
- cmap->num_chars = 0;
+ PFR_CMap pfrcmap = (PFR_CMap)cmap;
+
+
+ pfrcmap->chars = NULL;
+ pfrcmap->num_chars = 0;
}
FT_CALLBACK_DEF( FT_UInt )
- pfr_cmap_char_index( PFR_CMap cmap,
+ pfr_cmap_char_index( FT_CMap cmap, /* PFR_CMap */
FT_UInt32 char_code )
{
- FT_UInt min = 0;
- FT_UInt max = cmap->num_chars;
- FT_UInt mid = min + ( max - min ) / 2;
+ PFR_CMap pfrcmap = (PFR_CMap)cmap;
+ FT_UInt min = 0;
+ FT_UInt max = pfrcmap->num_chars;
+ FT_UInt mid = min + ( max - min ) / 2;
PFR_Char gchar;
while ( min < max )
{
- gchar = cmap->chars + mid;
+ gchar = pfrcmap->chars + mid;
if ( gchar->char_code == char_code )
return mid + 1;
@@ -96,10 +101,11 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- pfr_cmap_char_next( PFR_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ pfr_cmap_char_next( FT_CMap cmap, /* PFR_CMap */
FT_UInt32 *pchar_code )
{
+ PFR_CMap pfrcmap = (PFR_CMap)cmap;
FT_UInt result = 0;
FT_UInt32 char_code = *pchar_code + 1;
@@ -107,14 +113,14 @@
Restart:
{
FT_UInt min = 0;
- FT_UInt max = cmap->num_chars;
+ FT_UInt max = pfrcmap->num_chars;
FT_UInt mid = min + ( max - min ) / 2;
PFR_Char gchar;
while ( min < max )
{
- gchar = cmap->chars + mid;
+ gchar = pfrcmap->chars + mid;
if ( gchar->char_code == char_code )
{
@@ -143,9 +149,9 @@
/* we didn't find it, but we have a pair just above it */
char_code = 0;
- if ( min < cmap->num_chars )
+ if ( min < pfrcmap->num_chars )
{
- gchar = cmap->chars + min;
+ gchar = pfrcmap->chars + min;
result = min;
if ( result != 0 )
{
diff --git a/thirdparty/freetype/src/pfr/pfrdrivr.c b/thirdparty/freetype/src/pfr/pfrdrivr.c
index 78c6c6882c..0048f52411 100644
--- a/thirdparty/freetype/src/pfr/pfrdrivr.c
+++ b/thirdparty/freetype/src/pfr/pfrdrivr.c
@@ -27,16 +27,16 @@
FT_CALLBACK_DEF( FT_Error )
- pfr_get_kerning( FT_Face pfrface, /* PFR_Face */
+ pfr_get_kerning( FT_Face face, /* PFR_Face */
FT_UInt left,
FT_UInt right,
FT_Vector *avector )
{
- PFR_Face face = (PFR_Face)pfrface;
- PFR_PhyFont phys = &face->phy_font;
+ PFR_Face pfrface = (PFR_Face)face;
+ PFR_PhyFont phys = &pfrface->phy_font;
- (void)pfr_face_get_kerning( pfrface, left, right, avector );
+ (void)pfr_face_get_kerning( face, left, right, avector );
/* convert from metrics to outline units when necessary */
if ( phys->outline_resolution != phys->metrics_resolution )
@@ -62,12 +62,12 @@
*/
FT_CALLBACK_DEF( FT_Error )
- pfr_get_advance( FT_Face pfrface, /* PFR_Face */
+ pfr_get_advance( FT_Face face, /* PFR_Face */
FT_UInt gindex,
FT_Pos *anadvance )
{
- PFR_Face face = (PFR_Face)pfrface;
- FT_Error error = FT_ERR( Invalid_Argument );
+ PFR_Face pfrface = (PFR_Face)face;
+ FT_Error error = FT_ERR( Invalid_Argument );
*anadvance = 0;
@@ -77,9 +77,9 @@
gindex--;
- if ( face )
+ if ( pfrface )
{
- PFR_PhyFont phys = &face->phy_font;
+ PFR_PhyFont phys = &pfrface->phy_font;
if ( gindex < phys->num_chars )
@@ -95,16 +95,16 @@
FT_CALLBACK_DEF( FT_Error )
- pfr_get_metrics( FT_Face pfrface, /* PFR_Face */
+ pfr_get_metrics( FT_Face face, /* PFR_Face */
FT_UInt *anoutline_resolution,
FT_UInt *ametrics_resolution,
FT_Fixed *ametrics_x_scale,
FT_Fixed *ametrics_y_scale )
{
- PFR_Face face = (PFR_Face)pfrface;
- PFR_PhyFont phys = &face->phy_font;
+ PFR_Face pfrface = (PFR_Face)face;
+ PFR_PhyFont phys = &pfrface->phy_font;
FT_Fixed x_scale, y_scale;
- FT_Size size = face->root.size;
+ FT_Size size = pfrface->root.size;
if ( anoutline_resolution )
diff --git a/thirdparty/freetype/src/pfr/pfrgload.c b/thirdparty/freetype/src/pfr/pfrgload.c
index 14f2ec3778..48cf27ec80 100644
--- a/thirdparty/freetype/src/pfr/pfrgload.c
+++ b/thirdparty/freetype/src/pfr/pfrgload.c
@@ -560,8 +560,7 @@
FT_Byte* limit )
{
FT_Error error = FT_Err_Ok;
- FT_GlyphLoader loader = glyph->loader;
- FT_Memory memory = loader->memory;
+ FT_Memory memory = glyph->loader->memory;
PFR_SubGlyph subglyph;
FT_UInt flags, i, count, org_count;
FT_Int x_pos, y_pos;
diff --git a/thirdparty/freetype/src/pfr/pfrload.c b/thirdparty/freetype/src/pfr/pfrload.c
index de85ee6aad..856a5942f5 100644
--- a/thirdparty/freetype/src/pfr/pfrload.c
+++ b/thirdparty/freetype/src/pfr/pfrload.c
@@ -449,15 +449,16 @@
/* load bitmap strikes lists */
FT_CALLBACK_DEF( FT_Error )
- pfr_extra_item_load_bitmap_info( FT_Byte* p,
- FT_Byte* limit,
- PFR_PhyFont phy_font )
+ pfr_extra_item_load_bitmap_info( FT_Byte* p,
+ FT_Byte* limit,
+ void* phy_font_ )
{
- FT_Memory memory = phy_font->memory;
- PFR_Strike strike;
- FT_UInt flags0;
- FT_UInt n, count, size1;
- FT_Error error = FT_Err_Ok;
+ PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_;
+ FT_Memory memory = phy_font->memory;
+ PFR_Strike strike;
+ FT_UInt flags0;
+ FT_UInt n, count, size1;
+ FT_Error error = FT_Err_Ok;
PFR_CHECK( 5 );
@@ -549,13 +550,14 @@
* family.
*/
FT_CALLBACK_DEF( FT_Error )
- pfr_extra_item_load_font_id( FT_Byte* p,
- FT_Byte* limit,
- PFR_PhyFont phy_font )
+ pfr_extra_item_load_font_id( FT_Byte* p,
+ FT_Byte* limit,
+ void* phy_font_ )
{
- FT_Error error = FT_Err_Ok;
- FT_Memory memory = phy_font->memory;
- FT_UInt len = (FT_UInt)( limit - p );
+ PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_;
+ FT_Error error = FT_Err_Ok;
+ FT_Memory memory = phy_font->memory;
+ FT_UInt len = (FT_UInt)( limit - p );
if ( phy_font->font_id )
@@ -575,14 +577,15 @@
/* load stem snap tables */
FT_CALLBACK_DEF( FT_Error )
- pfr_extra_item_load_stem_snaps( FT_Byte* p,
- FT_Byte* limit,
- PFR_PhyFont phy_font )
+ pfr_extra_item_load_stem_snaps( FT_Byte* p,
+ FT_Byte* limit,
+ void* phy_font_ )
{
- FT_UInt count, num_vert, num_horz;
- FT_Int* snaps = NULL;
- FT_Error error = FT_Err_Ok;
- FT_Memory memory = phy_font->memory;
+ PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_;
+ FT_UInt count, num_vert, num_horz;
+ FT_Int* snaps = NULL;
+ FT_Error error = FT_Err_Ok;
+ FT_Memory memory = phy_font->memory;
if ( phy_font->vertical.stem_snaps )
@@ -619,10 +622,11 @@
/* load kerning pair data */
FT_CALLBACK_DEF( FT_Error )
- pfr_extra_item_load_kerning_pairs( FT_Byte* p,
- FT_Byte* limit,
- PFR_PhyFont phy_font )
+ pfr_extra_item_load_kerning_pairs( FT_Byte* p,
+ FT_Byte* limit,
+ void* phy_font_ )
{
+ PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_;
PFR_KernItem item = NULL;
FT_Error error = FT_Err_Ok;
FT_Memory memory = phy_font->memory;
@@ -715,10 +719,10 @@
static const PFR_ExtraItemRec pfr_phy_font_extra_items[] =
{
- { 1, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_bitmap_info },
- { 2, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_font_id },
- { 3, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_stem_snaps },
- { 4, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_kerning_pairs },
+ { 1, pfr_extra_item_load_bitmap_info },
+ { 2, pfr_extra_item_load_font_id },
+ { 3, pfr_extra_item_load_stem_snaps },
+ { 4, pfr_extra_item_load_kerning_pairs },
{ 0, NULL }
};
diff --git a/thirdparty/freetype/src/pfr/pfrobjs.c b/thirdparty/freetype/src/pfr/pfrobjs.c
index 3db8f0a060..8ef17c6636 100644
--- a/thirdparty/freetype/src/pfr/pfrobjs.c
+++ b/thirdparty/freetype/src/pfr/pfrobjs.c
@@ -50,14 +50,14 @@
if ( !face )
return;
- memory = pfrface->driver->root.memory;
+ memory = pfrface->memory;
/* we don't want dangling pointers */
pfrface->family_name = NULL;
pfrface->style_name = NULL;
/* finalize the physical font record */
- pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
+ pfr_phy_font_done( &face->phy_font, memory );
/* no need to finalize the logical font or the header */
FT_FREE( pfrface->available_sizes );
@@ -214,7 +214,7 @@
FT_UInt n, count = phy_font->num_strikes;
FT_Bitmap_Size* size;
PFR_Strike strike;
- FT_Memory memory = pfrface->stream->memory;
+ FT_Memory memory = pfrface->memory;
if ( FT_QNEW_ARRAY( pfrface->available_sizes, count ) )
diff --git a/thirdparty/freetype/src/psaux/afmparse.c b/thirdparty/freetype/src/psaux/afmparse.c
index 68f95698e6..db08941def 100644
--- a/thirdparty/freetype/src/psaux/afmparse.c
+++ b/thirdparty/freetype/src/psaux/afmparse.c
@@ -1086,7 +1086,7 @@
#else /* T1_CONFIG_OPTION_NO_AFM */
/* ANSI C doesn't like empty source files */
- typedef int _afm_parse_dummy;
+ typedef int afm_parse_dummy_;
#endif /* T1_CONFIG_OPTION_NO_AFM */
diff --git a/thirdparty/freetype/src/psaux/t1cmap.c b/thirdparty/freetype/src/psaux/t1cmap.c
index bf0a393b45..c4bcf599ea 100644
--- a/thirdparty/freetype/src/psaux/t1cmap.c
+++ b/thirdparty/freetype/src/psaux/t1cmap.c
@@ -50,8 +50,11 @@
FT_CALLBACK_DEF( void )
- t1_cmap_std_done( T1_CMapStd cmap )
+ t1_cmap_std_done( FT_CMap cmap_ ) /* T1_CMapStd */
{
+ T1_CMapStd cmap = (T1_CMapStd)cmap_;
+
+
cmap->num_glyphs = 0;
cmap->glyph_names = NULL;
cmap->sid_to_string = NULL;
@@ -60,10 +63,11 @@
FT_CALLBACK_DEF( FT_UInt )
- t1_cmap_std_char_index( T1_CMapStd cmap,
- FT_UInt32 char_code )
+ t1_cmap_std_char_index( FT_CMap cmap, /* T1_CMapStd */
+ FT_UInt32 char_code )
{
- FT_UInt result = 0;
+ T1_CMapStd t1cmap = (T1_CMapStd)cmap;
+ FT_UInt result = 0;
if ( char_code < 256 )
@@ -73,13 +77,13 @@
/* convert character code to Adobe SID string */
- code = cmap->code_to_sid[char_code];
- glyph_name = cmap->sid_to_string( code );
+ code = t1cmap->code_to_sid[char_code];
+ glyph_name = t1cmap->sid_to_string( code );
/* look for the corresponding glyph name */
- for ( n = 0; n < cmap->num_glyphs; n++ )
+ for ( n = 0; n < t1cmap->num_glyphs; n++ )
{
- const char* gname = cmap->glyph_names[n];
+ const char* gname = t1cmap->glyph_names[n];
if ( gname && gname[0] == glyph_name[0] &&
@@ -95,9 +99,9 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- t1_cmap_std_char_next( T1_CMapStd cmap,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_std_char_next( FT_CMap cmap,
+ FT_UInt32 *pchar_code )
{
FT_UInt result = 0;
FT_UInt32 char_code = *pchar_code + 1;
@@ -120,13 +124,14 @@
FT_CALLBACK_DEF( FT_Error )
- t1_cmap_standard_init( T1_CMapStd cmap,
+ t1_cmap_standard_init( FT_CMap cmap, /* T1_CMapStd */
FT_Pointer pointer )
{
+ T1_CMapStd t1cmap = (T1_CMapStd)cmap;
FT_UNUSED( pointer );
- t1_cmap_std_init( cmap, 0 );
+ t1_cmap_std_init( t1cmap, 0 );
return 0;
}
@@ -150,13 +155,14 @@
FT_CALLBACK_DEF( FT_Error )
- t1_cmap_expert_init( T1_CMapStd cmap,
+ t1_cmap_expert_init( FT_CMap cmap, /* T1_CMapStd */
FT_Pointer pointer )
{
+ T1_CMapStd t1cmap = (T1_CMapStd)cmap;
FT_UNUSED( pointer );
- t1_cmap_std_init( cmap, 1 );
+ t1_cmap_std_init( t1cmap, 1 );
return 0;
}
@@ -188,20 +194,21 @@
FT_CALLBACK_DEF( FT_Error )
- t1_cmap_custom_init( T1_CMapCustom cmap,
- FT_Pointer pointer )
+ t1_cmap_custom_init( FT_CMap cmap, /* T1_CMapCustom */
+ FT_Pointer pointer )
{
- T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
- T1_Encoding encoding = &face->type1.encoding;
+ T1_CMapCustom t1cmap = (T1_CMapCustom)cmap;
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ T1_Encoding encoding = &face->type1.encoding;
FT_UNUSED( pointer );
- cmap->first = (FT_UInt)encoding->code_first;
- cmap->count = (FT_UInt)encoding->code_last - cmap->first;
- cmap->indices = encoding->char_index;
+ t1cmap->first = (FT_UInt)encoding->code_first;
+ t1cmap->count = (FT_UInt)encoding->code_last - t1cmap->first;
+ t1cmap->indices = encoding->char_index;
- FT_ASSERT( cmap->indices );
+ FT_ASSERT( t1cmap->indices );
FT_ASSERT( encoding->code_first <= encoding->code_last );
return 0;
@@ -209,45 +216,50 @@
FT_CALLBACK_DEF( void )
- t1_cmap_custom_done( T1_CMapCustom cmap )
+ t1_cmap_custom_done( FT_CMap cmap ) /* T1_CMapCustom */
{
- cmap->indices = NULL;
- cmap->first = 0;
- cmap->count = 0;
+ T1_CMapCustom t1cmap = (T1_CMapCustom)cmap;
+
+
+ t1cmap->indices = NULL;
+ t1cmap->first = 0;
+ t1cmap->count = 0;
}
FT_CALLBACK_DEF( FT_UInt )
- t1_cmap_custom_char_index( T1_CMapCustom cmap,
- FT_UInt32 char_code )
+ t1_cmap_custom_char_index( FT_CMap cmap, /* T1_CMapCustom */
+ FT_UInt32 char_code )
{
- FT_UInt result = 0;
+ T1_CMapCustom t1cmap = (T1_CMapCustom)cmap;
+ FT_UInt result = 0;
- if ( ( char_code >= cmap->first ) &&
- ( char_code < ( cmap->first + cmap->count ) ) )
- result = cmap->indices[char_code];
+ if ( char_code >= t1cmap->first &&
+ char_code < ( t1cmap->first + t1cmap->count ) )
+ result = t1cmap->indices[char_code];
return result;
}
- FT_CALLBACK_DEF( FT_UInt32 )
- t1_cmap_custom_char_next( T1_CMapCustom cmap,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_custom_char_next( FT_CMap cmap, /* T1_CMapCustom */
+ FT_UInt32 *pchar_code )
{
- FT_UInt result = 0;
- FT_UInt32 char_code = *pchar_code;
+ T1_CMapCustom t1cmap = (T1_CMapCustom)cmap;
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code;
char_code++;
- if ( char_code < cmap->first )
- char_code = cmap->first;
+ if ( char_code < t1cmap->first )
+ char_code = t1cmap->first;
- for ( ; char_code < ( cmap->first + cmap->count ); char_code++ )
+ for ( ; char_code < ( t1cmap->first + t1cmap->count ); char_code++ )
{
- result = cmap->indices[char_code];
+ result = t1cmap->indices[char_code];
if ( result != 0 )
goto Exit;
}
@@ -287,20 +299,24 @@
/*************************************************************************/
FT_CALLBACK_DEF( const char * )
- psaux_get_glyph_name( T1_Face face,
+ psaux_get_glyph_name( void* face_,
FT_UInt idx )
{
+ T1_Face face = (T1_Face)face_;
+
+
return face->type1.glyph_names[idx];
}
FT_CALLBACK_DEF( FT_Error )
- t1_cmap_unicode_init( PS_Unicodes unicodes,
- FT_Pointer pointer )
+ t1_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */
+ FT_Pointer pointer )
{
- T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
FT_UNUSED( pointer );
@@ -311,17 +327,18 @@
return psnames->unicodes_init( memory,
unicodes,
(FT_UInt)face->type1.num_glyphs,
- (PS_GetGlyphNameFunc)&psaux_get_glyph_name,
+ &psaux_get_glyph_name,
(PS_FreeGlyphNameFunc)NULL,
(FT_Pointer)face );
}
FT_CALLBACK_DEF( void )
- t1_cmap_unicode_done( PS_Unicodes unicodes )
+ t1_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */
{
- FT_Face face = FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_FREE( unicodes->maps );
@@ -330,23 +347,25 @@
FT_CALLBACK_DEF( FT_UInt )
- t1_cmap_unicode_char_index( PS_Unicodes unicodes,
- FT_UInt32 char_code )
+ t1_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 char_code )
{
- T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
return psnames->unicodes_char_index( unicodes, char_code );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- t1_cmap_unicode_char_next( PS_Unicodes unicodes,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 *pchar_code )
{
- T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
return psnames->unicodes_char_next( unicodes, pchar_code );
diff --git a/thirdparty/freetype/src/pshinter/pshalgo.c b/thirdparty/freetype/src/pshinter/pshalgo.c
index a7f321291a..4f622e1e44 100644
--- a/thirdparty/freetype/src/pshinter/pshalgo.c
+++ b/thirdparty/freetype/src/pshinter/pshalgo.c
@@ -516,7 +516,7 @@
if ( !psh_hint_is_fitted( parent ) )
psh_hint_align( parent, globals, dimension, glyph );
- /* keep original relation between hints, this is, use the */
+ /* keep original relation between hints, that is, use the */
/* scaled distance between the centers of the hints to */
/* compute the new position */
par_org_center = parent->org_pos + ( parent->org_len >> 1 );
diff --git a/thirdparty/freetype/src/pshinter/pshmod.c b/thirdparty/freetype/src/pshinter/pshmod.c
index a12e485660..974a99e018 100644
--- a/thirdparty/freetype/src/pshinter/pshmod.c
+++ b/thirdparty/freetype/src/pshinter/pshmod.c
@@ -37,8 +37,11 @@
/* finalize module */
FT_CALLBACK_DEF( void )
- ps_hinter_done( PS_Hinter_Module module )
+ ps_hinter_done( FT_Module module_ ) /* PS_Hinter_Module */
{
+ PS_Hinter_Module module = (PS_Hinter_Module)module_;
+
+
module->t1_funcs.hints = NULL;
module->t2_funcs.hints = NULL;
@@ -48,8 +51,10 @@
/* initialize module, create hints recorder and the interface */
FT_CALLBACK_DEF( FT_Error )
- ps_hinter_init( PS_Hinter_Module module )
+ ps_hinter_init( FT_Module module_ ) /* PS_Hinter_Module */
{
+ PS_Hinter_Module module = (PS_Hinter_Module)module_;
+
FT_Memory memory = module->root.memory;
void* ph = &module->ps_hints;
diff --git a/thirdparty/freetype/src/pshinter/pshrec.c b/thirdparty/freetype/src/pshinter/pshrec.c
index 58c8cf1b48..680e6d0135 100644
--- a/thirdparty/freetype/src/pshinter/pshrec.c
+++ b/thirdparty/freetype/src/pshinter/pshrec.c
@@ -851,10 +851,11 @@
/* add one Type1 counter stem to the current hints table */
static void
- ps_hints_t1stem3( PS_Hints hints,
+ ps_hints_t1stem3( T1_Hints hints_, /* PS_Hints */
FT_UInt dimension,
FT_Fixed* stems )
{
+ PS_Hints hints = (PS_Hints)hints_;
FT_Error error = FT_Err_Ok;
@@ -914,9 +915,10 @@
/* reset hints (only with Type 1 hints) */
static void
- ps_hints_t1reset( PS_Hints hints,
+ ps_hints_t1reset( T1_Hints hints_, /* PS_Hints */
FT_UInt end_point )
{
+ PS_Hints hints = (PS_Hints)hints_;
FT_Error error = FT_Err_Ok;
@@ -953,11 +955,12 @@
/* Type2 "hintmask" operator, add a new hintmask to each direction */
static void
- ps_hints_t2mask( PS_Hints hints,
+ ps_hints_t2mask( T2_Hints hints_, /* PS_Hints */
FT_UInt end_point,
FT_UInt bit_count,
const FT_Byte* bytes )
{
+ PS_Hints hints = (PS_Hints)hints_;
FT_Error error;
@@ -999,10 +1002,11 @@
static void
- ps_hints_t2counter( PS_Hints hints,
+ ps_hints_t2counter( T2_Hints hints_, /* PS_Hints */
FT_UInt bit_count,
const FT_Byte* bytes )
{
+ PS_Hints hints = (PS_Hints)hints_;
FT_Error error;
@@ -1087,6 +1091,13 @@
ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 );
}
+ static FT_Error
+ t1_hints_close( T1_Hints hints,
+ FT_UInt end_point )
+ {
+ return ps_hints_close( (PS_Hints)hints, end_point );
+ }
+
static void
t1_hints_stem( T1_Hints hints,
FT_UInt dimension,
@@ -1102,17 +1113,27 @@
}
+ static FT_Error
+ t1_hints_apply( T1_Hints hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode )
+ {
+ return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode );
+ }
+
+
FT_LOCAL_DEF( void )
t1_hints_funcs_init( T1_Hints_FuncsRec* funcs )
{
FT_ZERO( funcs );
funcs->open = (T1_Hints_OpenFunc) t1_hints_open;
- funcs->close = (T1_Hints_CloseFunc) ps_hints_close;
+ funcs->close = (T1_Hints_CloseFunc) t1_hints_close;
funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem;
funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3;
funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset;
- funcs->apply = (T1_Hints_ApplyFunc) ps_hints_apply;
+ funcs->apply = (T1_Hints_ApplyFunc) t1_hints_apply;
}
@@ -1131,6 +1152,14 @@
}
+ static FT_Error
+ t2_hints_close( T2_Hints hints,
+ FT_UInt end_point )
+ {
+ return ps_hints_close( (PS_Hints)hints, end_point );
+ }
+
+
static void
t2_hints_stems( T2_Hints hints,
FT_UInt dimension,
@@ -1168,17 +1197,27 @@
}
+ static FT_Error
+ t2_hints_apply( T2_Hints hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode )
+ {
+ return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode );
+ }
+
+
FT_LOCAL_DEF( void )
t2_hints_funcs_init( T2_Hints_FuncsRec* funcs )
{
FT_ZERO( funcs );
- funcs->open = (T2_Hints_OpenFunc) t2_hints_open;
- funcs->close = (T2_Hints_CloseFunc) ps_hints_close;
- funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems;
- funcs->hintmask= (T2_Hints_MaskFunc) ps_hints_t2mask;
- funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter;
- funcs->apply = (T2_Hints_ApplyFunc) ps_hints_apply;
+ funcs->open = (T2_Hints_OpenFunc) t2_hints_open;
+ funcs->close = (T2_Hints_CloseFunc) t2_hints_close;
+ funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems;
+ funcs->hintmask = (T2_Hints_MaskFunc) ps_hints_t2mask;
+ funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter;
+ funcs->apply = (T2_Hints_ApplyFunc) t2_hints_apply;
}
diff --git a/thirdparty/freetype/src/psnames/psmodule.c b/thirdparty/freetype/src/psnames/psmodule.c
index db454e558e..8203a0465d 100644
--- a/thirdparty/freetype/src/psnames/psmodule.c
+++ b/thirdparty/freetype/src/psnames/psmodule.c
@@ -57,7 +57,7 @@
/* the name, as in `A.swash' or `e.final'; in this case, the */
/* VARIANT_BIT is set in the return value. */
/* */
- static FT_UInt32
+ FT_CALLBACK_DEF( FT_UInt32 )
ps_unicode_value( const char* glyph_name )
{
/* If the name begins with `uni', then the glyph name may be a */
@@ -309,7 +309,7 @@
/* Build a table that maps Unicode values to glyph indices. */
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
ps_unicodes_init( FT_Memory memory,
PS_Unicodes table,
FT_UInt num_glyphs,
@@ -408,7 +408,7 @@
}
- static FT_UInt
+ FT_CALLBACK_DEF( FT_UInt )
ps_unicodes_char_index( PS_Unicodes table,
FT_UInt32 unicode )
{
@@ -453,7 +453,7 @@
}
- static FT_UInt32
+ FT_CALLBACK_DEF( FT_UInt )
ps_unicodes_char_next( PS_Unicodes table,
FT_UInt32 *unicode )
{
@@ -518,7 +518,7 @@
#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
- static const char*
+ FT_CALLBACK_DEF( const char* )
ps_get_macintosh_name( FT_UInt name_index )
{
if ( name_index >= FT_NUM_MAC_NAMES )
@@ -528,7 +528,7 @@
}
- static const char*
+ FT_CALLBACK_DEF( const char* )
ps_get_standard_strings( FT_UInt sid )
{
if ( sid >= FT_NUM_SID_NAMES )
@@ -543,13 +543,13 @@
FT_DEFINE_SERVICE_PSCMAPSREC(
pscmaps_interface,
- (PS_Unicode_ValueFunc) ps_unicode_value, /* unicode_value */
- (PS_Unicodes_InitFunc) ps_unicodes_init, /* unicodes_init */
- (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index, /* unicodes_char_index */
- (PS_Unicodes_CharNextFunc) ps_unicodes_char_next, /* unicodes_char_next */
+ ps_unicode_value, /* PS_Unicode_ValueFunc unicode_value */
+ ps_unicodes_init, /* PS_Unicodes_InitFunc unicodes_init */
+ ps_unicodes_char_index, /* PS_Unicodes_CharIndexFunc unicodes_char_index */
+ ps_unicodes_char_next, /* PS_Unicodes_CharNextFunc unicodes_char_next */
- (PS_Macintosh_NameFunc) ps_get_macintosh_name, /* macintosh_name */
- (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings */
+ ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */
+ ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */
t1_standard_encoding, /* adobe_std_encoding */
t1_expert_encoding /* adobe_expert_encoding */
@@ -560,13 +560,13 @@
FT_DEFINE_SERVICE_PSCMAPSREC(
pscmaps_interface,
- NULL, /* unicode_value */
- NULL, /* unicodes_init */
- NULL, /* unicodes_char_index */
- NULL, /* unicodes_char_next */
+ NULL, /* PS_Unicode_ValueFunc unicode_value */
+ NULL, /* PS_Unicodes_InitFunc unicodes_init */
+ NULL, /* PS_Unicodes_CharIndexFunc unicodes_char_index */
+ NULL, /* PS_Unicodes_CharNextFunc unicodes_char_next */
- (PS_Macintosh_NameFunc) ps_get_macintosh_name, /* macintosh_name */
- (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings */
+ ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */
+ ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */
t1_standard_encoding, /* adobe_std_encoding */
t1_expert_encoding /* adobe_expert_encoding */
@@ -612,9 +612,9 @@
PUT_PS_NAMES_SERVICE(
(void*)&pscmaps_interface ), /* module specific interface */
- (FT_Module_Constructor)NULL, /* module_init */
- (FT_Module_Destructor) NULL, /* module_done */
- (FT_Module_Requester) PUT_PS_NAMES_SERVICE( psnames_get_service ) /* get_interface */
+ NULL, /* FT_Module_Constructor module_init */
+ NULL, /* FT_Module_Destructor module_done */
+ PUT_PS_NAMES_SERVICE( psnames_get_service ) /* FT_Module_Requester get_interface */
)
diff --git a/thirdparty/freetype/src/raster/ftraster.c b/thirdparty/freetype/src/raster/ftraster.c
index 67cbfd5d9b..192ca0701a 100644
--- a/thirdparty/freetype/src/raster/ftraster.c
+++ b/thirdparty/freetype/src/raster/ftraster.c
@@ -1742,9 +1742,9 @@
* SUCCESS on success, FAILURE on error.
*/
static Bool
- Decompose_Curve( RAS_ARGS UShort first,
- UShort last,
- Int flipped )
+ Decompose_Curve( RAS_ARGS Int first,
+ Int last,
+ Int flipped )
{
FT_Vector v_last;
FT_Vector v_control;
@@ -1969,8 +1969,8 @@
static Bool
Convert_Glyph( RAS_ARGS Int flipped )
{
- Int i;
- UInt start;
+ Int i;
+ Int first, last;
ras.fProfile = NULL;
@@ -1985,8 +1985,7 @@
ras.cProfile->offset = ras.top;
ras.num_Profs = 0;
- start = 0;
-
+ last = -1;
for ( i = 0; i < ras.outline.n_contours; i++ )
{
PProfile lastProfile;
@@ -1996,12 +1995,11 @@
ras.state = Unknown_State;
ras.gProfile = NULL;
- if ( Decompose_Curve( RAS_VARS (UShort)start,
- (UShort)ras.outline.contours[i],
- flipped ) )
- return FAILURE;
+ first = last + 1;
+ last = ras.outline.contours[i];
- start = (UShort)ras.outline.contours[i] + 1;
+ if ( Decompose_Curve( RAS_VARS first, last, flipped ) )
+ return FAILURE;
/* we must now check whether the extreme arcs join or not */
if ( FRAC( ras.lastY ) == 0 &&
@@ -3167,9 +3165,12 @@
static int
- ft_black_new( FT_Memory memory,
- black_PRaster *araster )
+ ft_black_new( void* memory_, /* FT_Memory */
+ FT_Raster *araster_ ) /* black_PRaster */
{
+ FT_Memory memory = (FT_Memory)memory_;
+ black_PRaster *araster = (black_PRaster*)araster_;
+
FT_Error error;
black_PRaster raster = NULL;
@@ -3184,9 +3185,10 @@
static void
- ft_black_done( black_PRaster raster )
+ ft_black_done( FT_Raster raster_ ) /* black_PRaster */
{
- FT_Memory memory = (FT_Memory)raster->memory;
+ black_PRaster raster = (black_PRaster)raster_;
+ FT_Memory memory = (FT_Memory)raster->memory;
FT_FREE( raster );
@@ -3281,11 +3283,11 @@
FT_GLYPH_FORMAT_OUTLINE,
- (FT_Raster_New_Func) ft_black_new, /* raster_new */
- (FT_Raster_Reset_Func) ft_black_reset, /* raster_reset */
- (FT_Raster_Set_Mode_Func)ft_black_set_mode, /* raster_set_mode */
- (FT_Raster_Render_Func) ft_black_render, /* raster_render */
- (FT_Raster_Done_Func) ft_black_done /* raster_done */
+ ft_black_new, /* FT_Raster_New_Func raster_new */
+ ft_black_reset, /* FT_Raster_Reset_Func raster_reset */
+ ft_black_set_mode, /* FT_Raster_Set_Mode_Func raster_set_mode */
+ ft_black_render, /* FT_Raster_Render_Func raster_render */
+ ft_black_done /* FT_Raster_Done_Func raster_done */
)
diff --git a/thirdparty/freetype/src/raster/ftrend1.c b/thirdparty/freetype/src/raster/ftrend1.c
index 0b5d867147..6d442b1ff8 100644
--- a/thirdparty/freetype/src/raster/ftrend1.c
+++ b/thirdparty/freetype/src/raster/ftrend1.c
@@ -27,8 +27,11 @@
/* initialize renderer -- init its raster */
static FT_Error
- ft_raster1_init( FT_Renderer render )
+ ft_raster1_init( FT_Module module ) /* FT_Renderer */
{
+ FT_Renderer render = (FT_Renderer)module;
+
+
render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
return FT_Err_Ok;
@@ -188,18 +191,18 @@
NULL, /* module specific interface */
- (FT_Module_Constructor)ft_raster1_init, /* module_init */
- (FT_Module_Destructor) NULL, /* module_done */
- (FT_Module_Requester) NULL, /* get_interface */
+ ft_raster1_init, /* FT_Module_Constructor module_init */
+ NULL, /* FT_Module_Destructor module_done */
+ NULL, /* FT_Module_Requester get_interface */
FT_GLYPH_FORMAT_OUTLINE,
- (FT_Renderer_RenderFunc) ft_raster1_render, /* render_glyph */
- (FT_Renderer_TransformFunc)ft_raster1_transform, /* transform_glyph */
- (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox, /* get_glyph_cbox */
- (FT_Renderer_SetModeFunc) ft_raster1_set_mode, /* set_mode */
+ ft_raster1_render, /* FT_Renderer_RenderFunc render_glyph */
+ ft_raster1_transform, /* FT_Renderer_TransformFunc transform_glyph */
+ ft_raster1_get_cbox, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */
+ ft_raster1_set_mode, /* FT_Renderer_SetModeFunc set_mode */
- (FT_Raster_Funcs*)&ft_standard_raster /* raster_class */
+ &ft_standard_raster /* FT_Raster_Funcs* raster_class */
)
diff --git a/thirdparty/freetype/src/sdf/ftbsdf.c b/thirdparty/freetype/src/sdf/ftbsdf.c
index 901d8b7402..e472738339 100644
--- a/thirdparty/freetype/src/sdf/ftbsdf.c
+++ b/thirdparty/freetype/src/sdf/ftbsdf.c
@@ -1173,9 +1173,12 @@
/* called when adding a new module through @FT_Add_Module */
static FT_Error
- bsdf_raster_new( FT_Memory memory,
- BSDF_PRaster* araster )
+ bsdf_raster_new( void* memory_, /* FT_Memory */
+ FT_Raster* araster_ ) /* BSDF_PRaster* */
{
+ FT_Memory memory = (FT_Memory)memory_;
+ BSDF_PRaster* araster = (BSDF_PRaster*)araster_;
+
FT_Error error;
BSDF_PRaster raster = NULL;
diff --git a/thirdparty/freetype/src/sdf/ftsdf.c b/thirdparty/freetype/src/sdf/ftsdf.c
index 26a6d00e4a..bc4625d984 100644
--- a/thirdparty/freetype/src/sdf/ftsdf.c
+++ b/thirdparty/freetype/src/sdf/ftsdf.c
@@ -2371,11 +2371,11 @@
* ```
*
* (6) Our task is to find a value of `t` such that the above equation
- * `Q(t)` becomes zero, this is, the point-to-curve vector makes
+ * `Q(t)` becomes zero, that is, the point-to-curve vector makes
* 90~degrees with the curve. We solve this with the Newton-Raphson
* method.
*
- * (7) We first assume an arbitary value of factor `t`, which we then
+ * (7) We first assume an arbitrary value of factor `t`, which we then
* improve.
*
* ```
@@ -2684,11 +2684,11 @@
* ```
*
* (6) Our task is to find a value of `t` such that the above equation
- * `Q(t)` becomes zero, this is, the point-to-curve vector makes
+ * `Q(t)` becomes zero, that is, the point-to-curve vector makes
* 90~degree with curve. We solve this with the Newton-Raphson
* method.
*
- * (7) We first assume an arbitary value of factor `t`, which we then
+ * (7) We first assume an arbitrary value of factor `t`, which we then
* improve.
*
* ```
@@ -2718,8 +2718,9 @@
FT_Error error = FT_Err_Ok;
- FT_26D6_Vec aA, bB, cC, dD; /* A, B, C in the above comment */
- FT_16D16_Vec nearest_point; /* point on curve nearest to `point` */
+ FT_26D6_Vec aA, bB, cC, dD; /* A, B, C, D in the above comment */
+ FT_16D16_Vec nearest_point = { 0, 0 };
+ /* point on curve nearest to `point` */
FT_16D16_Vec direction; /* direction of curve at `nearest_point` */
FT_26D6_Vec p0, p1, p2, p3; /* control points of a cubic curve */
@@ -3761,9 +3762,13 @@
*/
static FT_Error
- sdf_raster_new( FT_Memory memory,
- SDF_PRaster* araster )
+ sdf_raster_new( void* memory_, /* FT_Memory */
+ FT_Raster* araster_ ) /* SDF_PRaster* */
{
+ FT_Memory memory = (FT_Memory)memory_;
+ SDF_PRaster* araster = (SDF_PRaster*)araster_;
+
+
FT_Error error;
SDF_PRaster raster = NULL;
diff --git a/thirdparty/freetype/src/sdf/ftsdfrend.c b/thirdparty/freetype/src/sdf/ftsdfrend.c
index 9ac7d6f620..5610c119f8 100644
--- a/thirdparty/freetype/src/sdf/ftsdfrend.c
+++ b/thirdparty/freetype/src/sdf/ftsdfrend.c
@@ -197,10 +197,10 @@
static FT_Module_Interface
- ft_sdf_requester( FT_Renderer render,
+ ft_sdf_requester( FT_Module module,
const char* module_interface )
{
- FT_UNUSED( render );
+ FT_UNUSED( module );
return ft_service_list_lookup( sdf_services, module_interface );
}
@@ -221,9 +221,9 @@
*/
static FT_Error
- ft_sdf_init( FT_Renderer render )
+ ft_sdf_init( FT_Module module ) /* SDF_Renderer */
{
- SDF_Renderer sdf_render = SDF_RENDERER( render );
+ SDF_Renderer sdf_render = SDF_RENDERER( module );
sdf_render->spread = DEFAULT_SPREAD;
@@ -236,9 +236,9 @@
static void
- ft_sdf_done( FT_Renderer render )
+ ft_sdf_done( FT_Module module )
{
- FT_UNUSED( render );
+ FT_UNUSED( module );
}
@@ -300,7 +300,7 @@
/* nothing to render */
if ( !bitmap->rows || !bitmap->pitch )
- return FT_Err_Ok;
+ goto Exit;
/* the padding will simply be equal to the `spread' */
x_pad = sdf_module->spread;
@@ -508,6 +508,10 @@
goto Exit;
}
+ /* nothing to render */
+ if ( !bitmap->rows || !bitmap->pitch )
+ goto Exit;
+
/* Do not generate SDF if the bitmap is not owned by the */
/* glyph: it might be that the source buffer is already freed. */
if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
@@ -519,10 +523,6 @@
goto Exit;
}
- /* nothing to render */
- if ( !bitmap->rows || !bitmap->pitch )
- return FT_Err_Ok;
-
FT_Bitmap_New( &target );
/* padding will simply be equal to `spread` */
@@ -557,15 +557,14 @@
{
/* the glyph is successfully converted to a SDF */
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
- {
FT_FREE( bitmap->buffer );
- slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
- }
- slot->bitmap = target;
- slot->bitmap_top += y_pad;
- slot->bitmap_left -= x_pad;
- slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+ slot->bitmap = target;
+ slot->bitmap_top += y_pad;
+ slot->bitmap_left -= x_pad;
+
+ if ( target.buffer )
+ slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
}
else if ( target.buffer )
FT_FREE( target.buffer );
diff --git a/thirdparty/freetype/src/sfnt/pngshim.c b/thirdparty/freetype/src/sfnt/pngshim.c
index 423b07b02a..33712162e0 100644
--- a/thirdparty/freetype/src/sfnt/pngshim.c
+++ b/thirdparty/freetype/src/sfnt/pngshim.c
@@ -406,10 +406,7 @@
switch ( color_type )
{
- default:
- /* Shouldn't happen, but ... */
- FALL_THROUGH;
-
+ default: /* Shouldn't happen, but ... */
case PNG_COLOR_TYPE_RGB_ALPHA:
png_set_read_user_transform_fn( png, premultiply_data );
break;
@@ -457,7 +454,7 @@
#else /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */
/* ANSI C doesn't like empty source files */
- typedef int _pngshim_dummy;
+ typedef int pngshim_dummy_;
#endif /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */
diff --git a/thirdparty/freetype/src/sfnt/sfdriver.c b/thirdparty/freetype/src/sfnt/sfdriver.c
index 762883db54..0925940b03 100644
--- a/thirdparty/freetype/src/sfnt/sfdriver.c
+++ b/thirdparty/freetype/src/sfnt/sfdriver.c
@@ -79,41 +79,57 @@
*
*/
- static void*
- get_sfnt_table( TT_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ sfnt_load_table( FT_Face face, /* TT_Face */
+ FT_ULong tag,
+ FT_Long offset,
+ FT_Byte* buffer,
+ FT_ULong* length )
+ {
+ TT_Face ttface = (TT_Face)face;
+
+
+ return tt_face_load_any( ttface, tag, offset, buffer, length );
+ }
+
+
+ FT_CALLBACK_DEF( void* )
+ get_sfnt_table( FT_Face face, /* TT_Face */
FT_Sfnt_Tag tag )
{
+ TT_Face ttface = (TT_Face)face;
+
void* table;
switch ( tag )
{
case FT_SFNT_HEAD:
- table = &face->header;
+ table = &ttface->header;
break;
case FT_SFNT_HHEA:
- table = &face->horizontal;
+ table = &ttface->horizontal;
break;
case FT_SFNT_VHEA:
- table = face->vertical_info ? &face->vertical : NULL;
+ table = ttface->vertical_info ? &ttface->vertical : NULL;
break;
case FT_SFNT_OS2:
- table = ( face->os2.version == 0xFFFFU ) ? NULL : &face->os2;
+ table = ( ttface->os2.version == 0xFFFFU ) ? NULL : &ttface->os2;
break;
case FT_SFNT_POST:
- table = &face->postscript;
+ table = &ttface->postscript;
break;
case FT_SFNT_MAXP:
- table = &face->max_profile;
+ table = &ttface->max_profile;
break;
case FT_SFNT_PCLT:
- table = face->pclt.Version ? &face->pclt : NULL;
+ table = ttface->pclt.Version ? &ttface->pclt : NULL;
break;
default:
@@ -124,26 +140,29 @@
}
- static FT_Error
- sfnt_table_info( TT_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ sfnt_table_info( FT_Face face, /* TT_Face */
FT_UInt idx,
FT_ULong *tag,
FT_ULong *offset,
FT_ULong *length )
{
+ TT_Face ttface = (TT_Face)face;
+
+
if ( !offset || !length )
return FT_THROW( Invalid_Argument );
if ( !tag )
- *length = face->num_tables;
+ *length = ttface->num_tables;
else
{
- if ( idx >= face->num_tables )
+ if ( idx >= ttface->num_tables )
return FT_THROW( Table_Missing );
- *tag = face->dir_tables[idx].Tag;
- *offset = face->dir_tables[idx].Offset;
- *length = face->dir_tables[idx].Length;
+ *tag = ttface->dir_tables[idx].Tag;
+ *offset = ttface->dir_tables[idx].Offset;
+ *length = ttface->dir_tables[idx].Length;
}
return FT_Err_Ok;
@@ -153,9 +172,9 @@
FT_DEFINE_SERVICE_SFNT_TABLEREC(
sfnt_service_sfnt_table,
- (FT_SFNT_TableLoadFunc)tt_face_load_any, /* load_table */
- (FT_SFNT_TableGetFunc) get_sfnt_table, /* get_table */
- (FT_SFNT_TableInfoFunc)sfnt_table_info /* table_info */
+ sfnt_load_table, /* FT_SFNT_TableLoadFunc load_table */
+ get_sfnt_table, /* FT_SFNT_TableGetFunc get_table */
+ sfnt_table_info /* FT_SFNT_TableInfoFunc table_info */
)
@@ -166,7 +185,7 @@
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
sfnt_get_glyph_name( FT_Face face,
FT_UInt glyph_index,
FT_Pointer buffer,
@@ -184,7 +203,7 @@
}
- static FT_UInt
+ FT_CALLBACK_DEF( FT_UInt )
sfnt_get_name_index( FT_Face face,
const FT_String* glyph_name )
{
@@ -221,8 +240,8 @@
FT_DEFINE_SERVICE_GLYPHDICTREC(
sfnt_service_glyph_dict,
- (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, /* get_name */
- (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index /* name_index */
+ sfnt_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */
+ sfnt_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */
)
#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
@@ -523,15 +542,14 @@
FT_TRACE0(( "get_win_string:"
" Character 0x%X invalid in PS name string\n",
((unsigned)p[0])*256 + (unsigned)p[1] ));
- break;
+ continue;
}
}
- if ( !len )
- *r = '\0';
+ *r = '\0';
FT_FRAME_EXIT();
- if ( !len )
+ if ( r != result )
return result;
get_win_string_error:
@@ -580,15 +598,14 @@
FT_TRACE0(( "get_apple_string:"
" Character `%c' (0x%X) invalid in PS name string\n",
*p, *p ));
- break;
+ continue;
}
}
- if ( !len )
- *r = '\0';
+ *r = '\0';
FT_FRAME_EXIT();
- if ( !len )
+ if ( r != result )
return result;
get_apple_string_error:
@@ -602,7 +619,7 @@
}
- static FT_Bool
+ FT_CALLBACK_DEF( FT_Bool )
sfnt_get_name_id( TT_Face face,
FT_UShort id,
FT_Int *win,
@@ -819,9 +836,9 @@
if ( !found )
{
- /* as a last resort we try the family name; note that this is */
- /* not in the Adobe TechNote, but GX fonts (which predate the */
- /* TechNote) benefit from this behaviour */
+ /* according to the 'name' documentation in the OpenType */
+ /* specification the font family name is to be used if the */
+ /* typographic family name is missing, so let's do that */
found = sfnt_get_name_id( face,
TT_NAME_ID_FONT_FAMILY,
&win,
@@ -853,6 +870,10 @@
{
FT_TRACE0(( "sfnt_get_var_ps_name:"
" No valid PS name prefix for font instances found\n" ));
+ /* XXX It probably makes sense to never let this fail */
+ /* since an arbitrary prefix should work, too. */
+ /* On the other hand, it is very unlikely that */
+ /* we ever reach this code at all. */
return NULL;
}
@@ -1041,47 +1062,49 @@
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
- static const char*
- sfnt_get_ps_name( TT_Face face )
+ FT_CALLBACK_DEF( const char* )
+ sfnt_get_ps_name( FT_Face face ) /* TT_Face */
{
+ TT_Face ttface = (TT_Face)face;
+
FT_Int found, win, apple;
const char* result = NULL;
- if ( face->postscript_name )
- return face->postscript_name;
+ if ( ttface->postscript_name )
+ return ttface->postscript_name;
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- if ( face->blend &&
- ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ||
- FT_IS_VARIATION( FT_FACE( face ) ) ) )
+ if ( ttface->blend &&
+ ( FT_IS_NAMED_INSTANCE( face ) ||
+ FT_IS_VARIATION( face ) ) )
{
- face->postscript_name = sfnt_get_var_ps_name( face );
- return face->postscript_name;
+ ttface->postscript_name = sfnt_get_var_ps_name( ttface );
+ return ttface->postscript_name;
}
#endif
/* scan the name table to see whether we have a Postscript name here, */
/* either in Macintosh or Windows platform encodings */
- found = sfnt_get_name_id( face, TT_NAME_ID_PS_NAME, &win, &apple );
+ found = sfnt_get_name_id( ttface, TT_NAME_ID_PS_NAME, &win, &apple );
if ( !found )
return NULL;
/* prefer Windows entries over Apple */
if ( win != -1 )
- result = get_win_string( face->root.memory,
- face->name_table.stream,
- face->name_table.names + win,
+ result = get_win_string( FT_FACE_MEMORY( face ),
+ ttface->name_table.stream,
+ ttface->name_table.names + win,
sfnt_is_postscript,
1 );
if ( !result && apple != -1 )
- result = get_apple_string( face->root.memory,
- face->name_table.stream,
- face->name_table.names + apple,
+ result = get_apple_string( FT_FACE_MEMORY( face ),
+ ttface->name_table.stream,
+ ttface->name_table.names + apple,
sfnt_is_postscript,
1 );
- face->postscript_name = result;
+ ttface->postscript_name = result;
return result;
}
@@ -1090,7 +1113,7 @@
FT_DEFINE_SERVICE_PSFONTNAMEREC(
sfnt_service_ps_name,
- (FT_PsName_GetFunc)sfnt_get_ps_name /* get_ps_font_name */
+ sfnt_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */
)
@@ -1100,14 +1123,14 @@
FT_DEFINE_SERVICE_TTCMAPSREC(
tt_service_get_cmap_info,
- (TT_CMap_Info_GetFunc)tt_get_cmap_info /* get_cmap_info */
+ tt_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */
)
#ifdef TT_CONFIG_OPTION_BDF
static FT_Error
- sfnt_get_charset_id( TT_Face face,
+ sfnt_get_charset_id( FT_Face face,
const char* *acharset_encoding,
const char* *acharset_registry )
{
@@ -1145,8 +1168,8 @@
FT_DEFINE_SERVICE_BDFRec(
sfnt_service_bdf,
- (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id, /* get_charset_id */
- (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop /* get_property */
+ sfnt_get_charset_id, /* FT_BDF_GetCharsetIdFunc get_charset_id */
+ tt_face_find_bdf_prop /* FT_BDF_GetPropertyFunc get_property */
)
@@ -1337,9 +1360,9 @@
(const void*)&sfnt_interface, /* module specific interface */
- (FT_Module_Constructor)NULL, /* module_init */
- (FT_Module_Destructor) NULL, /* module_done */
- (FT_Module_Requester) sfnt_get_interface /* get_interface */
+ NULL, /* FT_Module_Constructor module_init */
+ NULL, /* FT_Module_Destructor module_done */
+ sfnt_get_interface /* FT_Module_Requester get_interface */
)
diff --git a/thirdparty/freetype/src/sfnt/sfobjs.c b/thirdparty/freetype/src/sfnt/sfobjs.c
index e018934cca..f5d66ef840 100644
--- a/thirdparty/freetype/src/sfnt/sfobjs.c
+++ b/thirdparty/freetype/src/sfnt/sfobjs.c
@@ -534,17 +534,23 @@
0 );
}
- if ( !face->var )
+ if ( !face->tt_var )
{
/* we want the metrics variations interface */
/* from the `truetype' module only */
FT_Module tt_module = FT_Get_Module( library, "truetype" );
- face->var = ft_module_get_service( tt_module,
- FT_SERVICE_ID_METRICS_VARIATIONS,
- 0 );
+ face->tt_var = ft_module_get_service( tt_module,
+ FT_SERVICE_ID_METRICS_VARIATIONS,
+ 0 );
}
+
+ if ( !face->face_var )
+ face->face_var = ft_module_get_service(
+ &face->root.driver->root,
+ FT_SERVICE_ID_METRICS_VARIATIONS,
+ 0 );
#endif
FT_TRACE2(( "SFNT driver\n" ));
@@ -692,6 +698,9 @@
instance_offset += instance_size;
}
+ /* named instance indices start with value 1 */
+ face->var_default_named_instance = i + 1;
+
if ( i == num_instances )
{
/* no default instance in named instance table; */
@@ -1054,6 +1063,16 @@
GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
}
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ {
+ FT_Memory memory = face->root.memory;
+
+
+ if ( FT_STRDUP( face->non_var_style_name, face->root.style_name ) )
+ goto Exit;
+ }
+#endif
+
/* now set up root fields */
{
FT_Face root = &face->root;
@@ -1221,7 +1240,7 @@
if ( count > 0 )
{
- FT_Memory memory = face->root.stream->memory;
+ FT_Memory memory = face->root.memory;
FT_UShort em_size = face->header.Units_Per_EM;
FT_Short avgwidth = face->os2.xAvgCharWidth;
FT_Size_Metrics metrics;
@@ -1500,6 +1519,7 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_FREE( face->var_postscript_prefix );
+ FT_FREE( face->non_var_style_name );
#endif
/* freeing glyph color palette data */
diff --git a/thirdparty/freetype/src/sfnt/sfwoff.c b/thirdparty/freetype/src/sfnt/sfwoff.c
index 9559bf3421..7c0ce2205e 100644
--- a/thirdparty/freetype/src/sfnt/sfwoff.c
+++ b/thirdparty/freetype/src/sfnt/sfwoff.c
@@ -426,7 +426,7 @@
#else /* !FT_CONFIG_OPTION_USE_ZLIB */
/* ANSI C doesn't like empty source files */
- typedef int _sfwoff_dummy;
+ typedef int sfwoff_dummy_;
#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
diff --git a/thirdparty/freetype/src/sfnt/sfwoff2.c b/thirdparty/freetype/src/sfnt/sfwoff2.c
index 7a01977f86..49ad5cc811 100644
--- a/thirdparty/freetype/src/sfnt/sfwoff2.c
+++ b/thirdparty/freetype/src/sfnt/sfwoff2.c
@@ -2378,7 +2378,7 @@
#else /* !FT_CONFIG_OPTION_USE_BROTLI */
/* ANSI C doesn't like empty source files */
- typedef int _sfwoff2_dummy;
+ typedef int sfwoff2_dummy_;
#endif /* !FT_CONFIG_OPTION_USE_BROTLI */
diff --git a/thirdparty/freetype/src/sfnt/ttbdf.c b/thirdparty/freetype/src/sfnt/ttbdf.c
index 118f475e7f..536fa7467e 100644
--- a/thirdparty/freetype/src/sfnt/ttbdf.c
+++ b/thirdparty/freetype/src/sfnt/ttbdf.c
@@ -136,13 +136,14 @@
FT_LOCAL_DEF( FT_Error )
- tt_face_find_bdf_prop( TT_Face face,
+ tt_face_find_bdf_prop( FT_Face face, /* TT_Face */
const char* property_name,
BDF_PropertyRec *aprop )
{
- TT_BDF bdf = &face->bdf;
- FT_Size size = FT_FACE( face )->size;
- FT_Error error = FT_Err_Ok;
+ TT_Face ttface = (TT_Face)face;
+ TT_BDF bdf = &ttface->bdf;
+ FT_Size size = FT_FACE_SIZE( face );
+ FT_Error error = FT_Err_Ok;
FT_Byte* p;
FT_UInt count;
FT_Byte* strike;
@@ -153,7 +154,7 @@
if ( bdf->loaded == 0 )
{
- error = tt_face_load_bdf_props( face, FT_FACE( face )->stream );
+ error = tt_face_load_bdf_props( ttface, FT_FACE_STREAM( face ) );
if ( error )
goto Exit;
}
@@ -248,7 +249,7 @@
#else /* !TT_CONFIG_OPTION_BDF */
/* ANSI C doesn't like empty source files */
- typedef int _tt_bdf_dummy;
+ typedef int tt_bdf_dummy_;
#endif /* !TT_CONFIG_OPTION_BDF */
diff --git a/thirdparty/freetype/src/sfnt/ttbdf.h b/thirdparty/freetype/src/sfnt/ttbdf.h
index 595aeb76c2..0d7a0acecc 100644
--- a/thirdparty/freetype/src/sfnt/ttbdf.h
+++ b/thirdparty/freetype/src/sfnt/ttbdf.h
@@ -34,7 +34,7 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
- tt_face_find_bdf_prop( TT_Face face,
+ tt_face_find_bdf_prop( FT_Face face,
const char* property_name,
BDF_PropertyRec *aprop );
diff --git a/thirdparty/freetype/src/sfnt/ttcmap.c b/thirdparty/freetype/src/sfnt/ttcmap.c
index 820cd08e6d..9ba25dcbc1 100644
--- a/thirdparty/freetype/src/sfnt/ttcmap.c
+++ b/thirdparty/freetype/src/sfnt/ttcmap.c
@@ -59,10 +59,14 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap_init( TT_CMap cmap,
- FT_Byte* table )
+ tt_cmap_init( FT_CMap cmap, /* TT_CMap */
+ void* table_ )
{
- cmap->data = table;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
+
+
+ ttcmap->data = table;
return FT_Err_Ok;
}
@@ -128,21 +132,23 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap0_char_index( TT_CMap cmap,
+ tt_cmap0_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
return char_code < 256 ? table[6 + char_code] : 0;
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap0_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap0_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt32 charcode = *pchar_code;
FT_UInt32 result = 0;
FT_UInt gindex = 0;
@@ -165,10 +171,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap0_get_info( TT_CMap cmap,
+ tt_cmap0_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 4;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 4;
cmap_info->format = 0;
@@ -453,10 +460,11 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap2_char_index( TT_CMap cmap,
+ tt_cmap2_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt result = 0;
FT_Byte* subheader;
@@ -491,11 +499,12 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap2_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap2_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pcharcode )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt gindex = 0;
FT_UInt32 result = 0;
FT_UInt32 charcode = *pcharcode + 1;
@@ -579,10 +588,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap2_get_info( TT_CMap cmap,
+ tt_cmap2_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 4;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 4;
cmap_info->format = 2;
@@ -706,18 +716,20 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap4_init( TT_CMap4 cmap,
- FT_Byte* table )
+ tt_cmap4_init( FT_CMap cmap, /* TT_CMap4 */
+ void* table_ )
{
+ TT_CMap4 ttcmap = (TT_CMap4)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
FT_Byte* p;
- cmap->cmap.data = table;
+ ttcmap->cmap.data = table;
- p = table + 6;
- cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1;
- cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
- cmap->cur_gindex = 0;
+ p = table + 6;
+ ttcmap->num_ranges = FT_PEEK_USHORT( p ) >> 1;
+ ttcmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
+ ttcmap->cur_gindex = 0;
return FT_Err_Ok;
}
@@ -755,7 +767,7 @@
cmap->cur_start == 0xFFFFU &&
cmap->cur_end == 0xFFFFU )
{
- TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
FT_Byte* limit = face->cmap_table + face->cmap_size;
@@ -788,15 +800,12 @@
static void
tt_cmap4_next( TT_CMap4 cmap )
{
- TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
FT_Byte* limit = face->cmap_table + face->cmap_size;
FT_UInt charcode;
- if ( cmap->cur_charcode >= 0xFFFFUL )
- goto Fail;
-
charcode = (FT_UInt)cmap->cur_charcode + 1;
if ( charcode < cmap->cur_start )
@@ -882,7 +891,6 @@
charcode = cmap->cur_start;
}
- Fail:
cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
cmap->cur_gindex = 0;
}
@@ -1097,32 +1105,26 @@
FT_UInt32* pcharcode,
FT_Bool next )
{
- TT_Face face = (TT_Face)cmap->cmap.charmap.face;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
FT_Byte* limit = face->cmap_table + face->cmap_size;
FT_UInt num_segs2, start, end, offset;
FT_Int delta;
FT_UInt i, num_segs;
- FT_UInt32 charcode = *pcharcode;
+ FT_UInt32 charcode = *pcharcode + next;
FT_UInt gindex = 0;
FT_Byte* p;
FT_Byte* q;
p = cmap->data + 6;
- num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
-
- num_segs = num_segs2 >> 1;
+ num_segs = TT_PEEK_USHORT( p ) >> 1;
if ( !num_segs )
return 0;
- if ( next )
- charcode++;
-
- if ( charcode > 0xFFFFU )
- return 0;
+ num_segs2 = num_segs << 1;
/* linear search */
p = cmap->data + 14; /* ends table */
@@ -1232,37 +1234,30 @@
FT_UInt32* pcharcode,
FT_Bool next )
{
- TT_Face face = (TT_Face)cmap->cmap.charmap.face;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
FT_Byte* limit = face->cmap_table + face->cmap_size;
FT_UInt num_segs2, start, end, offset;
FT_Int delta;
FT_UInt max, min, mid, num_segs;
- FT_UInt charcode = (FT_UInt)*pcharcode;
+ FT_UInt charcode = (FT_UInt)*pcharcode + next;
FT_UInt gindex = 0;
FT_Byte* p;
p = cmap->data + 6;
- num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
+ num_segs = TT_PEEK_USHORT( p ) >> 1;
- if ( !num_segs2 )
+ if ( !num_segs )
return 0;
- num_segs = num_segs2 >> 1;
-
- /* make compiler happy */
- mid = num_segs;
- end = 0xFFFFU;
-
- if ( next )
- charcode++;
+ num_segs2 = num_segs << 1;
min = 0;
max = num_segs;
/* binary search */
- while ( min < max )
+ do
{
mid = ( min + max ) >> 1;
p = cmap->data + 14 + mid * 2;
@@ -1445,6 +1440,7 @@
break;
}
}
+ while ( min < max );
if ( next )
{
@@ -1454,12 +1450,8 @@
/* if `charcode' is not in any segment, then `mid' is */
/* the segment nearest to `charcode' */
- if ( charcode > end )
- {
- mid++;
- if ( mid == num_segs )
- return 0;
- }
+ if ( charcode > end && ++mid == num_segs )
+ return 0;
if ( tt_cmap4_set_range( cmap4, mid ) )
{
@@ -1474,7 +1466,6 @@
cmap4->cur_gindex = gindex;
else
{
- cmap4->cur_charcode = charcode;
tt_cmap4_next( cmap4 );
gindex = cmap4->cur_gindex;
}
@@ -1489,31 +1480,35 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap4_char_index( TT_CMap cmap,
+ tt_cmap4_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
+ TT_CMap ttcmap = (TT_CMap)cmap;
+
+
if ( char_code >= 0x10000UL )
return 0;
- if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
- return tt_cmap4_char_map_linear( cmap, &char_code, 0 );
+ if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED )
+ return tt_cmap4_char_map_linear( ttcmap, &char_code, 0 );
else
- return tt_cmap4_char_map_binary( cmap, &char_code, 0 );
+ return tt_cmap4_char_map_binary( ttcmap, &char_code, 0 );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap4_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap4_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
+ TT_CMap ttcmap = (TT_CMap)cmap;
FT_UInt gindex;
if ( *pchar_code >= 0xFFFFU )
return 0;
- if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
- gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 );
+ if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED )
+ gindex = tt_cmap4_char_map_linear( ttcmap, pchar_code, 1 );
else
{
TT_CMap4 cmap4 = (TT_CMap4)cmap;
@@ -1528,7 +1523,7 @@
*pchar_code = cmap4->cur_charcode;
}
else
- gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 );
+ gindex = tt_cmap4_char_map_binary( ttcmap, pchar_code, 1 );
}
return gindex;
@@ -1536,10 +1531,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap4_get_info( TT_CMap cmap,
+ tt_cmap4_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 4;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 4;
cmap_info->format = 4;
@@ -1640,10 +1636,11 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap6_char_index( TT_CMap cmap,
+ tt_cmap6_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt result = 0;
FT_Byte* p = table + 6;
FT_UInt start = TT_NEXT_USHORT( p );
@@ -1661,11 +1658,12 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap6_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap6_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt32 result = 0;
FT_UInt32 char_code = *pchar_code + 1;
FT_UInt gindex = 0;
@@ -1706,10 +1704,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap6_get_info( TT_CMap cmap,
+ tt_cmap6_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 4;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 4;
cmap_info->format = 6;
@@ -1900,10 +1899,11 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap8_char_index( TT_CMap cmap,
+ tt_cmap8_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt result = 0;
FT_Byte* p = table + 8204;
FT_UInt32 num_groups = TT_NEXT_ULONG( p );
@@ -1932,15 +1932,16 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap8_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap8_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
- FT_Face face = cmap->cmap.charmap.face;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
FT_UInt32 result = 0;
FT_UInt32 char_code;
FT_UInt gindex = 0;
- FT_Byte* table = cmap->data;
+ FT_Byte* table = ttcmap->data;
FT_Byte* p = table + 8204;
FT_UInt32 num_groups = TT_NEXT_ULONG( p );
FT_UInt32 start, end, start_id;
@@ -2000,10 +2001,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap8_get_info( TT_CMap cmap,
+ tt_cmap8_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 8;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 8;
cmap_info->format = 8;
@@ -2104,10 +2106,11 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap10_char_index( TT_CMap cmap,
+ tt_cmap10_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt result = 0;
FT_Byte* p = table + 12;
FT_UInt32 start = TT_NEXT_ULONG( p );
@@ -2130,11 +2133,12 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap10_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap10_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt32 char_code;
FT_UInt gindex = 0;
FT_Byte* p = table + 12;
@@ -2172,10 +2176,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap10_get_info( TT_CMap cmap,
+ tt_cmap10_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 8;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 8;
cmap_info->format = 10;
@@ -2253,15 +2258,19 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap12_init( TT_CMap12 cmap,
- FT_Byte* table )
+ tt_cmap12_init( FT_CMap cmap, /* TT_CMap12 */
+ void* table_ )
{
- cmap->cmap.data = table;
+ TT_CMap12 ttcmap = (TT_CMap12)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
+
- table += 12;
- cmap->num_groups = FT_PEEK_ULONG( table );
+ ttcmap->cmap.data = table;
- cmap->valid = 0;
+ table += 12;
+ ttcmap->num_groups = FT_PEEK_ULONG( table );
+
+ ttcmap->valid = 0;
return FT_Err_Ok;
}
@@ -2331,23 +2340,21 @@
/* cmap->cur_group should be set up properly by caller */
/* */
static void
- tt_cmap12_next( TT_CMap12 cmap )
+ tt_cmap12_next( FT_CMap cmap ) /* TT_CMap12 */
{
- FT_Face face = cmap->cmap.cmap.charmap.face;
- FT_Byte* p;
- FT_ULong start, end, start_id, char_code;
- FT_ULong n;
- FT_UInt gindex;
-
+ TT_CMap12 ttcmap = (TT_CMap12)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Byte* p;
+ FT_ULong start, end, start_id, char_code;
+ FT_ULong n;
+ FT_UInt gindex;
- if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
- goto Fail;
- char_code = cmap->cur_charcode + 1;
+ char_code = ttcmap->cur_charcode + 1;
- for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
+ for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ )
{
- p = cmap->cmap.data + 16 + 12 * n;
+ p = ttcmap->cmap.data + 16 + 12 * n;
start = TT_NEXT_ULONG( p );
end = TT_NEXT_ULONG( p );
start_id = TT_PEEK_ULONG( p );
@@ -2379,16 +2386,16 @@
if ( gindex >= (FT_UInt)face->num_glyphs )
continue;
- cmap->cur_charcode = char_code;
- cmap->cur_gindex = gindex;
- cmap->cur_group = n;
+ ttcmap->cur_charcode = char_code;
+ ttcmap->cur_gindex = gindex;
+ ttcmap->cur_group = n;
return;
}
}
Fail:
- cmap->valid = 0;
+ ttcmap->valid = 0;
}
@@ -2400,7 +2407,7 @@
FT_UInt gindex = 0;
FT_Byte* p = cmap->data + 12;
FT_UInt32 num_groups = TT_PEEK_ULONG( p );
- FT_UInt32 char_code = *pchar_code;
+ FT_UInt32 char_code = *pchar_code + next;
FT_UInt32 start, end, start_id;
FT_UInt32 max, min, mid;
@@ -2408,23 +2415,11 @@
if ( !num_groups )
return 0;
- /* make compiler happy */
- mid = num_groups;
- end = 0xFFFFFFFFUL;
-
- if ( next )
- {
- if ( char_code >= 0xFFFFFFFFUL )
- return 0;
-
- char_code++;
- }
-
min = 0;
max = num_groups;
/* binary search */
- while ( min < max )
+ do
{
mid = ( min + max ) >> 1;
p = cmap->data + 16 + 12 * mid;
@@ -2448,22 +2443,19 @@
break;
}
}
+ while ( min < max );
if ( next )
{
- FT_Face face = cmap->cmap.charmap.face;
+ FT_Face face = FT_CMAP_FACE( cmap );
TT_CMap12 cmap12 = (TT_CMap12)cmap;
/* if `char_code' is not in any group, then `mid' is */
/* the group nearest to `char_code' */
- if ( char_code > end )
- {
- mid++;
- if ( mid == num_groups )
- return 0;
- }
+ if ( char_code > end && ++mid == num_groups )
+ return 0;
cmap12->valid = 1;
cmap12->cur_charcode = char_code;
@@ -2474,7 +2466,7 @@
if ( !gindex )
{
- tt_cmap12_next( cmap12 );
+ tt_cmap12_next( FT_CMAP( cmap12 ) );
if ( cmap12->valid )
gindex = cmap12->cur_gindex;
@@ -2490,25 +2482,28 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap12_char_index( TT_CMap cmap,
+ tt_cmap12_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- return tt_cmap12_char_map_binary( cmap, &char_code, 0 );
+ return tt_cmap12_char_map_binary( (TT_CMap)cmap, &char_code, 0 );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap12_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap12_char_next( FT_CMap cmap, /* TT_CMap12 */
FT_UInt32 *pchar_code )
{
TT_CMap12 cmap12 = (TT_CMap12)cmap;
FT_UInt gindex;
+ if ( *pchar_code >= 0xFFFFFFFFUL )
+ return 0;
+
/* no need to search */
if ( cmap12->valid && cmap12->cur_charcode == *pchar_code )
{
- tt_cmap12_next( cmap12 );
+ tt_cmap12_next( FT_CMAP( cmap12 ) );
if ( cmap12->valid )
{
gindex = cmap12->cur_gindex;
@@ -2518,17 +2513,18 @@
gindex = 0;
}
else
- gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 );
+ gindex = tt_cmap12_char_map_binary( (TT_CMap)cmap, pchar_code, 1 );
return gindex;
}
FT_CALLBACK_DEF( FT_Error )
- tt_cmap12_get_info( TT_CMap cmap,
+ tt_cmap12_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 8;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 8;
cmap_info->format = 12;
@@ -2606,15 +2602,19 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap13_init( TT_CMap13 cmap,
- FT_Byte* table )
+ tt_cmap13_init( FT_CMap cmap, /* TT_CMap13 */
+ void* table_ )
{
- cmap->cmap.data = table;
+ TT_CMap13 ttcmap = (TT_CMap13)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
+
+
+ ttcmap->cmap.data = table;
- table += 12;
- cmap->num_groups = FT_PEEK_ULONG( table );
+ table += 12;
+ ttcmap->num_groups = FT_PEEK_ULONG( table );
- cmap->valid = 0;
+ ttcmap->valid = 0;
return FT_Err_Ok;
}
@@ -2679,23 +2679,21 @@
/* cmap->cur_group should be set up properly by caller */
/* */
static void
- tt_cmap13_next( TT_CMap13 cmap )
+ tt_cmap13_next( FT_CMap cmap ) /* TT_CMap13 */
{
- FT_Face face = cmap->cmap.cmap.charmap.face;
- FT_Byte* p;
- FT_ULong start, end, glyph_id, char_code;
- FT_ULong n;
- FT_UInt gindex;
-
+ TT_CMap13 ttcmap = (TT_CMap13)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Byte* p;
+ FT_ULong start, end, glyph_id, char_code;
+ FT_ULong n;
+ FT_UInt gindex;
- if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
- goto Fail;
- char_code = cmap->cur_charcode + 1;
+ char_code = ttcmap->cur_charcode + 1;
- for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
+ for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ )
{
- p = cmap->cmap.data + 16 + 12 * n;
+ p = ttcmap->cmap.data + 16 + 12 * n;
start = TT_NEXT_ULONG( p );
end = TT_NEXT_ULONG( p );
glyph_id = TT_PEEK_ULONG( p );
@@ -2709,17 +2707,16 @@
if ( gindex && gindex < (FT_UInt)face->num_glyphs )
{
- cmap->cur_charcode = char_code;
- cmap->cur_gindex = gindex;
- cmap->cur_group = n;
+ ttcmap->cur_charcode = char_code;
+ ttcmap->cur_gindex = gindex;
+ ttcmap->cur_group = n;
return;
}
}
}
- Fail:
- cmap->valid = 0;
+ ttcmap->valid = 0;
}
@@ -2731,7 +2728,7 @@
FT_UInt gindex = 0;
FT_Byte* p = cmap->data + 12;
FT_UInt32 num_groups = TT_PEEK_ULONG( p );
- FT_UInt32 char_code = *pchar_code;
+ FT_UInt32 char_code = *pchar_code + next;
FT_UInt32 start, end;
FT_UInt32 max, min, mid;
@@ -2739,23 +2736,11 @@
if ( !num_groups )
return 0;
- /* make compiler happy */
- mid = num_groups;
- end = 0xFFFFFFFFUL;
-
- if ( next )
- {
- if ( char_code >= 0xFFFFFFFFUL )
- return 0;
-
- char_code++;
- }
-
min = 0;
max = num_groups;
/* binary search */
- while ( min < max )
+ do
{
mid = ( min + max ) >> 1;
p = cmap->data + 16 + 12 * mid;
@@ -2774,6 +2759,7 @@
break;
}
}
+ while ( min < max );
if ( next )
{
@@ -2784,12 +2770,8 @@
/* if `char_code' is not in any group, then `mid' is */
/* the group nearest to `char_code' */
- if ( char_code > end )
- {
- mid++;
- if ( mid == num_groups )
- return 0;
- }
+ if ( char_code > end && ++mid == num_groups )
+ return 0;
cmap13->valid = 1;
cmap13->cur_charcode = char_code;
@@ -2800,7 +2782,7 @@
if ( !gindex )
{
- tt_cmap13_next( cmap13 );
+ tt_cmap13_next( FT_CMAP( cmap13 ) );
if ( cmap13->valid )
gindex = cmap13->cur_gindex;
@@ -2816,25 +2798,28 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap13_char_index( TT_CMap cmap,
+ tt_cmap13_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- return tt_cmap13_char_map_binary( cmap, &char_code, 0 );
+ return tt_cmap13_char_map_binary( (TT_CMap)cmap, &char_code, 0 );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap13_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap13_char_next( FT_CMap cmap, /* TT_CMap13 */
FT_UInt32 *pchar_code )
{
TT_CMap13 cmap13 = (TT_CMap13)cmap;
FT_UInt gindex;
+ if ( *pchar_code >= 0xFFFFFFFFUL )
+ return 0;
+
/* no need to search */
if ( cmap13->valid && cmap13->cur_charcode == *pchar_code )
{
- tt_cmap13_next( cmap13 );
+ tt_cmap13_next( FT_CMAP( cmap13 ) );
if ( cmap13->valid )
{
gindex = cmap13->cur_gindex;
@@ -2844,17 +2829,18 @@
gindex = 0;
}
else
- gindex = tt_cmap13_char_map_binary( cmap, pchar_code, 1 );
+ gindex = tt_cmap13_char_map_binary( (TT_CMap)cmap, pchar_code, 1 );
return gindex;
}
FT_CALLBACK_DEF( FT_Error )
- tt_cmap13_get_info( TT_CMap cmap,
+ tt_cmap13_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 8;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 8;
cmap_info->format = 13;
@@ -2969,14 +2955,15 @@
FT_CALLBACK_DEF( void )
- tt_cmap14_done( TT_CMap14 cmap )
+ tt_cmap14_done( FT_CMap cmap ) /* TT_CMap14 */
{
- FT_Memory memory = cmap->memory;
+ TT_CMap14 ttcmap = (TT_CMap14)cmap;
+ FT_Memory memory = ttcmap->memory;
- cmap->max_results = 0;
- if ( memory && cmap->results )
- FT_FREE( cmap->results );
+ ttcmap->max_results = 0;
+ if ( memory && ttcmap->results )
+ FT_FREE( ttcmap->results );
}
@@ -3004,15 +2991,19 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap14_init( TT_CMap14 cmap,
- FT_Byte* table )
+ tt_cmap14_init( FT_CMap cmap, /* TT_CMap14 */
+ void* table_ )
{
- cmap->cmap.data = table;
+ TT_CMap14 ttcmap = (TT_CMap14)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
+
- table += 6;
- cmap->num_selectors = FT_PEEK_ULONG( table );
- cmap->max_results = 0;
- cmap->results = NULL;
+ ttcmap->cmap.data = table;
+
+ table += 6;
+ ttcmap->num_selectors = FT_PEEK_ULONG( table );
+ ttcmap->max_results = 0;
+ ttcmap->results = NULL;
return FT_Err_Ok;
}
@@ -3142,7 +3133,7 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap14_char_index( TT_CMap cmap,
+ tt_cmap14_char_index( FT_CMap cmap,
FT_UInt32 char_code )
{
FT_UNUSED( cmap );
@@ -3153,8 +3144,8 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap14_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap14_char_next( FT_CMap cmap,
FT_UInt32 *pchar_code )
{
FT_UNUSED( cmap );
@@ -3166,7 +3157,7 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap14_get_info( TT_CMap cmap,
+ tt_cmap14_get_info( FT_CharMap cmap,
TT_CMapInfo *cmap_info )
{
FT_UNUSED( cmap );
@@ -3280,12 +3271,16 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap14_char_var_index( TT_CMap cmap,
- TT_CMap ucmap,
+ tt_cmap14_char_var_index( FT_CMap cmap, /* TT_CMap */
+ FT_CMap ucmap, /* TT_CMap */
FT_UInt32 charcode,
FT_UInt32 variantSelector )
{
- FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ TT_CMap ttucmap = (TT_CMap)ucmap;
+
+ FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6,
+ variantSelector );
FT_ULong defOff;
FT_ULong nondefOff;
@@ -3296,16 +3291,16 @@
defOff = TT_NEXT_ULONG( p );
nondefOff = TT_PEEK_ULONG( p );
- if ( defOff != 0 &&
- tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+ if ( defOff != 0 &&
+ tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) )
{
/* This is the default variant of this charcode. GID not stored */
/* here; stored in the normal Unicode charmap instead. */
- return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode );
+ return ttucmap->cmap.clazz->char_index( &ttucmap->cmap, charcode );
}
if ( nondefOff != 0 )
- return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
+ return tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff,
charcode );
return 0;
@@ -3313,11 +3308,13 @@
FT_CALLBACK_DEF( FT_Int )
- tt_cmap14_char_var_isdefault( TT_CMap cmap,
+ tt_cmap14_char_var_isdefault( FT_CMap cmap, /* TT_CMap */
FT_UInt32 charcode,
FT_UInt32 variantSelector )
{
- FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6,
+ variantSelector );
FT_ULong defOff;
FT_ULong nondefOff;
@@ -3328,13 +3325,13 @@
defOff = TT_NEXT_ULONG( p );
nondefOff = TT_NEXT_ULONG( p );
- if ( defOff != 0 &&
- tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+ if ( defOff != 0 &&
+ tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) )
return 1;
- if ( nondefOff != 0 &&
- tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
- charcode ) != 0 )
+ if ( nondefOff != 0 &&
+ tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff,
+ charcode ) != 0 )
return 0;
return -1;
@@ -3342,12 +3339,13 @@
FT_CALLBACK_DEF( FT_UInt32* )
- tt_cmap14_variants( TT_CMap cmap,
+ tt_cmap14_variants( FT_CMap cmap, /* TT_CMap14 */
FT_Memory memory )
{
+ TT_CMap ttcmap = (TT_CMap)cmap;
TT_CMap14 cmap14 = (TT_CMap14)cmap;
FT_UInt32 count = cmap14->num_selectors;
- FT_Byte* p = cmap->data + 10;
+ FT_Byte* p = ttcmap->data + 10;
FT_UInt32* result;
FT_UInt32 i;
@@ -3368,13 +3366,14 @@
FT_CALLBACK_DEF( FT_UInt32 * )
- tt_cmap14_char_variants( TT_CMap cmap,
+ tt_cmap14_char_variants( FT_CMap cmap, /* TT_CMap14 */
FT_Memory memory,
FT_UInt32 charCode )
{
- TT_CMap14 cmap14 = (TT_CMap14) cmap;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ TT_CMap14 cmap14 = (TT_CMap14)cmap;
FT_UInt32 count = cmap14->num_selectors;
- FT_Byte* p = cmap->data + 10;
+ FT_Byte* p = ttcmap->data + 10;
FT_UInt32* q;
@@ -3388,12 +3387,12 @@
FT_ULong nondefOff = TT_NEXT_ULONG( p );
- if ( ( defOff != 0 &&
- tt_cmap14_char_map_def_binary( cmap->data + defOff,
- charCode ) ) ||
- ( nondefOff != 0 &&
- tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
- charCode ) != 0 ) )
+ if ( ( defOff != 0 &&
+ tt_cmap14_char_map_def_binary( ttcmap->data + defOff,
+ charCode ) ) ||
+ ( nondefOff != 0 &&
+ tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff,
+ charCode ) != 0 ) )
{
q[0] = varSel;
q++;
@@ -3489,15 +3488,16 @@
FT_CALLBACK_DEF( FT_UInt32 * )
- tt_cmap14_variant_chars( TT_CMap cmap,
+ tt_cmap14_variant_chars( FT_CMap cmap, /* TT_CMap */
FT_Memory memory,
FT_UInt32 variantSelector )
{
- FT_Byte *p = tt_cmap14_find_variant( cmap->data + 6,
- variantSelector );
- FT_Int i;
- FT_ULong defOff;
- FT_ULong nondefOff;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte *p = tt_cmap14_find_variant( ttcmap->data + 6,
+ variantSelector );
+ FT_Int i;
+ FT_ULong defOff;
+ FT_ULong nondefOff;
if ( !p )
@@ -3510,16 +3510,16 @@
return NULL;
if ( defOff == 0 )
- return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
+ return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff,
memory );
else if ( nondefOff == 0 )
- return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
+ return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff,
memory );
else
{
/* Both a default and a non-default glyph set? That's probably not */
/* good font design, but the spec allows for it... */
- TT_CMap14 cmap14 = (TT_CMap14) cmap;
+ TT_CMap14 cmap14 = (TT_CMap14)cmap;
FT_UInt32 numRanges;
FT_UInt32 numMappings;
FT_UInt32 duni;
@@ -3531,18 +3531,18 @@
FT_UInt32 *ret;
- p = cmap->data + nondefOff;
- dp = cmap->data + defOff;
+ p = ttcmap->data + nondefOff;
+ dp = ttcmap->data + defOff;
numMappings = (FT_UInt32)TT_NEXT_ULONG( p );
dcnt = tt_cmap14_def_char_count( dp );
numRanges = (FT_UInt32)TT_NEXT_ULONG( dp );
if ( numMappings == 0 )
- return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
+ return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff,
memory );
if ( dcnt == 0 )
- return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
+ return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff,
memory );
if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) )
@@ -3664,9 +3664,10 @@
#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
FT_CALLBACK_DEF( const char * )
- tt_get_glyph_name( TT_Face face,
+ tt_get_glyph_name( void* face_, /* TT_Face */
FT_UInt idx )
{
+ TT_Face face = (TT_Face)face_;
FT_String* PSname = NULL;
@@ -3677,12 +3678,13 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap_unicode_init( PS_Unicodes unicodes,
- FT_Pointer pointer )
+ tt_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */
+ FT_Pointer pointer )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
FT_UNUSED( pointer );
@@ -3693,17 +3695,18 @@
return psnames->unicodes_init( memory,
unicodes,
face->root.num_glyphs,
- (PS_GetGlyphNameFunc)&tt_get_glyph_name,
+ &tt_get_glyph_name,
(PS_FreeGlyphNameFunc)NULL,
(FT_Pointer)face );
}
FT_CALLBACK_DEF( void )
- tt_cmap_unicode_done( PS_Unicodes unicodes )
+ tt_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */
{
- FT_Face face = FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_FREE( unicodes->maps );
@@ -3712,23 +3715,25 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap_unicode_char_index( PS_Unicodes unicodes,
- FT_UInt32 char_code )
+ tt_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 char_code )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
return psnames->unicodes_char_index( unicodes, char_code );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap_unicode_char_next( PS_Unicodes unicodes,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 *pchar_code )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
return psnames->unicodes_char_next( unicodes, pchar_code );
@@ -3883,7 +3888,7 @@
tt_get_cmap_info( FT_CharMap charmap,
TT_CMapInfo *cmap_info )
{
- FT_CMap cmap = (FT_CMap)charmap;
+ FT_CMap cmap = FT_CMAP( charmap );
TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz;
diff --git a/thirdparty/freetype/src/sfnt/ttcolr.c b/thirdparty/freetype/src/sfnt/ttcolr.c
index 5d98dcab8f..69ccf0ee7a 100644
--- a/thirdparty/freetype/src/sfnt/ttcolr.c
+++ b/thirdparty/freetype/src/sfnt/ttcolr.c
@@ -699,7 +699,7 @@
item_deltas ) )
return 0;
- apaint->u.solid.color.alpha += item_deltas[0];
+ apaint->u.solid.color.alpha += (FT_F2Dot14)item_deltas[0];
}
#endif
@@ -1646,7 +1646,7 @@
return 0;
color_stop->stop_offset += F2DOT14_TO_FIXED( item_deltas[0] );
- color_stop->color.alpha += item_deltas[1];
+ color_stop->color.alpha += (FT_F2Dot14)item_deltas[1];
}
#else
FT_UNUSED( var_index_base );
@@ -1914,7 +1914,7 @@
#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
/* ANSI C doesn't like empty source files */
- typedef int _tt_colr_dummy;
+ typedef int tt_colr_dummy_;
#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
diff --git a/thirdparty/freetype/src/sfnt/ttcpal.c b/thirdparty/freetype/src/sfnt/ttcpal.c
index 4279bc0bd1..46ae08596f 100644
--- a/thirdparty/freetype/src/sfnt/ttcpal.c
+++ b/thirdparty/freetype/src/sfnt/ttcpal.c
@@ -303,7 +303,7 @@
#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
/* ANSI C doesn't like empty source files */
- typedef int _tt_cpal_dummy;
+ typedef int tt_cpal_dummy_;
#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
diff --git a/thirdparty/freetype/src/sfnt/ttload.c b/thirdparty/freetype/src/sfnt/ttload.c
index 14f625c824..7b44e9cd2e 100644
--- a/thirdparty/freetype/src/sfnt/ttload.c
+++ b/thirdparty/freetype/src/sfnt/ttload.c
@@ -504,6 +504,13 @@
FT_FRAME_EXIT();
+ if ( !valid_entries )
+ {
+ FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" ));
+ error = FT_THROW( Unknown_File_Format );
+ goto Exit;
+ }
+
FT_TRACE2(( "table directory loaded\n" ));
FT_TRACE2(( "\n" ));
diff --git a/thirdparty/freetype/src/sfnt/ttmtx.c b/thirdparty/freetype/src/sfnt/ttmtx.c
index 5e53e6dd4a..38ee9ae728 100644
--- a/thirdparty/freetype/src/sfnt/ttmtx.c
+++ b/thirdparty/freetype/src/sfnt/ttmtx.c
@@ -239,7 +239,7 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_Service_MetricsVariations var =
- (FT_Service_MetricsVariations)face->var;
+ (FT_Service_MetricsVariations)face->tt_var;
#endif
diff --git a/thirdparty/freetype/src/sfnt/ttpost.c b/thirdparty/freetype/src/sfnt/ttpost.c
index 0e17c6f34a..1dfad4298b 100644
--- a/thirdparty/freetype/src/sfnt/ttpost.c
+++ b/thirdparty/freetype/src/sfnt/ttpost.c
@@ -156,86 +156,66 @@
static FT_Error
- load_format_20( TT_Face face,
- FT_Stream stream,
- FT_ULong post_len )
+ load_format_20( TT_Post_Names names,
+ FT_Stream stream,
+ FT_UShort num_glyphs,
+ FT_ULong post_len )
{
FT_Memory memory = stream->memory;
FT_Error error;
- FT_Int num_glyphs;
- FT_UShort num_names;
+ FT_UShort n;
+ FT_UShort num_names = 0;
FT_UShort* glyph_indices = NULL;
- FT_Char** name_strings = NULL;
- FT_Byte* strings = NULL;
+ FT_Byte** name_strings = NULL;
+ FT_Byte* q;
- if ( FT_READ_USHORT( num_glyphs ) )
- goto Exit;
-
- /* UNDOCUMENTED! The number of glyphs in this table can be smaller */
- /* than the value in the maxp table (cf. cyberbit.ttf). */
-
- /* There already exist fonts which have more than 32768 glyph names */
- /* in this table, so the test for this threshold has been dropped. */
-
- if ( num_glyphs > face->max_profile.numGlyphs ||
- (FT_ULong)num_glyphs * 2UL > post_len - 2 )
+ if ( (FT_ULong)num_glyphs * 2 > post_len )
{
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
- /* load the indices */
- {
- FT_Int n;
-
-
- if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
- FT_FRAME_ENTER( num_glyphs * 2L ) )
- goto Fail;
-
- for ( n = 0; n < num_glyphs; n++ )
- glyph_indices[n] = FT_GET_USHORT();
+ /* load the indices and note their maximum */
+ if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
+ FT_FRAME_ENTER( num_glyphs * 2 ) )
+ goto Fail;
- FT_FRAME_EXIT();
- }
+ q = (FT_Byte*)stream->cursor;
- /* compute number of names stored in table */
+ for ( n = 0; n < num_glyphs; n++ )
{
- FT_Int n;
+ FT_UShort idx = FT_NEXT_USHORT( q );
- num_names = 0;
+ if ( idx > num_names )
+ num_names = idx;
- for ( n = 0; n < num_glyphs; n++ )
- {
- FT_Int idx;
+ glyph_indices[n] = idx;
+ }
+ FT_FRAME_EXIT();
- idx = glyph_indices[n];
- if ( idx >= 258 )
- {
- idx -= 257;
- if ( idx > num_names )
- num_names = (FT_UShort)idx;
- }
- }
- }
+ /* compute number of names stored in the table */
+ num_names = num_names > 257 ? num_names - 257 : 0;
/* now load the name strings */
if ( num_names )
{
- FT_UShort n;
FT_ULong p;
+ FT_Byte* strings;
- post_len -= (FT_ULong)num_glyphs * 2UL + 2;
+ post_len -= (FT_ULong)num_glyphs * 2;
+
+ if ( FT_QALLOC( name_strings, num_names * sizeof ( FT_Byte* ) +
+ post_len + 1 ) )
+ goto Fail;
- if ( FT_QALLOC( strings, post_len + 1 ) ||
- FT_STREAM_READ( strings, post_len ) ||
- FT_QNEW_ARRAY( name_strings, num_names ) )
+ strings = (FT_Byte*)( name_strings + num_names );
+ if ( FT_STREAM_READ( strings, post_len ) )
goto Fail;
/* convert from Pascal- to C-strings and set pointers */
@@ -251,7 +231,7 @@
}
strings[p] = 0;
- name_strings[n] = (FT_Char*)strings + p + 1;
+ name_strings[n] = strings + p + 1;
p += len + 1;
}
strings[post_len] = 0;
@@ -259,40 +239,24 @@
/* deal with missing or insufficient string data */
if ( n < num_names )
{
- if ( post_len == 0 )
- {
- /* fake empty string */
- if ( FT_QREALLOC( strings, 1, 2 ) )
- goto Fail;
-
- post_len = 1;
- strings[post_len] = 0;
- }
+ FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n",
+ num_names - n ));
- FT_ERROR(( "load_format_20:"
- " all entries in post table are already parsed,"
- " using NULL names for gid %d - %d\n",
- n, num_names - 1 ));
for ( ; n < num_names; n++ )
- name_strings[n] = (FT_Char*)strings + post_len;
+ name_strings[n] = strings + post_len;
}
}
/* all right, set table fields and exit successfully */
- {
- TT_Post_20 table = &face->postscript_names.names.format_20;
-
+ names->num_glyphs = num_glyphs;
+ names->num_names = num_names;
+ names->glyph_indices = glyph_indices;
+ names->glyph_names = name_strings;
- table->num_glyphs = (FT_UShort)num_glyphs;
- table->num_names = (FT_UShort)num_names;
- table->glyph_indices = glyph_indices;
- table->glyph_names = name_strings;
- }
return FT_Err_Ok;
Fail:
FT_FREE( name_strings );
- FT_FREE( strings );
FT_FREE( glyph_indices );
Exit:
@@ -301,66 +265,55 @@
static FT_Error
- load_format_25( TT_Face face,
- FT_Stream stream,
- FT_ULong post_len )
+ load_format_25( TT_Post_Names names,
+ FT_Stream stream,
+ FT_UShort num_glyphs,
+ FT_ULong post_len )
{
FT_Memory memory = stream->memory;
FT_Error error;
- FT_Int num_glyphs;
- FT_Char* offset_table = NULL;
-
- FT_UNUSED( post_len );
+ FT_UShort n;
+ FT_UShort* glyph_indices = NULL;
+ FT_Byte* q;
- if ( FT_READ_USHORT( num_glyphs ) )
- goto Exit;
-
- /* check the number of glyphs */
- if ( num_glyphs > face->max_profile.numGlyphs ||
- num_glyphs > 258 ||
- num_glyphs < 1 )
+ /* check the number of glyphs, including the theoretical limit */
+ if ( num_glyphs > post_len ||
+ num_glyphs > 258 + 128 )
{
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
- if ( FT_QNEW_ARRAY( offset_table, num_glyphs ) ||
- FT_STREAM_READ( offset_table, num_glyphs ) )
+ /* load the indices and check their Mac range */
+ if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
+ FT_FRAME_ENTER( num_glyphs ) )
goto Fail;
- /* now check the offset table */
- {
- FT_Int n;
+ q = (FT_Byte*)stream->cursor;
+ for ( n = 0; n < num_glyphs; n++ )
+ {
+ FT_Int idx = n + FT_NEXT_CHAR( q );
- for ( n = 0; n < num_glyphs; n++ )
- {
- FT_Long idx = (FT_Long)n + offset_table[n];
+ if ( idx < 0 || idx > 257 )
+ idx = 0;
- if ( idx < 0 || idx > num_glyphs )
- {
- error = FT_THROW( Invalid_File_Format );
- goto Fail;
- }
- }
+ glyph_indices[n] = (FT_UShort)idx;
}
- /* OK, set table fields and exit successfully */
- {
- TT_Post_25 table = &face->postscript_names.names.format_25;
-
+ FT_FRAME_EXIT();
- table->num_glyphs = (FT_UShort)num_glyphs;
- table->offsets = offset_table;
- }
+ /* OK, set table fields and exit successfully */
+ names->num_glyphs = num_glyphs;
+ names->glyph_indices = glyph_indices;
return FT_Err_Ok;
Fail:
- FT_FREE( offset_table );
+ FT_FREE( glyph_indices );
Exit:
return error;
@@ -370,37 +323,37 @@
static FT_Error
load_post_names( TT_Face face )
{
- FT_Stream stream;
- FT_Error error;
- FT_Fixed format;
+ FT_Error error = FT_Err_Ok;
+ FT_Stream stream = face->root.stream;
+ FT_Fixed format = face->postscript.FormatType;
FT_ULong post_len;
+ FT_UShort num_glyphs;
- /* get a stream for the face's resource */
- stream = face->root.stream;
-
/* seek to the beginning of the PS names table */
error = face->goto_table( face, TTAG_post, stream, &post_len );
if ( error )
goto Exit;
- format = face->postscript.FormatType;
-
- /* go to beginning of subtable */
- if ( FT_STREAM_SKIP( 32 ) )
+ /* UNDOCUMENTED! The number of glyphs in this table can be smaller */
+ /* than the value in the maxp table (cf. cyberbit.ttf). */
+ if ( post_len < 34 ||
+ FT_STREAM_SKIP( 32 ) ||
+ FT_READ_USHORT( num_glyphs ) ||
+ num_glyphs > face->max_profile.numGlyphs ||
+ num_glyphs == 0 )
goto Exit;
- /* now read postscript table */
- if ( format == 0x00020000L && post_len >= 34 )
- error = load_format_20( face, stream, post_len - 32 );
- else if ( format == 0x00025000L && post_len >= 34 )
- error = load_format_25( face, stream, post_len - 32 );
- else
- error = FT_THROW( Invalid_File_Format );
-
- face->postscript_names.loaded = 1;
+ /* now read postscript names data */
+ if ( format == 0x00020000L )
+ error = load_format_20( &face->postscript_names, stream,
+ num_glyphs, post_len - 34 );
+ else if ( format == 0x00025000L )
+ error = load_format_25( &face->postscript_names, stream,
+ num_glyphs, post_len - 34 );
Exit:
+ face->postscript_names.loaded = 1; /* even if failed */
return error;
}
@@ -410,39 +363,20 @@
{
FT_Memory memory = face->root.memory;
TT_Post_Names names = &face->postscript_names;
- FT_Fixed format;
- if ( names->loaded )
+ if ( names->num_glyphs )
{
- format = face->postscript.FormatType;
-
- if ( format == 0x00020000L )
- {
- TT_Post_20 table = &names->names.format_20;
-
-
- FT_FREE( table->glyph_indices );
- table->num_glyphs = 0;
-
- if ( table->num_names )
- {
- table->glyph_names[0]--;
- FT_FREE( table->glyph_names[0] );
-
- FT_FREE( table->glyph_names );
- table->num_names = 0;
- }
- }
- else if ( format == 0x00025000L )
- {
- TT_Post_25 table = &names->names.format_25;
-
+ FT_FREE( names->glyph_indices );
+ names->num_glyphs = 0;
+ }
- FT_FREE( table->offsets );
- table->num_glyphs = 0;
- }
+ if ( names->num_names )
+ {
+ FT_FREE( names->glyph_names );
+ names->num_names = 0;
}
+
names->loaded = 0;
}
@@ -478,7 +412,6 @@
FT_String** PSname )
{
FT_Error error;
- TT_Post_Names names;
FT_Fixed format;
#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
@@ -498,8 +431,6 @@
return FT_THROW( Unimplemented_Feature );
#endif
- names = &face->postscript_names;
-
/* `.notdef' by default */
*PSname = MAC_NAME( 0 );
@@ -510,9 +441,10 @@
if ( idx < 258 ) /* paranoid checking */
*PSname = MAC_NAME( idx );
}
- else if ( format == 0x00020000L )
+ else if ( format == 0x00020000L ||
+ format == 0x00025000L )
{
- TT_Post_20 table = &names->names.format_20;
+ TT_Post_Names names = &face->postscript_names;
if ( !names->loaded )
@@ -522,43 +454,29 @@
goto End;
}
- if ( idx < (FT_UInt)table->num_glyphs )
+ if ( idx < (FT_UInt)names->num_glyphs )
{
- FT_UShort name_index = table->glyph_indices[idx];
+ FT_UShort name_index = names->glyph_indices[idx];
if ( name_index < 258 )
*PSname = MAC_NAME( name_index );
- else
- *PSname = (FT_String*)table->glyph_names[name_index - 258];
- }
- }
- else if ( format == 0x00025000L )
- {
- TT_Post_25 table = &names->names.format_25;
-
-
- if ( !names->loaded )
- {
- error = load_post_names( face );
- if ( error )
- goto End;
+ else /* only for version 2.0 */
+ *PSname = (FT_String*)names->glyph_names[name_index - 258];
}
-
- if ( idx < (FT_UInt)table->num_glyphs ) /* paranoid checking */
- *PSname = MAC_NAME( (FT_Int)idx + table->offsets[idx] );
}
/* nothing to do for format == 0x00030000L */
End:
+ /* post format errors ignored */
return FT_Err_Ok;
}
#else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
/* ANSI C doesn't like empty source files */
- typedef int _tt_post_dummy;
+ typedef int tt_post_dummy_;
#endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
diff --git a/thirdparty/freetype/src/sfnt/ttsbit.c b/thirdparty/freetype/src/sfnt/ttsbit.c
index 3c06955131..03f90a628d 100644
--- a/thirdparty/freetype/src/sfnt/ttsbit.c
+++ b/thirdparty/freetype/src/sfnt/ttsbit.c
@@ -1677,7 +1677,7 @@
#else /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
/* ANSI C doesn't like empty source files */
- typedef int _tt_sbit_dummy;
+ typedef int tt_sbit_dummy_;
#endif /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
diff --git a/thirdparty/freetype/src/sfnt/ttsvg.c b/thirdparty/freetype/src/sfnt/ttsvg.c
index c1bbb66b81..4461d483b0 100644
--- a/thirdparty/freetype/src/sfnt/ttsvg.c
+++ b/thirdparty/freetype/src/sfnt/ttsvg.c
@@ -405,7 +405,7 @@
#else /* !FT_CONFIG_OPTION_SVG */
/* ANSI C doesn't like empty source files */
- typedef int _tt_svg_dummy;
+ typedef int tt_svg_dummy_;
#endif /* !FT_CONFIG_OPTION_SVG */
diff --git a/thirdparty/freetype/src/sfnt/woff2tags.c b/thirdparty/freetype/src/sfnt/woff2tags.c
index 7a0a351f06..eeedd9906b 100644
--- a/thirdparty/freetype/src/sfnt/woff2tags.c
+++ b/thirdparty/freetype/src/sfnt/woff2tags.c
@@ -111,7 +111,7 @@
#else /* !FT_CONFIG_OPTION_USE_BROTLI */
/* ANSI C doesn't like empty source files */
- typedef int _woff2tags_dummy;
+ typedef int woff2tags_dummy_;
#endif /* !FT_CONFIG_OPTION_USE_BROTLI */
diff --git a/thirdparty/freetype/src/smooth/ftgrays.c b/thirdparty/freetype/src/smooth/ftgrays.c
index d9f20eef13..6252df98ae 100644
--- a/thirdparty/freetype/src/smooth/ftgrays.c
+++ b/thirdparty/freetype/src/smooth/ftgrays.c
@@ -1006,9 +1006,9 @@ typedef ptrdiff_t FT_PtrDist;
*
* For other cases, using binary splits is actually slightly faster.
*/
-#if defined( __SSE2__ ) || \
- defined( __x86_64__ ) || \
- defined( _M_AMD64 ) || \
+#if defined( __SSE2__ ) || \
+ ( defined( __x86_64__ ) && !defined( __VMS ) ) || \
+ defined( _M_AMD64 ) || \
( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 )
# define FT_SSE2 1
#else
@@ -1427,8 +1427,10 @@ typedef ptrdiff_t FT_PtrDist;
static int
gray_move_to( const FT_Vector* to,
- gray_PWorker worker )
+ void* worker_ ) /* gray_PWorker */
{
+ gray_PWorker worker = (gray_PWorker)worker_;
+
TPos x, y;
@@ -1446,8 +1448,11 @@ typedef ptrdiff_t FT_PtrDist;
static int
gray_line_to( const FT_Vector* to,
- gray_PWorker worker )
+ void* worker_ ) /* gray_PWorker */
{
+ gray_PWorker worker = (gray_PWorker)worker_;
+
+
gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
return 0;
}
@@ -1456,8 +1461,11 @@ typedef ptrdiff_t FT_PtrDist;
static int
gray_conic_to( const FT_Vector* control,
const FT_Vector* to,
- gray_PWorker worker )
+ void* worker_ ) /* gray_PWorker */
{
+ gray_PWorker worker = (gray_PWorker)worker_;
+
+
gray_render_conic( RAS_VAR_ control, to );
return 0;
}
@@ -1467,8 +1475,11 @@ typedef ptrdiff_t FT_PtrDist;
gray_cubic_to( const FT_Vector* control1,
const FT_Vector* control2,
const FT_Vector* to,
- gray_PWorker worker )
+ void* worker_ ) /* gray_PWorker */
{
+ gray_PWorker worker = (gray_PWorker)worker_;
+
+
gray_render_cubic( RAS_VAR_ control1, control2, to );
return 0;
}
@@ -1666,6 +1677,8 @@ typedef ptrdiff_t FT_PtrDist;
int n; /* index of contour in outline */
int first; /* index of first point in contour */
+ int last; /* index of last point in contour */
+
char tag; /* current point's state */
int shift;
@@ -1680,18 +1693,17 @@ typedef ptrdiff_t FT_PtrDist;
shift = func_interface->shift;
delta = func_interface->delta;
- first = 0;
+ last = -1;
for ( n = 0; n < outline->n_contours; n++ )
{
- int last; /* index of last point in contour */
-
-
- FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
+ FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n ));
+ first = last + 1;
last = outline->contours[n];
- if ( last < 0 )
+ if ( last < first )
goto Invalid_Outline;
+
limit = outline->points + last;
v_start = outline->points[first];
@@ -1874,11 +1886,9 @@ typedef ptrdiff_t FT_PtrDist;
v_start.x / 64.0, v_start.y / 64.0 ));
error = func_interface->line_to( &v_start, user );
- Close:
+ Close:
if ( error )
goto Exit;
-
- first = last + 1;
}
FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
@@ -2156,9 +2166,12 @@ typedef ptrdiff_t FT_PtrDist;
#else /* !STANDALONE_ */
static int
- gray_raster_new( FT_Memory memory,
- gray_PRaster* araster )
+ gray_raster_new( void* memory_,
+ FT_Raster* araster_ )
{
+ FT_Memory memory = (FT_Memory)memory_;
+ gray_PRaster* araster = (gray_PRaster*)araster_;
+
FT_Error error;
gray_PRaster raster = NULL;
diff --git a/thirdparty/freetype/src/smooth/ftsmooth.c b/thirdparty/freetype/src/smooth/ftsmooth.c
index cdbc78c3e5..9b0e8886cb 100644
--- a/thirdparty/freetype/src/smooth/ftsmooth.c
+++ b/thirdparty/freetype/src/smooth/ftsmooth.c
@@ -87,8 +87,10 @@
/* initialize renderer -- init its raster */
static FT_Error
- ft_smooth_init( FT_Renderer render )
+ ft_smooth_init( FT_Module module ) /* FT_Renderer */
{
+ FT_Renderer render = (FT_Renderer)module;
+
FT_Vector* sub = render->root.library->lcd_geometry;
@@ -111,8 +113,10 @@
ft_smooth_lcd_spans( int y,
int count,
const FT_Span* spans,
- TOrigin* target )
+ void* target_ ) /* TOrigin* */
{
+ TOrigin* target = (TOrigin*)target_;
+
unsigned char* dst_line = target->origin - y * target->pitch;
unsigned char* dst;
unsigned short w;
@@ -141,7 +145,7 @@
/* Set up direct rendering to record them on each third byte. */
params.source = outline;
params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
- params.gray_spans = (FT_SpanFunc)ft_smooth_lcd_spans;
+ params.gray_spans = ft_smooth_lcd_spans;
params.user = &target;
params.clip_box.xMin = 0;
@@ -256,8 +260,11 @@
/* initialize renderer -- init its raster */
static FT_Error
- ft_smooth_init( FT_Renderer render )
+ ft_smooth_init( FT_Module module ) /* FT_Renderer */
{
+ FT_Renderer render = (FT_Renderer)module;
+
+
/* set up default LCD filtering */
FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
@@ -340,8 +347,11 @@
ft_smooth_overlap_spans( int y,
int count,
const FT_Span* spans,
- TOrigin* target )
+ void* target_ )
{
+ TOrigin* target = (TOrigin*)target_;
+
+
unsigned char* dst = target->origin - ( y / SCALE ) * target->pitch;
unsigned short x;
unsigned int cover, sum;
@@ -386,7 +396,7 @@
/* Set up direct rendering to average oversampled spans. */
params.source = outline;
params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
- params.gray_spans = (FT_SpanFunc)ft_smooth_overlap_spans;
+ params.gray_spans = ft_smooth_overlap_spans;
params.user = &target;
params.clip_box.xMin = 0;
diff --git a/thirdparty/freetype/src/svg/ftsvg.c b/thirdparty/freetype/src/svg/ftsvg.c
index 7edb1a338e..ba237f6380 100644
--- a/thirdparty/freetype/src/svg/ftsvg.c
+++ b/thirdparty/freetype/src/svg/ftsvg.c
@@ -40,26 +40,31 @@
/* ft_svg_init */
static FT_Error
- ft_svg_init( SVG_Renderer svg_module )
+ ft_svg_init( FT_Module module )
{
+ SVG_Renderer render = (SVG_Renderer)module;
+
FT_Error error = FT_Err_Ok;
- svg_module->loaded = FALSE;
- svg_module->hooks_set = FALSE;
+ render->loaded = FALSE;
+ render->hooks_set = FALSE;
return error;
}
static void
- ft_svg_done( SVG_Renderer svg_module )
+ ft_svg_done( FT_Module module )
{
- if ( svg_module->loaded == TRUE &&
- svg_module->hooks_set == TRUE )
- svg_module->hooks.free_svg( &svg_module->state );
+ SVG_Renderer render = (SVG_Renderer)module;
+
+
+ if ( render->loaded == TRUE &&
+ render->hooks_set == TRUE )
+ render->hooks.free_svg( &render->state );
- svg_module->loaded = FALSE;
+ render->loaded = FALSE;
}
@@ -148,7 +153,7 @@
static const SVG_Interface svg_interface =
{
- (Preset_Bitmap_Func)ft_svg_preset_slot
+ ft_svg_preset_slot /* Preset_Bitmap_Func preset_slot */
};
@@ -203,7 +208,7 @@
static FT_Error
ft_svg_property_get( FT_Module module,
const char* property_name,
- const void* value )
+ void* value )
{
FT_Error error = FT_Err_Ok;
SVG_Renderer renderer = (SVG_Renderer)module;
@@ -226,8 +231,8 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
ft_svg_service_properties,
- (FT_Properties_SetFunc)ft_svg_property_set, /* set_property */
- (FT_Properties_GetFunc)ft_svg_property_get /* get_property */
+ ft_svg_property_set, /* FT_Properties_SetFunc set_property */
+ ft_svg_property_get /* FT_Properties_GetFunc get_property */
)
@@ -333,17 +338,17 @@
(const void*)PUT_SVG_MODULE( &svg_interface ), /* module specific interface */
- (FT_Module_Constructor)PUT_SVG_MODULE( ft_svg_init ), /* module_init */
- (FT_Module_Destructor)PUT_SVG_MODULE( ft_svg_done ), /* module_done */
- PUT_SVG_MODULE( ft_svg_get_interface ), /* get_interface */
+ PUT_SVG_MODULE( ft_svg_init ), /* FT_Module_Constructor module_init */
+ PUT_SVG_MODULE( ft_svg_done ), /* FT_Module_Destructor module_done */
+ PUT_SVG_MODULE( ft_svg_get_interface ), /* FT_Module_Requester get_interface */
SVG_GLYPH_FORMAT,
- (FT_Renderer_RenderFunc) PUT_SVG_MODULE( ft_svg_render ), /* render_glyph */
- (FT_Renderer_TransformFunc)PUT_SVG_MODULE( ft_svg_transform ), /* transform_glyph */
- NULL, /* get_glyph_cbox */
- NULL, /* set_mode */
- NULL /* raster_class */
+ PUT_SVG_MODULE( ft_svg_render ), /* FT_Renderer_RenderFunc render_glyph */
+ PUT_SVG_MODULE( ft_svg_transform ), /* FT_Renderer_TransformFunc transform_glyph */
+ NULL, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */
+ NULL, /* FT_Renderer_SetModeFunc set_mode */
+ NULL /* FT_Raster_Funcs* raster_class */
)
diff --git a/thirdparty/freetype/src/truetype/ttdriver.c b/thirdparty/freetype/src/truetype/ttdriver.c
index 4bea63ef84..7151e82073 100644
--- a/thirdparty/freetype/src/truetype/ttdriver.c
+++ b/thirdparty/freetype/src/truetype/ttdriver.c
@@ -57,7 +57,7 @@
* PROPERTY SERVICE
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
tt_property_set( FT_Module module, /* TT_Driver */
const char* property_name,
const void* value,
@@ -93,17 +93,27 @@
interpreter_version = *iv;
}
- if ( interpreter_version == TT_INTERPRETER_VERSION_35
+ switch ( interpreter_version )
+ {
+ case TT_INTERPRETER_VERSION_35:
+ driver->interpreter_version = TT_INTERPRETER_VERSION_35;
+ break;
+
+ case TT_INTERPRETER_VERSION_38:
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- || interpreter_version == TT_INTERPRETER_VERSION_38
+ driver->interpreter_version = TT_INTERPRETER_VERSION_38;
+ break;
#endif
+
+ case TT_INTERPRETER_VERSION_40:
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
- || interpreter_version == TT_INTERPRETER_VERSION_40
+ driver->interpreter_version = TT_INTERPRETER_VERSION_40;
+ break;
#endif
- )
- driver->interpreter_version = interpreter_version;
- else
+
+ default:
error = FT_ERR( Unimplemented_Feature );
+ }
return error;
}
@@ -114,10 +124,10 @@
}
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
tt_property_get( FT_Module module, /* TT_Driver */
const char* property_name,
- const void* value )
+ void* value )
{
FT_Error error = FT_Err_Ok;
TT_Driver driver = (TT_Driver)module;
@@ -144,8 +154,8 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
tt_service_properties,
- (FT_Properties_SetFunc)tt_property_set, /* set_property */
- (FT_Properties_GetFunc)tt_property_get /* get_property */
+ tt_property_set, /* FT_Properties_SetFunc set_property */
+ tt_property_get /* FT_Properties_GetFunc get_property */
)
@@ -198,35 +208,35 @@
*
* They can be implemented by format-specific interfaces.
*/
- static FT_Error
- tt_get_kerning( FT_Face ttface, /* TT_Face */
+ FT_CALLBACK_DEF( FT_Error )
+ tt_get_kerning( FT_Face face, /* TT_Face */
FT_UInt left_glyph,
FT_UInt right_glyph,
FT_Vector* kerning )
{
- TT_Face face = (TT_Face)ttface;
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ TT_Face ttface = (TT_Face)face;
+ SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
kerning->x = 0;
kerning->y = 0;
if ( sfnt )
- kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph );
+ kerning->x = sfnt->get_kerning( ttface, left_glyph, right_glyph );
return 0;
}
- static FT_Error
- tt_get_advances( FT_Face ttface,
+ FT_CALLBACK_DEF( FT_Error )
+ tt_get_advances( FT_Face face, /* TT_Face */
FT_UInt start,
FT_UInt count,
FT_Int32 flags,
FT_Fixed *advances )
{
FT_UInt nn;
- TT_Face face = (TT_Face)ttface;
+ TT_Face ttface = (TT_Face)face;
/* XXX: TODO: check for sbits */
@@ -235,8 +245,8 @@
{
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
/* no fast retrieval for blended MM fonts without VVAR table */
- if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) &&
- !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
+ if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+ !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
return FT_THROW( Unimplemented_Feature );
#endif
@@ -247,7 +257,7 @@
/* since we don't need `tsb', we use zero for `yMax' parameter */
- TT_Get_VMetrics( face, start + nn, 0, &tsb, &ah );
+ TT_Get_VMetrics( ttface, start + nn, 0, &tsb, &ah );
advances[nn] = ah;
}
}
@@ -255,8 +265,8 @@
{
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
/* no fast retrieval for blended MM fonts without HVAR table */
- if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) &&
- !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
+ if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+ !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
return FT_THROW( Unimplemented_Feature );
#endif
@@ -266,7 +276,7 @@
FT_UShort aw;
- TT_Get_HMetrics( face, start + nn, &lsb, &aw );
+ TT_Get_HMetrics( ttface, start + nn, &lsb, &aw );
advances[nn] = aw;
}
}
@@ -290,7 +300,7 @@
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
tt_size_select( FT_Size size,
FT_ULong strike_index )
{
@@ -306,7 +316,7 @@
/* use the scaled metrics, even when tt_size_reset fails */
FT_Select_Metrics( size->face, strike_index );
- tt_size_reset( ttsize, 0 ); /* ignore return value */
+ tt_size_reset( ttsize ); /* ignore return value */
}
else
{
@@ -327,7 +337,7 @@
#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
tt_size_request( FT_Size size,
FT_Size_Request req )
{
@@ -367,7 +377,7 @@
if ( FT_IS_SCALABLE( size->face ) )
{
- error = tt_size_reset( ttsize, 0 );
+ error = tt_size_reset( ttsize );
#ifdef TT_USE_BYTECODE_INTERPRETER
/* for the `MPS' bytecode instruction we need the point size */
@@ -426,15 +436,15 @@
* @Return:
* FreeType error code. 0 means success.
*/
- static FT_Error
- tt_glyph_load( FT_GlyphSlot ttslot, /* TT_GlyphSlot */
- FT_Size ttsize, /* TT_Size */
+ FT_CALLBACK_DEF( FT_Error )
+ tt_glyph_load( FT_GlyphSlot slot, /* TT_GlyphSlot */
+ FT_Size size, /* TT_Size */
FT_UInt glyph_index,
FT_Int32 load_flags )
{
- TT_GlyphSlot slot = (TT_GlyphSlot)ttslot;
- TT_Size size = (TT_Size)ttsize;
- FT_Face face = ttslot->face;
+ TT_GlyphSlot ttslot = (TT_GlyphSlot)slot;
+ TT_Size ttsize = (TT_Size)size;
+ FT_Face face = ttslot->face;
FT_Error error;
@@ -476,12 +486,12 @@
}
/* use hinted metrics only if we load a glyph with hinting */
- size->metrics = ( load_flags & FT_LOAD_NO_HINTING )
- ? &ttsize->metrics
- : &size->hinted_metrics;
+ ttsize->metrics = ( load_flags & FT_LOAD_NO_HINTING )
+ ? &size->metrics
+ : &ttsize->hinted_metrics;
/* now fill in the glyph slot with outline/bitmap/layered */
- error = TT_Load_Glyph( size, slot, glyph_index, load_flags );
+ error = TT_Load_Glyph( ttsize, ttslot, glyph_index, load_flags );
/* force drop-out mode to 2 - irrelevant now */
/* slot->outline.dropout_mode = 2; */
@@ -507,49 +517,47 @@
FT_DEFINE_SERVICE_MULTIMASTERSREC(
tt_service_gx_multi_masters,
- (FT_Get_MM_Func) NULL, /* get_mm */
- (FT_Set_MM_Design_Func) NULL, /* set_mm_design */
- (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */
- (FT_Get_MM_Blend_Func) TT_Get_MM_Blend, /* get_mm_blend */
- (FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */
- (FT_Set_Var_Design_Func)TT_Set_Var_Design, /* set_var_design */
- (FT_Get_Var_Design_Func)TT_Get_Var_Design, /* get_var_design */
- (FT_Set_Instance_Func) TT_Set_Named_Instance, /* set_instance */
- (FT_Set_MM_WeightVector_Func)
- NULL, /* set_mm_weightvector */
- (FT_Get_MM_WeightVector_Func)
- NULL, /* get_mm_weightvector */
- (FT_Var_Load_Delta_Set_Idx_Map_Func)
- tt_var_load_delta_set_index_mapping,
- /* load_delta_set_idx_map */
- (FT_Var_Load_Item_Var_Store_Func)
- tt_var_load_item_variation_store,
- /* load_item_variation_store */
- (FT_Var_Get_Item_Delta_Func)
- tt_var_get_item_delta, /* get_item_delta */
- (FT_Var_Done_Item_Var_Store_Func)
- tt_var_done_item_variation_store,
- /* done_item_variation_store */
- (FT_Var_Done_Delta_Set_Idx_Map_Func)
- tt_var_done_delta_set_index_map,
- /* done_delta_set_index_map */
- (FT_Get_Var_Blend_Func) tt_get_var_blend, /* get_var_blend */
- (FT_Done_Blend_Func) tt_done_blend /* done_blend */
+ NULL, /* FT_Get_MM_Func get_mm */
+ NULL, /* FT_Set_MM_Design_Func set_mm_design */
+ TT_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */
+ TT_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */
+ TT_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */
+ TT_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */
+ TT_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */
+ TT_Set_Named_Instance, /* FT_Set_Named_Instance_Func set_named_instance */
+ TT_Get_Default_Named_Instance,
+ /* FT_Get_Default_Named_Instance_Func get_default_named_instance */
+ NULL, /* FT_Set_MM_WeightVector_Func set_mm_weightvector */
+ NULL, /* FT_Get_MM_WeightVector_Func get_mm_weightvector */
+
+ tt_construct_ps_name, /* FT_Construct_PS_Name_Func construct_ps_name */
+ tt_var_load_delta_set_index_mapping,
+ /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */
+ tt_var_load_item_variation_store,
+ /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */
+ tt_var_get_item_delta, /* FT_Var_Get_Item_Delta_Func get_item_delta */
+ tt_var_done_item_variation_store,
+ /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */
+ tt_var_done_delta_set_index_map,
+ /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */
+ tt_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */
+ tt_done_blend /* FT_Done_Blend_Func done_blend */
)
FT_DEFINE_SERVICE_METRICSVARIATIONSREC(
tt_service_metrics_variations,
- (FT_HAdvance_Adjust_Func)tt_hadvance_adjust, /* hadvance_adjust */
- (FT_LSB_Adjust_Func) NULL, /* lsb_adjust */
- (FT_RSB_Adjust_Func) NULL, /* rsb_adjust */
+ tt_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */
+ NULL, /* FT_LSB_Adjust_Func lsb_adjust */
+ NULL, /* FT_RSB_Adjust_Func rsb_adjust */
- (FT_VAdvance_Adjust_Func)tt_vadvance_adjust, /* vadvance_adjust */
- (FT_TSB_Adjust_Func) NULL, /* tsb_adjust */
- (FT_BSB_Adjust_Func) NULL, /* bsb_adjust */
- (FT_VOrg_Adjust_Func) NULL, /* vorg_adjust */
+ tt_vadvance_adjust, /* FT_VAdvance_Adjust_Func vadvance_adjust */
+ NULL, /* FT_TSB_Adjust_Func tsb_adjust */
+ NULL, /* FT_BSB_Adjust_Func bsb_adjust */
+ NULL, /* FT_VOrg_Adjust_Func vorg_adjust */
- (FT_Metrics_Adjust_Func) tt_apply_mvar /* metrics_adjust */
+ tt_apply_mvar, /* FT_Metrics_Adjust_Func metrics_adjust */
+ tt_size_reset_height /* FT_Size_Reset_Func size_reset */
)
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
diff --git a/thirdparty/freetype/src/truetype/ttgload.c b/thirdparty/freetype/src/truetype/ttgload.c
index d33bdad642..5f15a7f4de 100644
--- a/thirdparty/freetype/src/truetype/ttgload.c
+++ b/thirdparty/freetype/src/truetype/ttgload.c
@@ -362,17 +362,16 @@
FT_Byte* p = load->cursor;
FT_Byte* limit = load->limit;
FT_GlyphLoader gloader = load->gloader;
+ FT_Outline* outline = &gloader->current.outline;
FT_Int n_contours = load->n_contours;
- FT_Outline* outline;
- FT_UShort n_ins;
FT_Int n_points;
+ FT_UShort n_ins;
FT_Byte *flag, *flag_limit;
FT_Byte c, count;
FT_Vector *vec, *vec_limit;
FT_Pos x, y;
- FT_Short *cont, *cont_limit, prev_cont;
- FT_Int xy_size = 0;
+ FT_Short *cont, *cont_limit, last;
/* check that we can add the contours to the glyph */
@@ -380,41 +379,27 @@
if ( error )
goto Fail;
- /* reading the contours' endpoints & number of points */
- cont = gloader->current.outline.contours;
- cont_limit = cont + n_contours;
-
/* check space for contours array + instructions count */
- if ( n_contours >= 0xFFF || p + ( n_contours + 1 ) * 2 > limit )
+ if ( n_contours >= 0xFFF || p + 2 * n_contours + 2 > limit )
goto Invalid_Outline;
- prev_cont = FT_NEXT_SHORT( p );
-
- if ( n_contours > 0 )
- cont[0] = prev_cont;
-
- if ( prev_cont < 0 )
- goto Invalid_Outline;
+ /* reading the contours' endpoints & number of points */
+ cont = outline->contours;
+ cont_limit = cont + n_contours;
- for ( cont++; cont < cont_limit; cont++ )
+ last = -1;
+ for ( ; cont < cont_limit; cont++ )
{
- cont[0] = FT_NEXT_SHORT( p );
- if ( cont[0] <= prev_cont )
- {
- /* unordered contours: this is invalid */
- goto Invalid_Outline;
- }
- prev_cont = cont[0];
- }
+ *cont = FT_NEXT_SHORT( p );
- n_points = 0;
- if ( n_contours > 0 )
- {
- n_points = cont[-1] + 1;
- if ( n_points < 0 )
+ if ( *cont <= last )
goto Invalid_Outline;
+
+ last = *cont;
}
+ n_points = last + 1;
+
FT_TRACE5(( " # of points: %d\n", n_points ));
/* note that we will add four phantom points later */
@@ -422,59 +407,48 @@
if ( error )
goto Fail;
- /* reading the bytecode instructions */
- load->glyph->control_len = 0;
- load->glyph->control_data = NULL;
-
- if ( p + 2 > limit )
- goto Invalid_Outline;
-
+ /* space checked above */
n_ins = FT_NEXT_USHORT( p );
FT_TRACE5(( " Instructions size: %u\n", n_ins ));
+ /* check instructions size */
+ if ( p + n_ins > limit )
+ {
+ FT_TRACE1(( "TT_Load_Simple_Glyph: excessive instruction count\n" ));
+ error = FT_THROW( Too_Many_Hints );
+ goto Fail;
+ }
+
#ifdef TT_USE_BYTECODE_INTERPRETER
if ( IS_HINTED( load->load_flags ) )
{
- FT_ULong tmp;
+ TT_ExecContext exec = load->exec;
+ FT_Memory memory = exec->memory;
- /* check instructions size */
- if ( ( limit - p ) < n_ins )
- {
- FT_TRACE1(( "TT_Load_Simple_Glyph: instruction count mismatch\n" ));
- error = FT_THROW( Too_Many_Hints );
- goto Fail;
- }
+ if ( exec->glyphSize )
+ FT_FREE( exec->glyphIns );
+ exec->glyphSize = 0;
/* we don't trust `maxSizeOfInstructions' in the `maxp' table */
- /* and thus update the bytecode array size by ourselves */
-
- tmp = load->exec->glyphSize;
- error = Update_Max( load->exec->memory,
- &tmp,
- sizeof ( FT_Byte ),
- (void*)&load->exec->glyphIns,
- n_ins );
-
- load->exec->glyphSize = (FT_UInt)tmp;
- if ( error )
- return error;
+ /* and thus allocate the bytecode array size by ourselves */
+ if ( n_ins )
+ {
+ if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) )
+ return error;
- load->glyph->control_len = n_ins;
- load->glyph->control_data = load->exec->glyphIns;
+ FT_MEM_COPY( exec->glyphIns, p, (FT_Long)n_ins );
- if ( n_ins )
- FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins );
+ exec->glyphSize = n_ins;
+ }
}
#endif /* TT_USE_BYTECODE_INTERPRETER */
p += n_ins;
- outline = &gloader->current.outline;
-
/* reading the point tags */
flag = (FT_Byte*)outline->tags;
flag_limit = flag + n_points;
@@ -512,9 +486,6 @@
flag = (FT_Byte*)outline->tags;
x = 0;
- if ( p + xy_size > limit )
- goto Invalid_Outline;
-
for ( ; vec < vec_limit; vec++, flag++ )
{
FT_Pos delta = 0;
@@ -544,7 +515,7 @@
/* reading the Y coordinates */
- vec = gloader->current.outline.points;
+ vec = outline->points;
vec_limit = vec + n_points;
flag = (FT_Byte*)outline->tags;
y = 0;
@@ -836,15 +807,14 @@
TT_GlyphZone zone = &loader->zone;
#ifdef TT_USE_BYTECODE_INTERPRETER
- FT_Long n_ins;
+ TT_ExecContext exec = loader->exec;
+ FT_Long n_ins = exec->glyphSize;
#else
FT_UNUSED( is_composite );
#endif
#ifdef TT_USE_BYTECODE_INTERPRETER
- n_ins = loader->glyph->control_len;
-
/* save original point positions in `org' array */
if ( n_ins > 0 )
FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points );
@@ -856,15 +826,15 @@
/* completely refer to the (already) hinted subglyphs. */
if ( is_composite )
{
- loader->exec->metrics.x_scale = 1 << 16;
- loader->exec->metrics.y_scale = 1 << 16;
+ exec->metrics.x_scale = 1 << 16;
+ exec->metrics.y_scale = 1 << 16;
FT_ARRAY_COPY( zone->orus, zone->cur, zone->n_points );
}
else
{
- loader->exec->metrics.x_scale = loader->size->metrics->x_scale;
- loader->exec->metrics.y_scale = loader->size->metrics->y_scale;
+ exec->metrics.x_scale = loader->size->metrics->x_scale;
+ exec->metrics.y_scale = loader->size->metrics->y_scale;
}
#endif
@@ -884,23 +854,19 @@
{
FT_Error error;
- FT_GlyphLoader gloader = loader->gloader;
- FT_Outline current_outline = gloader->current.outline;
+ TT_Set_CodeRange( exec, tt_coderange_glyph, exec->glyphIns, n_ins );
- TT_Set_CodeRange( loader->exec, tt_coderange_glyph,
- loader->exec->glyphIns, n_ins );
-
- loader->exec->is_composite = is_composite;
- loader->exec->pts = *zone;
+ exec->is_composite = is_composite;
+ exec->pts = *zone;
error = TT_Run_Context( loader->exec );
- if ( error && loader->exec->pedantic_hinting )
+ if ( error && exec->pedantic_hinting )
return error;
/* store drop-out mode in bits 5-7; set bit 2 also as a marker */
- current_outline.tags[0] |=
- ( loader->exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE;
+ loader->gloader->current.outline.tags[0] |=
+ ( exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE;
}
#endif
@@ -910,7 +876,7 @@
/* compatibility mode, where no movement on the x axis means no reason */
/* to change bearings or advance widths. */
if ( !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
- loader->exec->backward_compatibility ) )
+ exec->backward_compatibility ) )
{
#endif
loader->pp1 = zone->cur[zone->n_points - 4];
@@ -924,10 +890,10 @@
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
{
- if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
+ if ( exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 );
- else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
+ else if ( exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 );
}
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
@@ -949,10 +915,10 @@
static FT_Error
TT_Process_Simple_Glyph( TT_Loader loader )
{
- FT_GlyphLoader gloader = loader->gloader;
- FT_Error error = FT_Err_Ok;
- FT_Outline* outline;
- FT_Int n_points;
+ FT_Error error = FT_Err_Ok;
+ FT_GlyphLoader gloader = loader->gloader;
+ FT_Outline* outline = &gloader->current.outline;
+ FT_Int n_points = outline->n_points;
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_Memory memory = loader->face->root.memory;
@@ -960,11 +926,7 @@
#endif
- outline = &gloader->current.outline;
- n_points = outline->n_points;
-
/* set phantom points */
-
outline->points[n_points ] = loader->pp1;
outline->points[n_points + 1] = loader->pp2;
outline->points[n_points + 2] = loader->pp3;
@@ -976,7 +938,7 @@
if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
{
- if ( FT_NEW_ARRAY( unrounded, n_points ) )
+ if ( FT_QNEW_ARRAY( unrounded, n_points ) )
goto Exit;
/* Deltas apply to the unscaled data. */
@@ -1331,12 +1293,12 @@
FT_UInt start_contour )
{
FT_Error error;
- FT_Outline* outline;
+ FT_Outline* outline = &loader->gloader->base.outline;
+ FT_Stream stream = loader->stream;
+ FT_UShort n_ins;
FT_UInt i;
- outline = &loader->gloader->base.outline;
-
/* make room for phantom points */
error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader,
outline->n_points + 4,
@@ -1352,10 +1314,13 @@
#ifdef TT_USE_BYTECODE_INTERPRETER
{
- FT_Stream stream = loader->stream;
- FT_UShort n_ins, max_ins;
- FT_ULong tmp;
+ TT_ExecContext exec = loader->exec;
+ FT_Memory memory = exec->memory;
+
+ if ( exec->glyphSize )
+ FT_FREE( exec->glyphIns );
+ exec->glyphSize = 0;
/* TT_Load_Composite_Glyph only gives us the offset of instructions */
/* so we read them here */
@@ -1365,39 +1330,24 @@
FT_TRACE5(( " Instructions size = %hu\n", n_ins ));
- /* check it */
- max_ins = loader->face->max_profile.maxSizeOfInstructions;
- if ( n_ins > max_ins )
- {
- /* don't trust `maxSizeOfInstructions'; */
- /* only do a rough safety check */
- if ( n_ins > loader->byte_len )
- {
- FT_TRACE1(( "TT_Process_Composite_Glyph:"
- " too many instructions (%hu) for glyph with length %u\n",
- n_ins, loader->byte_len ));
- return FT_THROW( Too_Many_Hints );
- }
-
- tmp = loader->exec->glyphSize;
- error = Update_Max( loader->exec->memory,
- &tmp,
- sizeof ( FT_Byte ),
- (void*)&loader->exec->glyphIns,
- n_ins );
+ if ( !n_ins )
+ return FT_Err_Ok;
- loader->exec->glyphSize = (FT_UShort)tmp;
- if ( error )
- return error;
+ /* don't trust `maxSizeOfInstructions'; */
+ /* only do a rough safety check */
+ if ( n_ins > loader->byte_len )
+ {
+ FT_TRACE1(( "TT_Process_Composite_Glyph:"
+ " too many instructions (%hu) for glyph with length %u\n",
+ n_ins, loader->byte_len ));
+ return FT_THROW( Too_Many_Hints );
}
- else if ( n_ins == 0 )
- return FT_Err_Ok;
- if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) )
+ if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) ||
+ FT_STREAM_READ( exec->glyphIns, n_ins ) )
return error;
- loader->glyph->control_data = loader->exec->glyphIns;
- loader->glyph->control_len = n_ins;
+ exec->glyphSize = n_ins;
}
#endif
@@ -1662,8 +1612,14 @@
else
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+ {
+ FT_ULong len;
+
- offset = tt_face_get_location( face, glyph_index, &loader->byte_len );
+ offset = tt_face_get_location( FT_FACE( face ), glyph_index, &len );
+
+ loader->byte_len = (FT_UInt)len;
+ }
if ( loader->byte_len > 0 )
{
@@ -1889,10 +1845,7 @@
short i, limit;
FT_SubGlyph subglyph;
- FT_Outline outline;
- FT_Vector* points = NULL;
- char* tags = NULL;
- short* contours = NULL;
+ FT_Outline outline = { 0, 0, NULL, NULL, NULL, 0 };
FT_Vector* unrounded = NULL;
@@ -1900,18 +1853,14 @@
/* construct an outline structure for */
/* communication with `TT_Vary_Apply_Glyph_Deltas' */
- outline.n_contours = outline.n_points = limit;
-
- outline.points = NULL;
- outline.tags = NULL;
- outline.contours = NULL;
-
- if ( FT_NEW_ARRAY( points, limit + 4 ) ||
- FT_NEW_ARRAY( tags, limit + 4 ) ||
- FT_NEW_ARRAY( contours, limit + 4 ) ||
- FT_NEW_ARRAY( unrounded, limit + 4 ) )
+ if ( FT_QNEW_ARRAY( outline.points, limit + 4 ) ||
+ FT_QNEW_ARRAY( outline.tags, limit ) ||
+ FT_QNEW_ARRAY( outline.contours, limit ) ||
+ FT_QNEW_ARRAY( unrounded, limit + 4 ) )
goto Exit1;
+ outline.n_contours = outline.n_points = limit;
+
subglyph = gloader->current.subglyphs;
for ( i = 0; i < limit; i++, subglyph++ )
@@ -1919,20 +1868,16 @@
/* applying deltas for anchor points doesn't make sense, */
/* but we don't have to specially check this since */
/* unused delta values are zero anyways */
- points[i].x = subglyph->arg1;
- points[i].y = subglyph->arg2;
- tags[i] = 1;
- contours[i] = i;
+ outline.points[i].x = subglyph->arg1;
+ outline.points[i].y = subglyph->arg2;
+ outline.tags[i] = ON_CURVE_POINT;
+ outline.contours[i] = i;
}
- points[i++] = loader->pp1;
- points[i++] = loader->pp2;
- points[i++] = loader->pp3;
- points[i ] = loader->pp4;
-
- outline.points = points;
- outline.tags = tags;
- outline.contours = contours;
+ outline.points[i++] = loader->pp1;
+ outline.points[i++] = loader->pp2;
+ outline.points[i++] = loader->pp3;
+ outline.points[i ] = loader->pp4;
/* this call provides additional offsets */
/* for each component's translation */
@@ -1947,8 +1892,8 @@
{
if ( subglyph->flags & ARGS_ARE_XY_VALUES )
{
- subglyph->arg1 = (FT_Int16)points[i].x;
- subglyph->arg2 = (FT_Int16)points[i].y;
+ subglyph->arg1 = (FT_Int16)outline.points[i].x;
+ subglyph->arg2 = (FT_Int16)outline.points[i].y;
}
}
@@ -2857,7 +2802,9 @@
#ifdef FT_CONFIG_OPTION_SVG
/* check for OT-SVG */
- if ( ( load_flags & FT_LOAD_COLOR ) && face->svg )
+ if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
+ ( load_flags & FT_LOAD_COLOR ) &&
+ face->svg )
{
SFNT_Service sfnt = (SFNT_Service)face->sfnt;
@@ -2955,6 +2902,9 @@
if ( IS_HINTED( load_flags ) )
{
+ glyph->control_data = loader.exec->glyphIns;
+ glyph->control_len = loader.exec->glyphSize;
+
if ( loader.exec->GS.scan_control )
{
/* convert scan conversion mode to FT_OUTLINE_XXX flags */
diff --git a/thirdparty/freetype/src/truetype/ttgxvar.c b/thirdparty/freetype/src/truetype/ttgxvar.c
index 60a0095b6e..8c713f1b6f 100644
--- a/thirdparty/freetype/src/truetype/ttgxvar.c
+++ b/thirdparty/freetype/src/truetype/ttgxvar.c
@@ -45,6 +45,7 @@
#include <freetype/internal/ftcalc.h>
#include <freetype/internal/ftstream.h>
#include <freetype/internal/sfnt.h>
+#include <freetype/internal/services/svmetric.h>
#include <freetype/tttags.h>
#include <freetype/ttnameid.h>
#include <freetype/ftmm.h>
@@ -465,7 +466,7 @@
if ( store_offset )
{
error = tt_var_load_item_variation_store(
- face,
+ FT_FACE( face ),
table_offset + store_offset,
&table->itemStore );
if ( error )
@@ -475,7 +476,7 @@
if ( axisMap_offset )
{
error = tt_var_load_delta_set_index_mapping(
- face,
+ FT_FACE( face ),
table_offset + axisMap_offset,
&table->axisMap,
&table->itemStore,
@@ -492,10 +493,11 @@
FT_LOCAL_DEF( FT_Error )
- tt_var_load_item_variation_store( TT_Face face,
+ tt_var_load_item_variation_store( FT_Face face, /* TT_Face */
FT_ULong offset,
GX_ItemVarStore itemStore )
{
+ TT_Face ttface = (TT_Face)face;
FT_Stream stream = FT_FACE_STREAM( face );
FT_Memory memory = stream->memory;
@@ -507,10 +509,10 @@
FT_UShort axis_count;
FT_UInt region_count;
- FT_UInt i, j, k;
+ FT_UInt i, j;
FT_Bool long_words;
- GX_Blend blend = face->blend;
+ GX_Blend blend = ttface->blend;
FT_ULong* dataOffsetArray = NULL;
@@ -622,6 +624,7 @@
FT_UInt item_count;
FT_UInt word_delta_count;
FT_UInt region_idx_count;
+ FT_UInt per_region_size;
if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) )
@@ -658,6 +661,8 @@
if ( FT_NEW_ARRAY( varData->regionIndices, region_idx_count ) )
goto Exit;
varData->regionIdxCount = region_idx_count;
+ varData->wordDeltaCount = word_delta_count;
+ varData->longWords = long_words;
for ( j = 0; j < varData->regionIdxCount; j++ )
{
@@ -673,37 +678,22 @@
}
}
- /* Parse delta set. */
- /* */
- /* On input, deltas are (word_delta_count + region_idx_count) bytes */
- /* each if `long_words` isn't set, and twice as much otherwise. */
- /* */
- /* On output, deltas are expanded to `region_idx_count` shorts each. */
- if ( FT_NEW_ARRAY( varData->deltaSet, item_count * region_idx_count ) )
- goto Exit;
- varData->itemCount = item_count;
+ per_region_size = word_delta_count + region_idx_count;
+ if ( long_words )
+ per_region_size *= 2;
- for ( j = 0; j < item_count * region_idx_count; )
+ if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) )
+ goto Exit;
+ if ( FT_Stream_Read( stream,
+ varData->deltaSet,
+ per_region_size * item_count ) )
{
- if ( long_words )
- {
- for ( k = 0; k < word_delta_count; k++, j++ )
- if ( FT_READ_LONG( varData->deltaSet[j] ) )
- goto Exit;
- for ( ; k < region_idx_count; k++, j++ )
- if ( FT_READ_SHORT( varData->deltaSet[j] ) )
- goto Exit;
- }
- else
- {
- for ( k = 0; k < word_delta_count; k++, j++ )
- if ( FT_READ_SHORT( varData->deltaSet[j] ) )
- goto Exit;
- for ( ; k < region_idx_count; k++, j++ )
- if ( FT_READ_CHAR( varData->deltaSet[j] ) )
- goto Exit;
- }
+ FT_TRACE2(( "deltaSet read failed." ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
}
+
+ varData->itemCount = item_count;
}
Exit:
@@ -714,7 +704,7 @@
FT_LOCAL_DEF( FT_Error )
- tt_var_load_delta_set_index_mapping( TT_Face face,
+ tt_var_load_delta_set_index_mapping( FT_Face face, /* TT_Face */
FT_ULong offset,
GX_DeltaSetIdxMap map,
GX_ItemVarStore itemStore,
@@ -941,7 +931,7 @@
}
error = tt_var_load_item_variation_store(
- face,
+ FT_FACE( face ),
table_offset + store_offset,
&table->itemStore );
if ( error )
@@ -950,7 +940,7 @@
if ( widthMap_offset )
{
error = tt_var_load_delta_set_index_mapping(
- face,
+ FT_FACE( face ),
table_offset + widthMap_offset,
&table->widthMap,
&table->itemStore,
@@ -992,24 +982,30 @@
FT_LOCAL_DEF( FT_ItemVarDelta )
- tt_var_get_item_delta( TT_Face face,
+ tt_var_get_item_delta( FT_Face face, /* TT_Face */
GX_ItemVarStore itemStore,
FT_UInt outerIndex,
FT_UInt innerIndex )
{
+ TT_Face ttface = (TT_Face)face;
FT_Stream stream = FT_FACE_STREAM( face );
FT_Memory memory = stream->memory;
FT_Error error = FT_Err_Ok;
GX_ItemVarData varData;
- FT_ItemVarDelta* deltaSet;
+ FT_ItemVarDelta* deltaSet = NULL;
+ FT_ItemVarDelta deltaSetStack[16];
+
+ FT_Fixed* scalars = NULL;
+ FT_Fixed scalarsStack[16];
FT_UInt master, j;
- FT_Fixed* scalars = NULL;
- FT_ItemVarDelta returnValue;
+ FT_ItemVarDelta returnValue = 0;
+ FT_UInt per_region_size;
+ FT_Byte* bytes;
- if ( !face->blend || !face->blend->normalizedcoords )
+ if ( !ttface->blend || !ttface->blend->normalizedcoords )
return 0;
/* OpenType 1.8.4+: No variation data for this item */
@@ -1023,15 +1019,48 @@
if ( outerIndex >= itemStore->dataCount )
return 0; /* Out of range. */
- varData = &itemStore->varData[outerIndex];
- deltaSet = FT_OFFSET( varData->deltaSet,
- varData->regionIdxCount * innerIndex );
+ varData = &itemStore->varData[outerIndex];
if ( innerIndex >= varData->itemCount )
return 0; /* Out of range. */
- if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) )
- return 0;
+ if ( varData->regionIdxCount < 16 )
+ {
+ deltaSet = deltaSetStack;
+ scalars = scalarsStack;
+ }
+ else
+ {
+ if ( FT_QNEW_ARRAY( deltaSet, varData->regionIdxCount ) )
+ goto Exit;
+ if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) )
+ goto Exit;
+ }
+
+ /* Parse delta set. */
+ /* */
+ /* Deltas are (word_delta_count + region_idx_count) bytes each */
+ /* if `longWords` isn't set, and twice as much otherwise. */
+ per_region_size = varData->wordDeltaCount + varData->regionIdxCount;
+ if ( varData->longWords )
+ per_region_size *= 2;
+
+ bytes = varData->deltaSet + per_region_size * innerIndex;
+
+ if ( varData->longWords )
+ {
+ for ( master = 0; master < varData->wordDeltaCount; master++ )
+ deltaSet[master] = FT_NEXT_LONG( bytes );
+ for ( ; master < varData->regionIdxCount; master++ )
+ deltaSet[master] = FT_NEXT_SHORT( bytes );
+ }
+ else
+ {
+ for ( master = 0; master < varData->wordDeltaCount; master++ )
+ deltaSet[master] = FT_NEXT_SHORT( bytes );
+ for ( ; master < varData->regionIdxCount; master++ )
+ deltaSet[master] = FT_NEXT_CHAR( bytes );
+ }
/* outer loop steps through master designs to be blended */
for ( master = 0; master < varData->regionIdxCount; master++ )
@@ -1060,27 +1089,27 @@
else if ( axis->peakCoord == 0 )
continue;
- else if ( face->blend->normalizedcoords[j] == axis->peakCoord )
+ else if ( ttface->blend->normalizedcoords[j] == axis->peakCoord )
continue;
/* ignore this region if coords are out of range */
- else if ( face->blend->normalizedcoords[j] <= axis->startCoord ||
- face->blend->normalizedcoords[j] >= axis->endCoord )
+ else if ( ttface->blend->normalizedcoords[j] <= axis->startCoord ||
+ ttface->blend->normalizedcoords[j] >= axis->endCoord )
{
scalar = 0;
break;
}
/* cumulative product of all the axis scalars */
- else if ( face->blend->normalizedcoords[j] < axis->peakCoord )
+ else if ( ttface->blend->normalizedcoords[j] < axis->peakCoord )
scalar =
FT_MulDiv( scalar,
- face->blend->normalizedcoords[j] - axis->startCoord,
+ ttface->blend->normalizedcoords[j] - axis->startCoord,
axis->peakCoord - axis->startCoord );
else
scalar =
FT_MulDiv( scalar,
- axis->endCoord - face->blend->normalizedcoords[j],
+ axis->endCoord - ttface->blend->normalizedcoords[j],
axis->endCoord - axis->peakCoord );
} /* per-axis loop */
@@ -1106,7 +1135,11 @@
*/
returnValue = FT_MulAddFix( scalars, deltaSet, varData->regionIdxCount );
- FT_FREE( scalars );
+ Exit:
+ if ( scalars != scalarsStack )
+ FT_FREE( scalars );
+ if ( deltaSet != deltaSetStack )
+ FT_FREE( deltaSet );
return returnValue;
}
@@ -1206,7 +1239,7 @@
innerIndex = gindex;
}
- delta = tt_var_get_item_delta( face,
+ delta = tt_var_get_item_delta( FT_FACE( face ),
&table->itemStore,
outerIndex,
innerIndex );
@@ -1229,20 +1262,20 @@
FT_LOCAL_DEF( FT_Error )
- tt_hadvance_adjust( TT_Face face,
+ tt_hadvance_adjust( FT_Face face, /* TT_Face */
FT_UInt gindex,
FT_Int *avalue )
{
- return tt_hvadvance_adjust( face, gindex, avalue, 0 );
+ return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 0 );
}
FT_LOCAL_DEF( FT_Error )
- tt_vadvance_adjust( TT_Face face,
+ tt_vadvance_adjust( FT_Face face, /* TT_Face */
FT_UInt gindex,
FT_Int *avalue )
{
- return tt_hvadvance_adjust( face, gindex, avalue, 1 );
+ return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 1 );
}
@@ -1389,7 +1422,7 @@
records_offset = FT_STREAM_POS();
error = tt_var_load_item_variation_store(
- face,
+ FT_FACE( face ),
table_offset + store_offset,
&blend->mvar_table->itemStore );
if ( error )
@@ -1462,15 +1495,14 @@
static FT_Error
- tt_size_reset_iterator( FT_ListNode node,
+ ft_size_reset_iterator( FT_ListNode node,
void* user )
{
- TT_Size size = (TT_Size)node->data;
-
- FT_UNUSED( user );
+ FT_Size size = (FT_Size)node->data;
+ FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)user;
- tt_size_reset( size, 1 );
+ var->size_reset( size );
return FT_Err_Ok;
}
@@ -1489,16 +1521,19 @@
* The font face.
*/
FT_LOCAL_DEF( void )
- tt_apply_mvar( TT_Face face )
+ tt_apply_mvar( FT_Face face ) /* TT_Face */
{
- GX_Blend blend = face->blend;
+ TT_Face ttface = (TT_Face)face;
+
+ GX_Blend blend = ttface->blend;
GX_Value value, limit;
+
FT_Short mvar_hasc_delta = 0;
FT_Short mvar_hdsc_delta = 0;
FT_Short mvar_hlgp_delta = 0;
- if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
+ if ( !( ttface->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
return;
value = blend->mvar_table->values;
@@ -1506,7 +1541,7 @@
for ( ; value < limit; value++ )
{
- FT_Short* p = ft_var_get_value_pointer( face, value->tag );
+ FT_Short* p = ft_var_get_value_pointer( ttface, value->tag );
FT_Int delta;
@@ -1543,7 +1578,8 @@
/* adjust all derived values */
{
- FT_Face root = &face->root;
+ FT_Service_MetricsVariations var =
+ (FT_Service_MetricsVariations)ttface->face_var;
/*
* Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender,
@@ -1571,24 +1607,25 @@
* whether they were actually changed or the font had the OS/2 table's
* fsSelection's bit 7 (USE_TYPO_METRICS) set.
*/
- FT_Short current_line_gap = root->height - root->ascender +
- root->descender;
+ FT_Short current_line_gap = face->height - face->ascender +
+ face->descender;
- root->ascender = root->ascender + mvar_hasc_delta;
- root->descender = root->descender + mvar_hdsc_delta;
- root->height = root->ascender - root->descender +
+ face->ascender = face->ascender + mvar_hasc_delta;
+ face->descender = face->descender + mvar_hdsc_delta;
+ face->height = face->ascender - face->descender +
current_line_gap + mvar_hlgp_delta;
- root->underline_position = face->postscript.underlinePosition -
- face->postscript.underlineThickness / 2;
- root->underline_thickness = face->postscript.underlineThickness;
+ face->underline_position = ttface->postscript.underlinePosition -
+ ttface->postscript.underlineThickness / 2;
+ face->underline_thickness = ttface->postscript.underlineThickness;
- /* iterate over all FT_Size objects and call `tt_size_reset' */
- /* to propagate the metrics changes */
- FT_List_Iterate( &root->sizes_list,
- tt_size_reset_iterator,
- NULL );
+ /* iterate over all FT_Size objects and call `var->size_reset' */
+ /* to propagate the metrics changes */
+ if ( var && var->size_reset )
+ FT_List_Iterate( &face->sizes_list,
+ ft_size_reset_iterator,
+ (void*)var );
}
}
@@ -2099,7 +2136,7 @@
innerIndex = table->axisMap.innerIndex[idx];
}
- delta = tt_var_get_item_delta( face,
+ delta = tt_var_get_item_delta( FT_FACE( face ),
&table->itemStore,
outerIndex,
innerIndex );
@@ -2261,11 +2298,12 @@
* FreeType error code. 0 means success.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Get_MM_Var( TT_Face face,
+ TT_Get_MM_Var( FT_Face face, /* TT_Face */
FT_MM_Var* *master )
{
- FT_Stream stream = face->root.stream;
- FT_Memory memory = face->root.memory;
+ TT_Face ttface = (TT_Face)face;
+ FT_Stream stream = FT_FACE_STREAM( face );
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_ULong table_len;
FT_Error error = FT_Err_Ok;
FT_ULong fvar_start = 0;
@@ -2329,19 +2367,19 @@
/* the default instance, which might be missing in the table of named */
/* instances (in 'fvar'). This value is validated in `sfobjs.c` and */
/* may be reset to 0 if consistency checks fail. */
- num_instances = (FT_UInt)face->root.style_flags >> 16;
+ num_instances = (FT_UInt)face->style_flags >> 16;
/* read the font data and set up the internal representation */
/* if not already done */
- need_init = !face->blend;
+ need_init = !ttface->blend;
if ( need_init )
{
FT_TRACE2(( "FVAR " ));
- if ( FT_SET_ERROR( face->goto_table( face, TTAG_fvar,
- stream, &table_len ) ) )
+ if ( FT_SET_ERROR( ttface->goto_table( ttface, TTAG_fvar,
+ stream, &table_len ) ) )
{
FT_TRACE1(( "is missing\n" ));
goto Exit;
@@ -2374,14 +2412,14 @@
fvar_head.axisCount,
fvar_head.axisCount == 1 ? "is" : "es" ));
- if ( FT_NEW( face->blend ) )
+ if ( FT_NEW( ttface->blend ) )
goto Exit;
- num_axes = fvar_head.axisCount;
- face->blend->num_axis = num_axes;
+ num_axes = fvar_head.axisCount;
+ ttface->blend->num_axis = num_axes;
}
else
- num_axes = face->blend->num_axis;
+ num_axes = ttface->blend->num_axis;
/* prepare storage area for MM data; this cannot overflow */
/* 32-bit arithmetic because of the size limits used in the */
@@ -2410,16 +2448,16 @@
if ( need_init )
{
- face->blend->mmvar_len = mmvar_size +
- axis_flags_size +
- axis_size +
- namedstyle_size +
- next_coords_size +
- next_name_size;
-
- if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
+ ttface->blend->mmvar_len = mmvar_size +
+ axis_flags_size +
+ axis_size +
+ namedstyle_size +
+ next_coords_size +
+ next_name_size;
+
+ if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) )
goto Exit;
- face->blend->mmvar = mmvar;
+ ttface->blend->mmvar = mmvar;
/* set up pointers and offsets into the `mmvar' array; */
/* the data gets filled in later on */
@@ -2525,27 +2563,27 @@
/* named instance coordinates are stored as design coordinates; */
/* we have to convert them to normalized coordinates also */
- if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords,
+ if ( FT_NEW_ARRAY( ttface->blend->normalized_stylecoords,
num_axes * num_instances ) )
goto Exit;
- if ( fvar_head.instanceCount && !face->blend->avar_loaded )
+ if ( fvar_head.instanceCount && !ttface->blend->avar_loaded )
{
FT_ULong offset = FT_STREAM_POS();
- ft_var_load_avar( face );
+ ft_var_load_avar( ttface );
if ( FT_STREAM_SEEK( offset ) )
goto Exit;
}
- FT_TRACE5(( "%d instance%s\n",
+ FT_TRACE5(( "%d named instance%s\n",
fvar_head.instanceCount,
fvar_head.instanceCount == 1 ? "" : "s" ));
ns = mmvar->namedstyle;
- nsc = face->blend->normalized_stylecoords;
+ nsc = ttface->blend->normalized_stylecoords;
for ( i = 0; i < fvar_head.instanceCount; i++, ns++ )
{
/* PostScript names add 2 bytes to the instance record size */
@@ -2568,7 +2606,7 @@
#ifdef FT_DEBUG_LEVEL_TRACE
{
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
FT_String* strname = NULL;
FT_String* psname = NULL;
@@ -2580,7 +2618,7 @@
if ( ns->strid != 0xFFFF )
{
- (void)sfnt->get_name( face,
+ (void)sfnt->get_name( ttface,
(FT_UShort)ns->strid,
&strname );
if ( strname && !ft_strcmp( strname, ".notdef" ) )
@@ -2589,7 +2627,7 @@
if ( ns->psid != 0xFFFF )
{
- (void)sfnt->get_name( face,
+ (void)sfnt->get_name( ttface,
(FT_UShort)ns->psid,
&psname );
if ( psname && !ft_strcmp( psname, ".notdef" ) )
@@ -2598,7 +2636,7 @@
(void)FT_STREAM_SEEK( pos );
- FT_TRACE5(( " instance %d (%s%s%s, %s%s%s)\n",
+ FT_TRACE5(( " named instance %d (%s%s%s, %s%s%s)\n",
i,
strname ? "name: `" : "",
strname ? strname : "unnamed",
@@ -2612,7 +2650,7 @@
}
#endif /* FT_DEBUG_LEVEL_TRACE */
- ft_var_to_normalized( face, num_axes, ns->coords, nsc );
+ ft_var_to_normalized( ttface, num_axes, ns->coords, nsc );
nsc += num_axes;
FT_FRAME_EXIT();
@@ -2620,15 +2658,17 @@
if ( num_instances != fvar_head.instanceCount )
{
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
FT_Int found, dummy1, dummy2;
FT_UInt strid = ~0U;
- /* the default instance is missing in array the */
- /* of named instances; try to synthesize an entry */
- found = sfnt->get_name_id( face,
+ /* The default instance is missing in array the */
+ /* of named instances; try to synthesize an entry. */
+ /* If this fails, `default_named_instance` remains */
+ /* at value zero, which doesn't do any harm. */
+ found = sfnt->get_name_id( ttface,
TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY,
&dummy1,
&dummy2 );
@@ -2636,7 +2676,7 @@
strid = TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY;
else
{
- found = sfnt->get_name_id( face,
+ found = sfnt->get_name_id( ttface,
TT_NAME_ID_FONT_SUBFAMILY,
&dummy1,
&dummy2 );
@@ -2646,7 +2686,7 @@
if ( found )
{
- found = sfnt->get_name_id( face,
+ found = sfnt->get_name_id( ttface,
TT_NAME_ID_PS_NAME,
&dummy1,
&dummy2 );
@@ -2655,6 +2695,9 @@
FT_TRACE5(( "TT_Get_MM_Var:"
" Adding default instance to named instances\n" ));
+ /* named instance indices start with value 1 */
+ ttface->var_default_named_instance = num_instances;
+
ns = &mmvar->namedstyle[fvar_head.instanceCount];
ns->strid = strid;
@@ -2668,7 +2711,7 @@
}
}
- ft_var_load_mvar( face );
+ ft_var_load_mvar( ttface );
}
/* fill the output array if requested */
@@ -2678,9 +2721,9 @@
FT_UInt n;
- if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
+ if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) )
goto Exit;
- FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len );
+ FT_MEM_COPY( mmvar, ttface->blend->mmvar, ttface->blend->mmvar_len );
axis_flags =
(FT_UShort*)( (char*)mmvar + mmvar_size );
@@ -2756,7 +2799,7 @@
if ( !face->blend )
{
- if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
+ if ( FT_SET_ERROR( TT_Get_MM_Var( FT_FACE( face ), NULL ) ) )
goto Exit;
}
@@ -2841,26 +2884,29 @@
}
}
- if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
+ if ( !have_diff )
{
- FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16;
+ if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
+ {
+ FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16;
- c = blend->normalizedcoords + i;
- n = blend->normalized_stylecoords +
- ( instance_index - 1 ) * mmvar->num_axis +
- i;
+ c = blend->normalizedcoords + i;
+ n = blend->normalized_stylecoords +
+ ( instance_index - 1 ) * mmvar->num_axis +
+ i;
- for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
- if ( *c != *n )
- have_diff = 1;
- }
- else
- {
- c = blend->normalizedcoords + i;
- for ( j = i; j < mmvar->num_axis; j++, c++ )
- if ( *c != 0 )
- have_diff = 1;
+ for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
+ if ( *c != *n )
+ have_diff = 1;
+ }
+ else
+ {
+ c = blend->normalizedcoords + i;
+ for ( j = i; j < mmvar->num_axis; j++, c++ )
+ if ( *c != 0 )
+ have_diff = 1;
+ }
}
/* return value -1 indicates `no change' */
@@ -2924,9 +2970,6 @@
}
}
- /* enforce recomputation of the PostScript name; */
- FT_FREE( face->postscript_name );
-
Exit:
return error;
}
@@ -2958,26 +3001,15 @@
* An array of `num_coords', each between [-1,1].
*
* @Return:
- * FreeType error code. 0 means success.
+ * FreeType error code. 0 means success, -1 means success and unchanged
+ * axis values.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Set_MM_Blend( TT_Face face,
+ TT_Set_MM_Blend( FT_Face face, /* TT_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Error error;
-
-
- error = tt_set_mm_blend( face, num_coords, coords, 1 );
- if ( error )
- return error;
-
- if ( num_coords )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
- return FT_Err_Ok;
+ return tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 );
}
@@ -3005,31 +3037,34 @@
* An array of `num_coords', each between [-1,1].
*
* @Return:
- * FreeType error code. 0 means success.
+ * FreeType error code. 0 means success, -1 means success and unchanged
+ * axis values.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Get_MM_Blend( TT_Face face,
+ TT_Get_MM_Blend( FT_Face face, /* TT_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
+ TT_Face ttface = (TT_Face)face;
+
FT_Error error = FT_Err_Ok;
GX_Blend blend;
FT_UInt i, nc;
- if ( !face->blend )
+ if ( !ttface->blend )
{
if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
return error;
}
- blend = face->blend;
+ blend = ttface->blend;
if ( !blend->coords )
{
/* select default instance coordinates */
/* if no instance is selected yet */
- if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) )
+ if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) )
return error;
}
@@ -3042,7 +3077,7 @@
nc = blend->num_axis;
}
- if ( face->doblend )
+ if ( ttface->doblend )
{
for ( i = 0; i < nc; i++ )
coords[i] = blend->normalizedcoords[i];
@@ -3089,15 +3124,16 @@
* FreeType error code. 0 means success.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Set_Var_Design( TT_Face face,
+ TT_Set_Var_Design( FT_Face face, /* TT_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
+ TT_Face ttface = (TT_Face)face;
FT_Error error = FT_Err_Ok;
GX_Blend blend;
FT_MM_Var* mmvar;
FT_UInt i;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_Fixed* c;
FT_Fixed* n;
@@ -3106,13 +3142,13 @@
FT_Bool have_diff = 0;
- if ( !face->blend )
+ if ( !ttface->blend )
{
if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
goto Exit;
}
- blend = face->blend;
+ blend = ttface->blend;
mmvar = blend->mmvar;
if ( num_coords > mmvar->num_axis )
@@ -3140,13 +3176,13 @@
}
}
- if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
+ if ( FT_IS_NAMED_INSTANCE( face ) )
{
FT_UInt instance_index;
FT_Var_Named_Style* named_style;
- instance_index = (FT_UInt)face->root.face_index >> 16;
+ instance_index = (FT_UInt)face->face_index >> 16;
named_style = mmvar->namedstyle + instance_index - 1;
n = named_style->coords + num_coords;
@@ -3183,22 +3219,17 @@
if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
goto Exit;
- if ( !face->blend->avar_loaded )
- ft_var_load_avar( face );
+ if ( !ttface->blend->avar_loaded )
+ ft_var_load_avar( ttface );
FT_TRACE5(( "TT_Set_Var_Design:\n" ));
FT_TRACE5(( " normalized design coordinates:\n" ));
- ft_var_to_normalized( face, num_coords, blend->coords, normalized );
+ ft_var_to_normalized( ttface, num_coords, blend->coords, normalized );
- error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 );
+ error = tt_set_mm_blend( ttface, mmvar->num_axis, normalized, 0 );
if ( error )
goto Exit;
- if ( num_coords )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
Exit:
FT_FREE( normalized );
return error;
@@ -3231,28 +3262,29 @@
* FreeType error code. 0~means success.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Get_Var_Design( TT_Face face,
+ TT_Get_Var_Design( FT_Face face, /* TT_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Error error = FT_Err_Ok;
+ TT_Face ttface = (TT_Face)face;
+ FT_Error error = FT_Err_Ok;
GX_Blend blend;
FT_UInt i, nc;
- if ( !face->blend )
+ if ( !ttface->blend )
{
if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
return error;
}
- blend = face->blend;
+ blend = ttface->blend;
if ( !blend->coords )
{
/* select default instance coordinates */
/* if no instance is selected yet */
- if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) )
+ if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) )
return error;
}
@@ -3265,7 +3297,7 @@
nc = blend->num_axis;
}
- if ( face->doblend )
+ if ( ttface->doblend )
{
for ( i = 0; i < nc; i++ )
coords[i] = blend->coords[i];
@@ -3301,29 +3333,33 @@
* Value 0 indicates to not use an instance.
*
* @Return:
- * FreeType error code. 0~means success.
+ * FreeType error code. 0~means success, -1 means success and unchanged
+ * axis values.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Set_Named_Instance( TT_Face face,
+ TT_Set_Named_Instance( FT_Face face, /* TT_Face */
FT_UInt instance_index )
{
+ TT_Face ttface = (TT_Face)face;
FT_Error error;
GX_Blend blend;
FT_MM_Var* mmvar;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
FT_UInt num_instances;
- if ( !face->blend )
+ if ( !ttface->blend )
{
if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
goto Exit;
}
- blend = face->blend;
+ blend = ttface->blend;
mmvar = blend->mmvar;
- num_instances = (FT_UInt)face->root.style_flags >> 16;
+ num_instances = (FT_UInt)face->style_flags >> 16;
/* `instance_index' starts with value 1, thus `>' */
if ( instance_index > num_instances )
@@ -3334,8 +3370,7 @@
if ( instance_index > 0 )
{
- FT_Memory memory = face->root.memory;
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
FT_Var_Named_Style* named_style;
FT_String* style_name;
@@ -3343,40 +3378,89 @@
named_style = mmvar->namedstyle + instance_index - 1;
- error = sfnt->get_name( face,
+ error = sfnt->get_name( ttface,
(FT_UShort)named_style->strid,
&style_name );
if ( error )
goto Exit;
/* set (or replace) style name */
- FT_FREE( face->root.style_name );
- face->root.style_name = style_name;
+ FT_FREE( face->style_name );
+ face->style_name = style_name;
/* finally, select the named instance */
error = TT_Set_Var_Design( face,
mmvar->num_axis,
named_style->coords );
- if ( error )
- {
- /* internal error code -1 means `no change' */
- if ( error == -1 )
- error = FT_Err_Ok;
- goto Exit;
- }
}
else
+ {
+ /* restore non-VF style name */
+ FT_FREE( face->style_name );
+ if ( FT_STRDUP( face->style_name, ttface->non_var_style_name ) )
+ goto Exit;
error = TT_Set_Var_Design( face, 0, NULL );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * TT_Get_Default_Named_Instance
+ *
+ * @Description:
+ * Get the default named instance.
+ *
+ * @Input:
+ * face ::
+ * A handle to the source face.
+ *
+ * @Output:
+ * instance_index ::
+ * The default named instance index.
+ *
+ * @Return:
+ * FreeType error code. 0~means success.
+ */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Get_Default_Named_Instance( FT_Face face,
+ FT_UInt *instance_index )
+ {
+ TT_Face ttface = (TT_Face)face;
+ FT_Error error = FT_Err_Ok;
- face->root.face_index = ( instance_index << 16 ) |
- ( face->root.face_index & 0xFFFFL );
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+ if ( !ttface->blend )
+ {
+ if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
+ goto Exit;
+ }
+
+ *instance_index = ttface->var_default_named_instance;
Exit:
return error;
}
+ /* This function triggers (lazy) recomputation of the `postscript_name` */
+ /* field in `TT_Face`. */
+
+ FT_LOCAL_DEF( void )
+ tt_construct_ps_name( FT_Face face )
+ {
+ TT_Face ttface = (TT_Face)face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ FT_FREE( ttface->postscript_name );
+ }
+
+
/*************************************************************************/
/*************************************************************************/
/***** *****/
@@ -4409,22 +4493,25 @@
* the MM machinery in case it isn't loaded yet.
*/
FT_LOCAL_DEF( FT_Error )
- tt_get_var_blend( TT_Face face,
+ tt_get_var_blend( FT_Face face, /* TT_Face */
FT_UInt *num_coords,
FT_Fixed* *coords,
FT_Fixed* *normalizedcoords,
FT_MM_Var* *mm_var )
{
- if ( face->blend )
+ TT_Face ttface = (TT_Face)face;
+
+
+ if ( ttface->blend )
{
if ( num_coords )
- *num_coords = face->blend->num_axis;
+ *num_coords = ttface->blend->num_axis;
if ( coords )
- *coords = face->blend->coords;
+ *coords = ttface->blend->coords;
if ( normalizedcoords )
- *normalizedcoords = face->blend->normalizedcoords;
+ *normalizedcoords = ttface->blend->normalizedcoords;
if ( mm_var )
- *mm_var = face->blend->mmvar;
+ *mm_var = ttface->blend->mmvar;
}
else
{
@@ -4441,7 +4528,7 @@
FT_LOCAL_DEF( void )
- tt_var_done_item_variation_store( TT_Face face,
+ tt_var_done_item_variation_store( FT_Face face,
GX_ItemVarStore itemStore )
{
FT_Memory memory = FT_FACE_MEMORY( face );
@@ -4470,7 +4557,7 @@
FT_LOCAL_DEF( void )
- tt_var_done_delta_set_index_map( TT_Face face,
+ tt_var_done_delta_set_index_map( FT_Face face,
GX_DeltaSetIdxMap deltaSetIdxMap )
{
FT_Memory memory = FT_FACE_MEMORY( face );
@@ -4490,10 +4577,11 @@
* Free the blend internal data structure.
*/
FT_LOCAL_DEF( void )
- tt_done_blend( TT_Face face )
+ tt_done_blend( FT_Face face )
{
+ TT_Face ttface = (TT_Face)face;
FT_Memory memory = FT_FACE_MEMORY( face );
- GX_Blend blend = face->blend;
+ GX_Blend blend = ttface->blend;
if ( blend )
@@ -4565,7 +4653,7 @@
#else /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */
/* ANSI C doesn't like empty source files */
- typedef int _tt_gxvar_dummy;
+ typedef int tt_gxvar_dummy_;
#endif /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */
diff --git a/thirdparty/freetype/src/truetype/ttgxvar.h b/thirdparty/freetype/src/truetype/ttgxvar.h
index 4fec980dcc..e3da6d1705 100644
--- a/thirdparty/freetype/src/truetype/ttgxvar.h
+++ b/thirdparty/freetype/src/truetype/ttgxvar.h
@@ -347,34 +347,41 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
- TT_Set_MM_Blend( TT_Face face,
+ TT_Set_MM_Blend( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- TT_Get_MM_Blend( TT_Face face,
+ TT_Get_MM_Blend( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- TT_Set_Var_Design( TT_Face face,
+ TT_Set_Var_Design( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- TT_Get_MM_Var( TT_Face face,
+ TT_Get_MM_Var( FT_Face face,
FT_MM_Var* *master );
FT_LOCAL( FT_Error )
- TT_Get_Var_Design( TT_Face face,
+ TT_Get_Var_Design( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- TT_Set_Named_Instance( TT_Face face,
+ TT_Set_Named_Instance( FT_Face face,
FT_UInt instance_index );
FT_LOCAL( FT_Error )
+ TT_Get_Default_Named_Instance( FT_Face face,
+ FT_UInt *instance_index );
+
+ FT_LOCAL( void )
+ tt_construct_ps_name( FT_Face face );
+
+ FT_LOCAL( FT_Error )
tt_face_vary_cvt( TT_Face face,
FT_Stream stream );
@@ -385,55 +392,54 @@ FT_BEGIN_HEADER
FT_Vector* unrounded );
FT_LOCAL( FT_Error )
- tt_hadvance_adjust( TT_Face face,
+ tt_hadvance_adjust( FT_Face face,
FT_UInt gindex,
FT_Int *adelta );
FT_LOCAL( FT_Error )
- tt_vadvance_adjust( TT_Face face,
+ tt_vadvance_adjust( FT_Face face,
FT_UInt gindex,
FT_Int *adelta );
FT_LOCAL( void )
- tt_apply_mvar( TT_Face face );
-
+ tt_apply_mvar( FT_Face face );
FT_LOCAL( FT_Error )
- tt_var_load_item_variation_store( TT_Face face,
+ tt_var_load_item_variation_store( FT_Face face,
FT_ULong offset,
GX_ItemVarStore itemStore );
FT_LOCAL( FT_Error )
- tt_var_load_delta_set_index_mapping( TT_Face face,
+ tt_var_load_delta_set_index_mapping( FT_Face face,
FT_ULong offset,
GX_DeltaSetIdxMap map,
GX_ItemVarStore itemStore,
FT_ULong table_len );
FT_LOCAL( FT_ItemVarDelta )
- tt_var_get_item_delta( TT_Face face,
+ tt_var_get_item_delta( FT_Face face,
GX_ItemVarStore itemStore,
FT_UInt outerIndex,
FT_UInt innerIndex );
FT_LOCAL( void )
- tt_var_done_item_variation_store( TT_Face face,
+ tt_var_done_item_variation_store( FT_Face face,
GX_ItemVarStore itemStore );
FT_LOCAL( void )
- tt_var_done_delta_set_index_map( TT_Face face,
+ tt_var_done_delta_set_index_map( FT_Face face,
GX_DeltaSetIdxMap deltaSetIdxMap );
FT_LOCAL( FT_Error )
- tt_get_var_blend( TT_Face face,
+ tt_get_var_blend( FT_Face face,
FT_UInt *num_coords,
FT_Fixed* *coords,
FT_Fixed* *normalizedcoords,
FT_MM_Var* *mm_var );
FT_LOCAL( void )
- tt_done_blend( TT_Face face );
+ tt_done_blend( FT_Face face );
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
diff --git a/thirdparty/freetype/src/truetype/ttinterp.c b/thirdparty/freetype/src/truetype/ttinterp.c
index 4fcfaa3e43..34c3e6c92a 100644
--- a/thirdparty/freetype/src/truetype/ttinterp.c
+++ b/thirdparty/freetype/src/truetype/ttinterp.c
@@ -278,57 +278,6 @@
/**************************************************************************
*
* @Function:
- * Update_Max
- *
- * @Description:
- * Checks the size of a buffer and reallocates it if necessary.
- *
- * @Input:
- * memory ::
- * A handle to the parent memory object.
- *
- * multiplier ::
- * The size in bytes of each element in the buffer.
- *
- * new_max ::
- * The new capacity (size) of the buffer.
- *
- * @InOut:
- * size ::
- * The address of the buffer's current size expressed
- * in elements.
- *
- * buff ::
- * The address of the buffer base pointer.
- *
- * @Return:
- * FreeType error code. 0 means success.
- */
- FT_LOCAL_DEF( FT_Error )
- Update_Max( FT_Memory memory,
- FT_ULong* size,
- FT_ULong multiplier,
- void* _pbuff,
- FT_ULong new_max )
- {
- FT_Error error;
- void** pbuff = (void**)_pbuff;
-
-
- if ( *size < new_max )
- {
- if ( FT_QREALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
- return error;
- *size = new_max;
- }
-
- return FT_Err_Ok;
- }
-
-
- /**************************************************************************
- *
- * @Function:
* TT_Load_Context
*
* @Description:
@@ -359,9 +308,9 @@
TT_Size size )
{
FT_Int i;
- FT_ULong tmp;
TT_MaxProfile* maxp;
FT_Error error;
+ FT_Memory memory = exec->memory;
exec->face = face;
@@ -406,25 +355,15 @@
/* XXX: We reserve a little more elements on the stack to deal safely */
/* with broken fonts like arialbs, courbs, timesbs, etc. */
- tmp = (FT_ULong)exec->stackSize;
- error = Update_Max( exec->memory,
- &tmp,
- sizeof ( FT_F26Dot6 ),
- (void*)&exec->stack,
- maxp->maxStackElements + 32 );
- exec->stackSize = (FT_Long)tmp;
- if ( error )
+ if ( FT_QRENEW_ARRAY( exec->stack,
+ exec->stackSize,
+ maxp->maxStackElements + 32 ) )
return error;
+ exec->stackSize = maxp->maxStackElements + 32;
- tmp = (FT_ULong)exec->glyphSize;
- error = Update_Max( exec->memory,
- &tmp,
- sizeof ( FT_Byte ),
- (void*)&exec->glyphIns,
- maxp->maxSizeOfInstructions );
- exec->glyphSize = (FT_UInt)tmp;
- if ( error )
- return error;
+ /* free previous glyph code range */
+ FT_FREE( exec->glyphIns );
+ exec->glyphSize = 0;
exec->pts.n_points = 0;
exec->pts.n_contours = 0;
@@ -1530,14 +1469,16 @@
if ( exc->iniRange == tt_coderange_glyph &&
exc->cvt != exc->glyfCvt )
{
- exc->error = Update_Max( exc->memory,
- &exc->glyfCvtSize,
- sizeof ( FT_Long ),
- (void*)&exc->glyfCvt,
- exc->cvtSize );
- if ( exc->error )
+ FT_Memory memory = exc->memory;
+ FT_Error error;
+
+
+ FT_MEM_QRENEW_ARRAY( exc->glyfCvt, exc->glyfCvtSize, exc->cvtSize );
+ exc->error = error;
+ if ( error )
return;
+ exc->glyfCvtSize = exc->cvtSize;
FT_ARRAY_COPY( exc->glyfCvt, exc->cvt, exc->glyfCvtSize );
exc->cvt = exc->glyfCvt;
}
@@ -3117,18 +3058,18 @@
if ( exc->iniRange == tt_coderange_glyph &&
exc->storage != exc->glyfStorage )
{
- FT_ULong tmp = (FT_ULong)exc->glyfStoreSize;
+ FT_Memory memory = exc->memory;
+ FT_Error error;
- exc->error = Update_Max( exc->memory,
- &tmp,
- sizeof ( FT_Long ),
- (void*)&exc->glyfStorage,
- exc->storeSize );
- exc->glyfStoreSize = (FT_UShort)tmp;
- if ( exc->error )
+ FT_MEM_QRENEW_ARRAY( exc->glyfStorage,
+ exc->glyfStoreSize,
+ exc->storeSize );
+ exc->error = error;
+ if ( error )
return;
+ exc->glyfStoreSize = exc->storeSize;
FT_ARRAY_COPY( exc->glyfStorage, exc->storage, exc->glyfStoreSize );
exc->storage = exc->glyfStorage;
}
@@ -3606,7 +3547,8 @@
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
/* arguments to opcodes are skipped by `SKIP_Code' */
- FT_Byte opcode_pattern[9][12] = {
+ FT_Byte opcode_pattern[9][12] =
+ {
/* #0 inline delta function 1 */
{
0x4B, /* PPEM */
@@ -7380,14 +7322,6 @@
* GETINFO[]: GET INFOrmation
* Opcode range: 0x88
* Stack: uint32 --> uint32
- *
- * XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May
- * 2015) not documented in the OpenType specification.
- *
- * Selector bit 11 is incorrectly described as bit 8, while the
- * real meaning of bit 8 (vertical LCD subpixels) stays
- * undocumented. The same mistake can be found in Greg Hitchcock's
- * whitepaper.
*/
static void
Ins_GETINFO( TT_ExecContext exc,
@@ -7446,8 +7380,6 @@
* VARIATION GLYPH
* Selector Bit: 3
* Return Bit(s): 10
- *
- * XXX: UNDOCUMENTED!
*/
if ( (args[0] & 8 ) != 0 && exc->face->blend )
K |= 1 << 10;
@@ -7739,20 +7671,23 @@
/* documentation is in ttinterp.h */
FT_EXPORT_DEF( FT_Error )
- TT_RunIns( TT_ExecContext exc )
+ TT_RunIns( void* exec )
{
+ TT_ExecContext exc = (TT_ExecContext)exec;
+
FT_ULong ins_counter = 0; /* executed instructions counter */
FT_ULong num_twilight_points;
FT_UShort i;
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- FT_Byte opcode_pattern[1][2] = {
- /* #8 TypeMan Talk Align */
- {
- 0x06, /* SPVTL */
- 0x7D, /* RDTG */
- },
- };
+ FT_Byte opcode_pattern[1][2] =
+ {
+ /* #8 TypeMan Talk Align */
+ {
+ 0x06, /* SPVTL */
+ 0x7D, /* RDTG */
+ },
+ };
FT_UShort opcode_patterns = 1;
FT_UShort opcode_pointer[1] = { 0 };
FT_UShort opcode_size[1] = { 1 };
@@ -7906,7 +7841,7 @@
/* a variable number of arguments */
/* it is the job of the application to `activate' GX handling, */
- /* this is, calling any of the GX API functions on the current */
+ /* that is, calling any of the GX API functions on the current */
/* font to select a variation instance */
if ( exc->face->blend )
exc->new_top = exc->args + exc->face->blend->num_axis;
@@ -8466,7 +8401,7 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
case 0x91:
/* it is the job of the application to `activate' GX handling, */
- /* this is, calling any of the GX API functions on the current */
+ /* that is, calling any of the GX API functions on the current */
/* font to select a variation instance */
if ( exc->face->blend )
Ins_GETVARIATION( exc, args );
@@ -8604,7 +8539,7 @@
#else /* !TT_USE_BYTECODE_INTERPRETER */
/* ANSI C doesn't like empty source files */
- typedef int _tt_interp_dummy;
+ typedef int tt_interp_dummy_;
#endif /* !TT_USE_BYTECODE_INTERPRETER */
diff --git a/thirdparty/freetype/src/truetype/ttinterp.h b/thirdparty/freetype/src/truetype/ttinterp.h
index c54c053b29..48d493af80 100644
--- a/thirdparty/freetype/src/truetype/ttinterp.h
+++ b/thirdparty/freetype/src/truetype/ttinterp.h
@@ -460,14 +460,6 @@ FT_BEGIN_HEADER
FT_LOCAL( void )
TT_Clear_CodeRange( TT_ExecContext exec,
FT_Int range );
-
-
- FT_LOCAL( FT_Error )
- Update_Max( FT_Memory memory,
- FT_ULong* size,
- FT_ULong multiplier,
- void* _pbuff,
- FT_ULong new_max );
#endif /* TT_USE_BYTECODE_INTERPRETER */
@@ -536,7 +528,7 @@ FT_BEGIN_HEADER
* invoked by the TrueType debugger.
*/
FT_EXPORT( FT_Error )
- TT_RunIns( TT_ExecContext exec );
+ TT_RunIns( void* exec );
FT_END_HEADER
diff --git a/thirdparty/freetype/src/truetype/ttobjs.c b/thirdparty/freetype/src/truetype/ttobjs.c
index 4a8873fd8c..958fa54d42 100644
--- a/thirdparty/freetype/src/truetype/ttobjs.c
+++ b/thirdparty/freetype/src/truetype/ttobjs.c
@@ -312,7 +312,8 @@
#define TRICK_SFNT_IDS_NUM_FACES 31
static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES]
- [TRICK_SFNT_IDS_PER_FACE] = {
+ [TRICK_SFNT_IDS_PER_FACE] =
+ {
#define TRICK_SFNT_ID_cvt 0
#define TRICK_SFNT_ID_fpgm 1
@@ -581,7 +582,7 @@
FT_Bool result = FALSE;
TT_Face face = (TT_Face)ttface;
- FT_UInt asize;
+ FT_ULong asize;
FT_ULong i;
FT_ULong glyph_index = 0;
FT_UInt count = 0;
@@ -589,7 +590,7 @@
for( i = 0; i < face->num_locations; i++ )
{
- tt_face_get_location( face, i, &asize );
+ tt_face_get_location( ttface, i, &asize );
if ( asize > 0 )
{
count += 1;
@@ -777,7 +778,6 @@
}
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-
{
FT_UInt instance_index = (FT_UInt)face_index >> 16;
@@ -785,14 +785,11 @@
if ( FT_HAS_MULTIPLE_MASTERS( ttface ) &&
instance_index > 0 )
{
- error = TT_Set_Named_Instance( face, instance_index );
+ error = FT_Set_Named_Instance( ttface, instance_index );
if ( error )
goto Exit;
-
- tt_apply_mvar( face );
}
}
-
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
/* initialize standard glyph loading routines */
@@ -858,7 +855,7 @@
face->cvt_program_size = 0;
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- tt_done_blend( face );
+ tt_done_blend( ttface );
face->blend = NULL;
#endif
}
@@ -1338,39 +1335,29 @@
/**************************************************************************
*
* @Function:
- * tt_size_reset
+ * tt_size_reset_height
*
* @Description:
- * Reset a TrueType size when resolutions and character dimensions
- * have been changed.
+ * Recompute a TrueType size's ascender, descender, and height
+ * when resolutions and character dimensions have been changed.
+ * Used for variation fonts as an iterator function.
*
* @Input:
- * size ::
- * A handle to the target size object.
- *
- * only_height ::
- * Only recompute ascender, descender, and height;
- * this flag is used for variation fonts where
- * `tt_size_reset' is used as an iterator function.
+ * ft_size ::
+ * A handle to the target TT_Size object. This function will be called
+ * through a `FT_Size_Reset_Func` pointer which takes `FT_Size`. This
+ * function must take `FT_Size` as a result. The passed `FT_Size` is
+ * expected to point to a `TT_Size`.
*/
FT_LOCAL_DEF( FT_Error )
- tt_size_reset( TT_Size size,
- FT_Bool only_height )
+ tt_size_reset_height( FT_Size ft_size )
{
- TT_Face face;
- FT_Size_Metrics* size_metrics;
-
-
- face = (TT_Face)size->root.face;
-
- /* nothing to do for CFF2 */
- if ( face->is_cff2 )
- return FT_Err_Ok;
+ TT_Size size = (TT_Size)ft_size;
+ TT_Face face = (TT_Face)size->root.face;
+ FT_Size_Metrics* size_metrics = &size->hinted_metrics;
size->ttmetrics.valid = FALSE;
- size_metrics = &size->hinted_metrics;
-
/* copy the result from base layer */
*size_metrics = size->root.metrics;
@@ -1397,12 +1384,34 @@
size->ttmetrics.valid = TRUE;
- if ( only_height )
- {
- /* we must not recompute the scaling values here since */
- /* `tt_size_reset' was already called (with only_height = 0) */
- return FT_Err_Ok;
- }
+ return FT_Err_Ok;
+ }
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * tt_size_reset
+ *
+ * @Description:
+ * Reset a TrueType size when resolutions and character dimensions
+ * have been changed.
+ *
+ * @Input:
+ * size ::
+ * A handle to the target size object.
+ */
+ FT_LOCAL_DEF( FT_Error )
+ tt_size_reset( TT_Size size )
+ {
+ FT_Error error;
+ TT_Face face = (TT_Face)size->root.face;
+ FT_Size_Metrics* size_metrics = &size->hinted_metrics;
+
+
+ error = tt_size_reset_height( (FT_Size)size );
+ if ( error )
+ return error;
if ( face->header.Flags & 8 )
{
diff --git a/thirdparty/freetype/src/truetype/ttobjs.h b/thirdparty/freetype/src/truetype/ttobjs.h
index bc6fbe7f19..d1834c046f 100644
--- a/thirdparty/freetype/src/truetype/ttobjs.h
+++ b/thirdparty/freetype/src/truetype/ttobjs.h
@@ -391,8 +391,10 @@ FT_BEGIN_HEADER
#endif /* TT_USE_BYTECODE_INTERPRETER */
FT_LOCAL( FT_Error )
- tt_size_reset( TT_Size size,
- FT_Bool only_height );
+ tt_size_reset_height( FT_Size size );
+
+ FT_LOCAL( FT_Error )
+ tt_size_reset( TT_Size size );
/**************************************************************************
diff --git a/thirdparty/freetype/src/truetype/ttpload.c b/thirdparty/freetype/src/truetype/ttpload.c
index e08bf309e3..54a64c7b46 100644
--- a/thirdparty/freetype/src/truetype/ttpload.c
+++ b/thirdparty/freetype/src/truetype/ttpload.c
@@ -180,10 +180,11 @@
FT_LOCAL_DEF( FT_ULong )
- tt_face_get_location( TT_Face face,
- FT_UInt gindex,
- FT_UInt *asize )
+ tt_face_get_location( FT_Face face, /* TT_Face */
+ FT_UInt gindex,
+ FT_ULong *asize )
{
+ TT_Face ttface = (TT_Face)face;
FT_ULong pos1, pos2;
FT_Byte* p;
FT_Byte* p_limit;
@@ -191,12 +192,12 @@
pos1 = pos2 = 0;
- if ( gindex < face->num_locations )
+ if ( gindex < ttface->num_locations )
{
- if ( face->header.Index_To_Loc_Format != 0 )
+ if ( ttface->header.Index_To_Loc_Format != 0 )
{
- p = face->glyph_locations + gindex * 4;
- p_limit = face->glyph_locations + face->num_locations * 4;
+ p = ttface->glyph_locations + gindex * 4;
+ p_limit = ttface->glyph_locations + ttface->num_locations * 4;
pos1 = FT_NEXT_ULONG( p );
pos2 = pos1;
@@ -206,8 +207,8 @@
}
else
{
- p = face->glyph_locations + gindex * 2;
- p_limit = face->glyph_locations + face->num_locations * 2;
+ p = ttface->glyph_locations + gindex * 2;
+ p_limit = ttface->glyph_locations + ttface->num_locations * 2;
pos1 = FT_NEXT_USHORT( p );
pos2 = pos1;
@@ -221,30 +222,30 @@
}
/* Check broken location data. */
- if ( pos1 > face->glyf_len )
+ if ( pos1 > ttface->glyf_len )
{
FT_TRACE1(( "tt_face_get_location:"
" too large offset (0x%08lx) found for glyph index %d,\n",
pos1, gindex ));
FT_TRACE1(( " "
" exceeding the end of `glyf' table (0x%08lx)\n",
- face->glyf_len ));
+ ttface->glyf_len ));
*asize = 0;
return 0;
}
- if ( pos2 > face->glyf_len )
+ if ( pos2 > ttface->glyf_len )
{
/* We try to sanitize the last `loca' entry. */
- if ( gindex == face->num_locations - 2 )
+ if ( gindex == ttface->num_locations - 2 )
{
FT_TRACE1(( "tt_face_get_location:"
" too large size (%ld bytes) found for glyph index %d,\n",
pos2 - pos1, gindex ));
FT_TRACE1(( " "
" truncating at the end of `glyf' table to %ld bytes\n",
- face->glyf_len - pos1 ));
- pos2 = face->glyf_len;
+ ttface->glyf_len - pos1 ));
+ pos2 = ttface->glyf_len;
}
else
{
@@ -253,7 +254,7 @@
pos2, gindex + 1 ));
FT_TRACE1(( " "
" exceeding the end of `glyf' table (0x%08lx)\n",
- face->glyf_len ));
+ ttface->glyf_len ));
*asize = 0;
return 0;
}
@@ -268,9 +269,9 @@
/* We get (intentionally) a wrong, non-zero result in case the */
/* `glyf' table is missing. */
if ( pos2 >= pos1 )
- *asize = (FT_UInt)( pos2 - pos1 );
+ *asize = (FT_ULong)( pos2 - pos1 );
else
- *asize = (FT_UInt)( face->glyf_len - pos1 );
+ *asize = (FT_ULong)( ttface->glyf_len - pos1 );
return pos1;
}
diff --git a/thirdparty/freetype/src/truetype/ttpload.h b/thirdparty/freetype/src/truetype/ttpload.h
index 939e02fe4f..ed229fa461 100644
--- a/thirdparty/freetype/src/truetype/ttpload.h
+++ b/thirdparty/freetype/src/truetype/ttpload.h
@@ -31,9 +31,9 @@ FT_BEGIN_HEADER
FT_Stream stream );
FT_LOCAL( FT_ULong )
- tt_face_get_location( TT_Face face,
- FT_UInt gindex,
- FT_UInt *asize );
+ tt_face_get_location( FT_Face face,
+ FT_UInt gindex,
+ FT_ULong *asize );
FT_LOCAL( void )
tt_face_done_loca( TT_Face face );
diff --git a/thirdparty/freetype/src/truetype/ttsubpix.c b/thirdparty/freetype/src/truetype/ttsubpix.c
index d811beef0d..aed4a1a274 100644
--- a/thirdparty/freetype/src/truetype/ttsubpix.c
+++ b/thirdparty/freetype/src/truetype/ttsubpix.c
@@ -1004,7 +1004,7 @@
/* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */
/* ANSI C doesn't like empty source files */
- typedef int _tt_subpix_dummy;
+ typedef int tt_subpix_dummy_;
#endif /* !(TT_USE_BYTECODE_INTERPRETER && */
/* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */
diff --git a/thirdparty/freetype/src/type1/t1afm.c b/thirdparty/freetype/src/type1/t1afm.c
index 787aa92c98..d9b9398b01 100644
--- a/thirdparty/freetype/src/type1/t1afm.c
+++ b/thirdparty/freetype/src/type1/t1afm.c
@@ -299,7 +299,7 @@
/* ascender and descender are optional and could both be zero */
/* check if values are meaningful before overriding defaults */
if ( fi->Ascender > fi->Descender )
- {
+ {
/* no `U' suffix here to 0x8000! */
t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 );
t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 );
@@ -405,7 +405,7 @@
#else /* T1_CONFIG_OPTION_NO_AFM */
/* ANSI C doesn't like empty source files */
- typedef int _t1_afm_dummy;
+ typedef int t1_afm_dummy_;
#endif /* T1_CONFIG_OPTION_NO_AFM */
diff --git a/thirdparty/freetype/src/type1/t1driver.c b/thirdparty/freetype/src/type1/t1driver.c
index ded3b264e8..a4cdf372a9 100644
--- a/thirdparty/freetype/src/type1/t1driver.c
+++ b/thirdparty/freetype/src/type1/t1driver.c
@@ -56,28 +56,32 @@
*
*/
- static FT_Error
- t1_get_glyph_name( T1_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ t1_get_glyph_name( FT_Face face, /* T1_Face */
FT_UInt glyph_index,
FT_Pointer buffer,
FT_UInt buffer_max )
{
- FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max );
+ T1_Face t1face = (T1_Face)face;
+
+
+ FT_STRCPYN( buffer, t1face->type1.glyph_names[glyph_index], buffer_max );
return FT_Err_Ok;
}
- static FT_UInt
- t1_get_name_index( T1_Face face,
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_get_name_index( FT_Face face, /* T1_Face */
const FT_String* glyph_name )
{
- FT_Int i;
+ T1_Face t1face = (T1_Face)face;
+ FT_Int i;
- for ( i = 0; i < face->type1.num_glyphs; i++ )
+ for ( i = 0; i < t1face->type1.num_glyphs; i++ )
{
- FT_String* gname = face->type1.glyph_names[i];
+ FT_String* gname = t1face->type1.glyph_names[i];
if ( !ft_strcmp( glyph_name, gname ) )
@@ -90,8 +94,8 @@
static const FT_Service_GlyphDictRec t1_service_glyph_dict =
{
- (FT_GlyphDict_GetNameFunc) t1_get_glyph_name, /* get_name */
- (FT_GlyphDict_NameIndexFunc)t1_get_name_index /* name_index */
+ t1_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */
+ t1_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */
};
@@ -101,9 +105,12 @@
*/
static const char*
- t1_get_ps_name( T1_Face face )
+ t1_get_ps_name( FT_Face face ) /* T1_Face */
{
- return (const char*) face->type1.font_name;
+ T1_Face t1face = (T1_Face)face;
+
+
+ return (const char*) t1face->type1.font_name;
}
@@ -121,30 +128,28 @@
#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
static const FT_Service_MultiMastersRec t1_service_multi_masters =
{
- (FT_Get_MM_Func) T1_Get_Multi_Master, /* get_mm */
- (FT_Set_MM_Design_Func) T1_Set_MM_Design, /* set_mm_design */
- (FT_Set_MM_Blend_Func) T1_Set_MM_Blend, /* set_mm_blend */
- (FT_Get_MM_Blend_Func) T1_Get_MM_Blend, /* get_mm_blend */
- (FT_Get_MM_Var_Func) T1_Get_MM_Var, /* get_mm_var */
- (FT_Set_Var_Design_Func)T1_Set_Var_Design, /* set_var_design */
- (FT_Get_Var_Design_Func)T1_Get_Var_Design, /* get_var_design */
- (FT_Set_Instance_Func) T1_Reset_MM_Blend, /* set_instance */
- (FT_Set_MM_WeightVector_Func)
- T1_Set_MM_WeightVector, /* set_mm_weightvector */
- (FT_Get_MM_WeightVector_Func)
- T1_Get_MM_WeightVector, /* get_mm_weightvector */
- (FT_Var_Load_Delta_Set_Idx_Map_Func)
- NULL, /* load_delta_set_idx_map */
- (FT_Var_Load_Item_Var_Store_Func)
- NULL, /* load_item_variation_store */
- (FT_Var_Get_Item_Delta_Func)
- NULL, /* get_item_delta */
- (FT_Var_Done_Item_Var_Store_Func)
- NULL, /* done_item_variation_store */
- (FT_Var_Done_Delta_Set_Idx_Map_Func)
- NULL, /* done_delta_set_index_map */
- (FT_Get_Var_Blend_Func) NULL, /* get_var_blend */
- (FT_Done_Blend_Func) T1_Done_Blend /* done_blend */
+ T1_Get_Multi_Master, /* FT_Get_MM_Func get_mm */
+ T1_Set_MM_Design, /* FT_Set_MM_Design_Func set_mm_design */
+ T1_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */
+ T1_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */
+ T1_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */
+ T1_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */
+ T1_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */
+ T1_Reset_MM_Blend, /* FT_Set_Named_Instance_Func set_named_instance */
+ NULL, /* FT_Get_Default_Named_Instance_Func get_default_named_instance */
+ T1_Set_MM_WeightVector,
+ /* FT_Set_MM_WeightVector_Func set_mm_weightvector */
+ T1_Get_MM_WeightVector,
+ /* FT_Get_MM_WeightVector_Func get_mm_weightvector */
+
+ NULL, /* FT_Construct_PS_Name_Func construct_ps_name */
+ NULL, /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */
+ NULL, /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */
+ NULL, /* FT_Var_Get_Item_Delta_Func get_item_delta */
+ NULL, /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */
+ NULL, /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */
+ NULL, /* FT_Get_Var_Blend_Func get_var_blend */
+ T1_Done_Blend /* FT_Done_Blend_Func done_blend */
};
#endif
@@ -632,11 +637,11 @@
static const FT_Service_PsInfoRec t1_service_ps_info =
{
- (PS_GetFontInfoFunc) t1_ps_get_font_info, /* ps_get_font_info */
- (PS_GetFontExtraFunc) t1_ps_get_font_extra, /* ps_get_font_extra */
- (PS_HasGlyphNamesFunc) t1_ps_has_glyph_names, /* ps_has_glyph_names */
- (PS_GetFontPrivateFunc)t1_ps_get_font_private, /* ps_get_font_private */
- (PS_GetFontValueFunc) t1_ps_get_font_value, /* ps_get_font_value */
+ t1_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */
+ t1_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */
+ t1_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */
+ t1_ps_get_font_private, /* PS_GetFontPrivateFunc ps_get_font_private */
+ t1_ps_get_font_value, /* PS_GetFontValueFunc ps_get_font_value */
};
@@ -656,9 +661,9 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
t1_service_properties,
- (FT_Properties_SetFunc)ps_property_set, /* set_property */
- (FT_Properties_GetFunc)ps_property_get ) /* get_property */
-
+ ps_property_set, /* FT_Properties_SetFunc set_property */
+ ps_property_get /* FT_Properties_GetFunc get_property */
+ )
/*
* SERVICE LIST
diff --git a/thirdparty/freetype/src/type1/t1load.c b/thirdparty/freetype/src/type1/t1load.c
index 5a1afd8d9f..b292a3cc0e 100644
--- a/thirdparty/freetype/src/type1/t1load.c
+++ b/thirdparty/freetype/src/type1/t1load.c
@@ -73,7 +73,8 @@
#ifdef FT_CONFIG_OPTION_INCREMENTAL
-#define IS_INCREMENTAL FT_BOOL( face->root.internal->incremental_interface )
+#define IS_INCREMENTAL \
+ FT_BOOL( FT_FACE( face )->internal->incremental_interface )
#else
#define IS_INCREMENTAL 0
#endif
@@ -174,10 +175,11 @@
FT_LOCAL_DEF( FT_Error )
- T1_Get_Multi_Master( T1_Face face,
+ T1_Get_Multi_Master( FT_Face face, /* T1_Face */
FT_Multi_Master* master )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_UInt n;
FT_Error error;
@@ -225,11 +227,12 @@
for ( j = 1; j < axismap->num_points; j++ )
{
if ( ncv <= axismap->blend_points[j] )
- return INT_TO_FIXED( axismap->design_points[j - 1] ) +
- ( axismap->design_points[j] - axismap->design_points[j - 1] ) *
- FT_DivFix( ncv - axismap->blend_points[j - 1],
- axismap->blend_points[j] -
- axismap->blend_points[j - 1] );
+ return INT_TO_FIXED( axismap->design_points[j - 1] +
+ FT_MulDiv( ncv - axismap->blend_points[j - 1],
+ axismap->design_points[j] -
+ axismap->design_points[j - 1],
+ axismap->blend_points[j] -
+ axismap->blend_points[j - 1] ) );
}
return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] );
@@ -284,16 +287,17 @@
* arguments needed by the GX var distortable fonts.
*/
FT_LOCAL_DEF( FT_Error )
- T1_Get_MM_Var( T1_Face face,
+ T1_Get_MM_Var( FT_Face face, /* T1_Face */
FT_MM_Var* *master )
{
- FT_Memory memory = face->root.memory;
- FT_MM_Var *mmvar = NULL;
+ T1_Face t1face = (T1_Face)face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_MM_Var *mmvar = NULL;
FT_Multi_Master mmaster;
FT_Error error;
FT_UInt i;
FT_Fixed axiscoords[T1_MAX_MM_AXIS];
- PS_Blend blend = face->blend;
+ PS_Blend blend = t1face->blend;
FT_UShort* axis_flags;
FT_Offset mmvar_size;
@@ -319,9 +323,9 @@
sizeof ( FT_UShort ) );
axis_size = mmaster.num_axis * sizeof ( FT_Var_Axis );
- if ( FT_ALLOC( mmvar, mmvar_size +
- axis_flags_size +
- axis_size ) )
+ if ( FT_QALLOC( mmvar, mmvar_size +
+ axis_flags_size +
+ axis_size ) )
goto Exit;
mmvar->num_axis = mmaster.num_axis;
@@ -332,8 +336,7 @@
/* to make `FT_Get_Var_Axis_Flags' work: the function expects that the */
/* values directly follow the data of `FT_MM_Var' */
axis_flags = (FT_UShort*)( (char*)mmvar + mmvar_size );
- for ( i = 0; i < mmaster.num_axis; i++ )
- axis_flags[i] = 0;
+ FT_ARRAY_ZERO( axis_flags, mmaster.num_axis );
mmvar->axis = (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size );
mmvar->namedstyle = NULL;
@@ -438,32 +441,21 @@
FT_LOCAL_DEF( FT_Error )
- T1_Set_MM_Blend( T1_Face face,
+ T1_Set_MM_Blend( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Error error;
-
-
- error = t1_set_mm_blend( face, num_coords, coords );
- if ( error )
- return error;
-
- if ( num_coords )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
- return FT_Err_Ok;
+ return t1_set_mm_blend( (T1_Face)face, num_coords, coords );
}
FT_LOCAL_DEF( FT_Error )
- T1_Get_MM_Blend( T1_Face face,
+ T1_Get_MM_Blend( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_Fixed axiscoords[4];
FT_UInt i, nc;
@@ -494,11 +486,12 @@
FT_LOCAL_DEF( FT_Error )
- T1_Set_MM_WeightVector( T1_Face face,
+ T1_Set_MM_WeightVector( FT_Face face, /* T1_Face */
FT_UInt len,
FT_Fixed* weightvector )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_UInt i, n;
@@ -522,11 +515,6 @@
for ( ; i < blend->num_designs; i++ )
blend->weight_vector[i] = (FT_Fixed)0;
-
- if ( len )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
}
return FT_Err_Ok;
@@ -534,11 +522,12 @@
FT_LOCAL_DEF( FT_Error )
- T1_Get_MM_WeightVector( T1_Face face,
+ T1_Get_MM_WeightVector( FT_Face face, /* T1_Face */
FT_UInt* len,
FT_Fixed* weightvector )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_UInt i;
@@ -563,12 +552,13 @@
FT_LOCAL_DEF( FT_Error )
- T1_Set_MM_Design( T1_Face face,
+ T1_Set_MM_Design( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Long* coords )
{
+ T1_Face t1face = (T1_Face)face;
FT_Error error;
- PS_Blend blend = face->blend;
+ PS_Blend blend = t1face->blend;
FT_UInt n;
FT_Fixed final_blends[T1_MAX_MM_DESIGNS];
@@ -634,15 +624,10 @@
final_blends[n] = the_blend;
}
- error = t1_set_mm_blend( face, blend->num_axis, final_blends );
+ error = t1_set_mm_blend( t1face, blend->num_axis, final_blends );
if ( error )
return error;
- if ( num_coords )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
return FT_Err_Ok;
}
@@ -650,7 +635,7 @@
/* MM fonts don't have named instances, so only the design is reset */
FT_LOCAL_DEF( FT_Error )
- T1_Reset_MM_Blend( T1_Face face,
+ T1_Reset_MM_Blend( FT_Face face,
FT_UInt instance_index )
{
FT_UNUSED( instance_index );
@@ -665,7 +650,7 @@
* arguments needed by the GX var distortable fonts.
*/
FT_LOCAL_DEF( FT_Error )
- T1_Set_Var_Design( T1_Face face,
+ T1_Set_Var_Design( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
@@ -684,11 +669,12 @@
FT_LOCAL_DEF( FT_Error )
- T1_Get_Var_Design( T1_Face face,
+ T1_Get_Var_Design( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_Fixed axiscoords[4];
FT_UInt i, nc;
@@ -720,10 +706,11 @@
FT_LOCAL_DEF( void )
- T1_Done_Blend( T1_Face face )
+ T1_Done_Blend( FT_Face face ) /* T1_Face */
{
- FT_Memory memory = face->root.memory;
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ PS_Blend blend = t1face->blend;
if ( blend )
@@ -768,20 +755,22 @@
dmap->num_points = 0;
}
- FT_FREE( face->blend );
+ FT_FREE( t1face->blend );
}
}
static void
- parse_blend_axis_types( T1_Face face,
- T1_Loader loader )
+ parse_blend_axis_types( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_TokenRec axis_tokens[T1_MAX_MM_AXIS];
FT_Int n, num_axis;
- FT_Error error = FT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
PS_Blend blend;
- FT_Memory memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
/* take an array of objects */
@@ -801,14 +790,13 @@
}
/* allocate blend if necessary */
- error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+ error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis );
if ( error )
goto Exit;
FT_TRACE4(( " [" ));
- blend = face->blend;
- memory = face->root.memory;
+ blend = t1face->blend;
/* each token is an immediate containing the name of the axis */
for ( n = 0; n < num_axis; n++ )
@@ -856,14 +844,16 @@
static void
- parse_blend_design_positions( T1_Face face,
- T1_Loader loader )
+ parse_blend_design_positions( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS];
FT_Int num_designs;
FT_Int num_axis = 0; /* make compiler happy */
T1_Parser parser = &loader->parser;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_Error error = FT_Err_Ok;
FT_Fixed* design_pos[T1_MAX_MM_DESIGNS];
@@ -921,7 +911,7 @@
}
num_axis = n_axis;
- error = t1_allocate_blend( face,
+ error = t1_allocate_blend( t1face,
(FT_UInt)num_designs,
(FT_UInt)num_axis );
if ( error )
@@ -962,7 +952,7 @@
loader->parser.root.limit = old_limit;
/* a valid BlendDesignPosition has been parsed */
- blend = face->blend;
+ blend = t1face->blend;
if ( blend->design_pos[0] )
FT_FREE( blend->design_pos[0] );
@@ -980,9 +970,11 @@
static void
- parse_blend_design_map( T1_Face face,
- T1_Loader loader )
+ parse_blend_design_map( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
FT_Error error = FT_Err_Ok;
T1_Parser parser = &loader->parser;
PS_Blend blend;
@@ -990,7 +982,7 @@
FT_Int n, num_axis;
FT_Byte* old_cursor;
FT_Byte* old_limit;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
T1_ToTokenArray( parser, axis_tokens,
@@ -1011,10 +1003,10 @@
old_cursor = parser->root.cursor;
old_limit = parser->root.limit;
- error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+ error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis );
if ( error )
goto Exit;
- blend = face->blend;
+ blend = t1face->blend;
FT_TRACE4(( " [" ));
@@ -1089,15 +1081,17 @@
static void
- parse_weight_vector( T1_Face face,
- T1_Loader loader )
+ parse_weight_vector( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS];
FT_Int num_designs;
FT_Error error = FT_Err_Ok;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
T1_Parser parser = &loader->parser;
- PS_Blend blend = face->blend;
+ PS_Blend blend = t1face->blend;
T1_Token token;
FT_Int n;
FT_Byte* old_cursor;
@@ -1122,10 +1116,10 @@
if ( !blend || !blend->num_designs )
{
- error = t1_allocate_blend( face, (FT_UInt)num_designs, 0 );
+ error = t1_allocate_blend( t1face, (FT_UInt)num_designs, 0 );
if ( error )
goto Exit;
- blend = face->blend;
+ blend = t1face->blend;
}
else if ( blend->num_designs != (FT_UInt)num_designs )
{
@@ -1173,11 +1167,15 @@
/* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */
/* we're only interested in the number of array elements */
static void
- parse_buildchar( T1_Face face,
- T1_Loader loader )
+ parse_buildchar( FT_Face face, /* T1_Face */
+ void* loader_ )
{
- face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser,
- 0, NULL, 0 );
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
+
+
+ t1face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser,
+ 0, NULL, 0 );
#ifdef FT_DEBUG_LEVEL_TRACE
{
@@ -1185,7 +1183,7 @@
FT_TRACE4(( " [" ));
- for ( i = 0; i < face->len_buildchar; i++ )
+ for ( i = 0; i < t1face->len_buildchar; i++ )
FT_TRACE4(( " 0" ));
FT_TRACE4(( "]\n" ));
@@ -1335,9 +1333,10 @@
static void
- parse_private( T1_Face face,
- T1_Loader loader )
+ parse_private( FT_Face face,
+ void* loader_ )
{
+ T1_Loader loader = (T1_Loader)loader_;
FT_UNUSED( face );
loader->keywords_encountered |= T1_PRIVATE;
@@ -1401,13 +1400,14 @@
/* and `/CharStrings' dictionaries. */
static void
- t1_parse_font_matrix( T1_Face face,
- T1_Loader loader )
+ t1_parse_font_matrix( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_Parser parser = &loader->parser;
- FT_Matrix* matrix = &face->type1.font_matrix;
- FT_Vector* offset = &face->type1.font_offset;
- FT_Face root = (FT_Face)&face->root;
+ FT_Matrix* matrix = &t1face->type1.font_matrix;
+ FT_Vector* offset = &t1face->type1.font_offset;
FT_Fixed temp[6];
FT_Fixed temp_scale;
FT_Int result;
@@ -1443,7 +1443,7 @@
if ( temp_scale != 0x10000L )
{
/* set units per EM based on FontMatrix values */
- root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
+ face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
temp[0] = FT_DivFix( temp[0], temp_scale );
temp[1] = FT_DivFix( temp[1], temp_scale );
@@ -1471,14 +1471,16 @@
static void
- parse_encoding( T1_Face face,
- T1_Loader loader )
+ parse_encoding( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_Parser parser = &loader->parser;
FT_Byte* cur;
FT_Byte* limit = parser->root.limit;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t1face->psaux;
T1_Skip_Spaces( parser );
@@ -1494,7 +1496,7 @@
/* and we must load it now */
if ( ft_isdigit( *cur ) || *cur == '[' )
{
- T1_Encoding encode = &face->type1.encoding;
+ T1_Encoding encode = &t1face->type1.encoding;
FT_Int count, array_size, n;
PS_Table char_table = &loader->encoding_table;
FT_Memory memory = parser->root.memory;
@@ -1676,7 +1678,7 @@
FT_TRACE4(( "]\n" ));
#endif
- face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
+ t1face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
parser->root.cursor = cur;
}
@@ -1687,21 +1689,21 @@
if ( cur + 17 < limit &&
ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
{
- face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+ t1face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
FT_TRACE4(( " StandardEncoding\n" ));
}
else if ( cur + 15 < limit &&
ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
{
- face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+ t1face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
FT_TRACE4(( " ExpertEncoding\n" ));
}
else if ( cur + 18 < limit &&
ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
{
- face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+ t1face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
FT_TRACE4(( " ISOLatin1Encoding\n" ));
}
@@ -1715,9 +1717,11 @@
static void
- parse_subrs( T1_Face face,
- T1_Loader loader )
+ parse_subrs( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_Parser parser = &loader->parser;
PS_Table table = &loader->subrs;
FT_Memory memory = parser->root.memory;
@@ -1725,7 +1729,7 @@
FT_Int num_subrs;
FT_UInt count;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t1face->psaux;
T1_Skip_Spaces( parser );
@@ -1857,7 +1861,7 @@
/* */
/* thanks to Tom Kacvinsky for pointing this out */
/* */
- if ( face->type1.private_dict.lenIV >= 0 )
+ if ( t1face->type1.private_dict.lenIV >= 0 )
{
FT_Byte* temp = NULL;
@@ -1865,7 +1869,7 @@
/* some fonts define empty subr records -- this is not totally */
/* compliant to the specification (which says they should at */
/* least contain a `return'), but we support them anyway */
- if ( size < (FT_ULong)face->type1.private_dict.lenIV )
+ if ( size < (FT_ULong)t1face->type1.private_dict.lenIV )
{
error = FT_THROW( Invalid_File_Format );
goto Fail;
@@ -1876,9 +1880,11 @@
goto Fail;
FT_MEM_COPY( temp, base, size );
psaux->t1_decrypt( temp, size, 4330 );
- size -= (FT_ULong)face->type1.private_dict.lenIV;
- error = T1_Add_Table( table, (FT_Int)idx,
- temp + face->type1.private_dict.lenIV, size );
+ size -= (FT_ULong)t1face->type1.private_dict.lenIV;
+ error = T1_Add_Table( table,
+ (FT_Int)idx,
+ temp + t1face->type1.private_dict.lenIV,
+ size );
FT_FREE( temp );
}
else
@@ -1910,9 +1916,11 @@
static void
- parse_charstrings( T1_Face face,
- T1_Loader loader )
+ parse_charstrings( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_Parser parser = &loader->parser;
PS_Table code_table = &loader->charstrings;
PS_Table name_table = &loader->glyph_names;
@@ -1920,7 +1928,7 @@
FT_Memory memory = parser->root.memory;
FT_Error error;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t1face->psaux;
FT_Byte* cur = parser->root.cursor;
FT_Byte* limit = parser->root.limit;
@@ -2069,13 +2077,13 @@
notdef_found = 1;
}
- if ( face->type1.private_dict.lenIV >= 0 &&
+ if ( t1face->type1.private_dict.lenIV >= 0 &&
n < num_glyphs + TABLE_EXTEND )
{
FT_Byte* temp = NULL;
- if ( size <= (FT_ULong)face->type1.private_dict.lenIV )
+ if ( size <= (FT_ULong)t1face->type1.private_dict.lenIV )
{
error = FT_THROW( Invalid_File_Format );
goto Fail;
@@ -2086,9 +2094,11 @@
goto Fail;
FT_MEM_COPY( temp, base, size );
psaux->t1_decrypt( temp, size, 4330 );
- size -= (FT_ULong)face->type1.private_dict.lenIV;
- error = T1_Add_Table( code_table, n,
- temp + face->type1.private_dict.lenIV, size );
+ size -= (FT_ULong)t1face->type1.private_dict.lenIV;
+ error = T1_Add_Table( code_table,
+ n,
+ temp + t1face->type1.private_dict.lenIV,
+ size );
FT_FREE( temp );
}
else
@@ -2570,7 +2580,7 @@
{
FT_ERROR(( "T1_Open_Face:"
" number-of-designs != 2 ^^ number-of-axes\n" ));
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
}
if ( face->blend &&
@@ -2590,15 +2600,15 @@
/* font as a normal PS font */
if ( face->blend &&
( !face->blend->num_designs || !face->blend->num_axis ) )
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
/* the font may have no valid WeightVector */
if ( face->blend && !face->blend->weight_vector )
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
/* the font may have no valid BlendDesignPositions */
if ( face->blend && !face->blend->design_pos[0] )
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
/* the font may have no valid BlendDesignMap */
if ( face->blend )
@@ -2609,7 +2619,7 @@
for ( i = 0; i < face->blend->num_axis; i++ )
if ( !face->blend->design_map[i].num_points )
{
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
break;
}
}
diff --git a/thirdparty/freetype/src/type1/t1load.h b/thirdparty/freetype/src/type1/t1load.h
index f8511cccf6..d8c9d2d8ab 100644
--- a/thirdparty/freetype/src/type1/t1load.h
+++ b/thirdparty/freetype/src/type1/t1load.h
@@ -66,52 +66,52 @@ FT_BEGIN_HEADER
#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
FT_LOCAL( FT_Error )
- T1_Get_Multi_Master( T1_Face face,
+ T1_Get_Multi_Master( FT_Face face,
FT_Multi_Master* master );
FT_LOCAL( FT_Error )
- T1_Get_MM_Var( T1_Face face,
+ T1_Get_MM_Var( FT_Face face,
FT_MM_Var* *master );
FT_LOCAL( FT_Error )
- T1_Set_MM_Blend( T1_Face face,
+ T1_Set_MM_Blend( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- T1_Get_MM_Blend( T1_Face face,
+ T1_Get_MM_Blend( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- T1_Set_MM_Design( T1_Face face,
+ T1_Set_MM_Design( FT_Face face,
FT_UInt num_coords,
FT_Long* coords );
FT_LOCAL( FT_Error )
- T1_Reset_MM_Blend( T1_Face face,
+ T1_Reset_MM_Blend( FT_Face face,
FT_UInt instance_index );
FT_LOCAL( FT_Error )
- T1_Get_Var_Design( T1_Face face,
+ T1_Get_Var_Design( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- T1_Set_Var_Design( T1_Face face,
+ T1_Set_Var_Design( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( void )
- T1_Done_Blend( T1_Face face );
+ T1_Done_Blend( FT_Face face );
FT_LOCAL( FT_Error )
- T1_Set_MM_WeightVector( T1_Face face,
+ T1_Set_MM_WeightVector( FT_Face face,
FT_UInt len,
FT_Fixed* weightvector );
FT_LOCAL( FT_Error )
- T1_Get_MM_WeightVector( T1_Face face,
+ T1_Get_MM_WeightVector( FT_Face face,
FT_UInt* len,
FT_Fixed* weightvector );
diff --git a/thirdparty/freetype/src/type1/t1objs.c b/thirdparty/freetype/src/type1/t1objs.c
index 1bb2f15f3a..69e4fd5065 100644
--- a/thirdparty/freetype/src/type1/t1objs.c
+++ b/thirdparty/freetype/src/type1/t1objs.c
@@ -167,8 +167,7 @@
FT_Module module;
- module = FT_Get_Module( slot->face->driver->root.library,
- "pshinter" );
+ module = FT_Get_Module( slot->library, "pshinter" );
if ( module )
{
T1_Hints_Funcs funcs;
@@ -227,7 +226,7 @@
face->len_buildchar = 0;
}
- T1_Done_Blend( face );
+ T1_Done_Blend( t1face );
face->blend = NULL;
#endif
@@ -290,7 +289,8 @@
*
* @Input:
* stream ::
- * input stream where to load font data.
+ * Dummy argument for compatibility with the `FT_Face_InitFunc` API.
+ * Ignored. The stream should be passed through `face->root.stream`.
*
* face_index ::
* The index of the font face in the resource.
diff --git a/thirdparty/freetype/src/type42/t42drivr.c b/thirdparty/freetype/src/type42/t42drivr.c
index ce1528e5db..ee5fd44a9f 100644
--- a/thirdparty/freetype/src/type42/t42drivr.c
+++ b/thirdparty/freetype/src/type42/t42drivr.c
@@ -56,33 +56,41 @@
*
*/
- static FT_Error
- t42_get_glyph_name( T42_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ t42_get_glyph_name( FT_Face face, /* T42_Face */
FT_UInt glyph_index,
FT_Pointer buffer,
FT_UInt buffer_max )
{
- FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max );
+ T42_Face t42face = (T42_Face)face;
+
+
+ FT_STRCPYN( buffer,
+ t42face->type1.glyph_names[glyph_index],
+ buffer_max );
return FT_Err_Ok;
}
- static FT_UInt
- t42_get_name_index( T42_Face face,
+ FT_CALLBACK_DEF( FT_UInt )
+ t42_get_name_index( FT_Face face, /* T42_Face */
const FT_String* glyph_name )
{
- FT_Int i;
+ T42_Face t42face = (T42_Face)face;
+ FT_Int i;
- for ( i = 0; i < face->type1.num_glyphs; i++ )
+ for ( i = 0; i < t42face->type1.num_glyphs; i++ )
{
- FT_String* gname = face->type1.glyph_names[i];
+ FT_String* gname = t42face->type1.glyph_names[i];
if ( glyph_name[0] == gname[0] && !ft_strcmp( glyph_name, gname ) )
- return (FT_UInt)ft_strtol( (const char *)face->type1.charstrings[i],
- NULL, 10 );
+ return (FT_UInt)ft_strtol(
+ (const char *)t42face->type1.charstrings[i],
+ NULL,
+ 10 );
}
return 0;
@@ -102,10 +110,13 @@
*
*/
- static const char*
- t42_get_ps_font_name( T42_Face face )
+ FT_CALLBACK_DEF( const char* )
+ t42_get_ps_font_name( FT_Face face ) /* T42_Face */
{
- return (const char*)face->type1.font_name;
+ T42_Face t42face = (T42_Face)face;
+
+
+ return (const char*)t42face->type1.font_name;
}
@@ -121,7 +132,7 @@
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
t42_ps_get_font_info( FT_Face face,
PS_FontInfoRec* afont_info )
{
@@ -131,7 +142,7 @@
}
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
t42_ps_get_font_extra( FT_Face face,
PS_FontExtraRec* afont_extra )
{
@@ -141,7 +152,7 @@
}
- static FT_Int
+ FT_CALLBACK_DEF( FT_Int )
t42_ps_has_glyph_names( FT_Face face )
{
FT_UNUSED( face );
diff --git a/thirdparty/freetype/src/type42/t42parse.c b/thirdparty/freetype/src/type42/t42parse.c
index 6d765c8c10..764bbd4c4d 100644
--- a/thirdparty/freetype/src/type42/t42parse.c
+++ b/thirdparty/freetype/src/type42/t42parse.c
@@ -34,19 +34,19 @@
static void
- t42_parse_font_matrix( T42_Face face,
- T42_Loader loader );
+ t42_parse_font_matrix( FT_Face face,
+ void* loader_ );
static void
- t42_parse_encoding( T42_Face face,
- T42_Loader loader );
+ t42_parse_encoding( FT_Face face,
+ void* loader_ );
static void
- t42_parse_charstrings( T42_Face face,
- T42_Loader loader );
+ t42_parse_charstrings( FT_Face face,
+ void* loader_ );
static void
- t42_parse_sfnts( T42_Face face,
- T42_Loader loader );
+ t42_parse_sfnts( FT_Face face,
+ void* loader_ );
/* as Type42 fonts have no Private dict, */
@@ -241,12 +241,14 @@
static void
- t42_parse_font_matrix( T42_Face face,
- T42_Loader loader )
+ t42_parse_font_matrix( FT_Face face, /* T42_Face */
+ void* loader_ )
{
- T42_Parser parser = &loader->parser;
- FT_Matrix* matrix = &face->type1.font_matrix;
- FT_Vector* offset = &face->type1.font_offset;
+ T42_Face t42face = (T42_Face)face;
+ T42_Loader loader = (T42_Loader)loader_;
+ T42_Parser parser = &loader->parser;
+ FT_Matrix* matrix = &t42face->type1.font_matrix;
+ FT_Vector* offset = &t42face->type1.font_offset;
FT_Fixed temp[6];
FT_Fixed temp_scale;
FT_Int result;
@@ -299,14 +301,16 @@
static void
- t42_parse_encoding( T42_Face face,
- T42_Loader loader )
+ t42_parse_encoding( FT_Face face,
+ void* loader_ )
{
- T42_Parser parser = &loader->parser;
+ T42_Face t42face = (T42_Face)face;
+ T42_Loader loader = (T42_Loader)loader_;
+ T42_Parser parser = &loader->parser;
FT_Byte* cur;
- FT_Byte* limit = parser->root.limit;
+ FT_Byte* limit = parser->root.limit;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t42face->psaux;
T1_Skip_Spaces( parser );
@@ -322,7 +326,7 @@
/* and we must load it now */
if ( ft_isdigit( *cur ) || *cur == '[' )
{
- T1_Encoding encode = &face->type1.encoding;
+ T1_Encoding encode = &t42face->type1.encoding;
FT_Int count, n;
PS_Table char_table = &loader->encoding_table;
FT_Memory memory = parser->root.memory;
@@ -493,8 +497,8 @@
T1_Skip_Spaces( parser );
}
- face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
- parser->root.cursor = cur;
+ t42face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
+ parser->root.cursor = cur;
}
/* Otherwise, we should have either `StandardEncoding', */
@@ -503,15 +507,15 @@
{
if ( cur + 17 < limit &&
ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
- face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+ t42face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
else if ( cur + 15 < limit &&
ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
- face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+ t42face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
else if ( cur + 18 < limit &&
ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
- face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+ t42face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
else
parser->root.error = FT_ERR( Ignore );
@@ -529,9 +533,11 @@
static void
- t42_parse_sfnts( T42_Face face,
- T42_Loader loader )
+ t42_parse_sfnts( FT_Face face,
+ void* loader_ )
{
+ T42_Face t42face = (T42_Face)face;
+ T42_Loader loader = (T42_Loader)loader_;
T42_Parser parser = &loader->parser;
FT_Memory memory = parser->root.memory;
FT_Byte* cur;
@@ -548,8 +554,8 @@
T42_Load_Status status;
/** There should only be one sfnts array, but free any previous. */
- FT_FREE( face->ttf_data );
- face->ttf_size = 0;
+ FT_FREE( t42face->ttf_data );
+ t42face->ttf_size = 0;
/* The format is */
/* */
@@ -580,7 +586,7 @@
old_string_size = 0;
ttf_count = 0;
ttf_reserved = 12;
- if ( FT_QALLOC( face->ttf_data, ttf_reserved ) )
+ if ( FT_QALLOC( t42face->ttf_data, ttf_reserved ) )
goto Fail;
FT_TRACE2(( "\n" ));
@@ -596,7 +602,7 @@
if ( *cur == ']' )
{
parser->root.cursor++;
- face->ttf_size = ttf_count;
+ t42face->ttf_size = ttf_count;
goto Exit;
}
@@ -707,7 +713,7 @@
/* load offset table, 12 bytes */
if ( ttf_count < 12 )
{
- face->ttf_data[ttf_count++] = string_buf[n];
+ t42face->ttf_data[ttf_count++] = string_buf[n];
continue;
}
else
@@ -715,7 +721,7 @@
FT_Long ttf_reserved_prev = ttf_reserved;
- num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
+ num_tables = 16 * t42face->ttf_data[4] + t42face->ttf_data[5];
status = BEFORE_TABLE_DIR;
ttf_reserved = 12 + 16 * num_tables;
@@ -729,7 +735,7 @@
goto Fail;
}
- if ( FT_QREALLOC( face->ttf_data, ttf_reserved_prev,
+ if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev,
ttf_reserved ) )
goto Fail;
}
@@ -739,7 +745,7 @@
/* the offset table is read; read the table directory */
if ( ttf_count < ttf_reserved )
{
- face->ttf_data[ttf_count++] = string_buf[n];
+ t42face->ttf_data[ttf_count++] = string_buf[n];
continue;
}
else
@@ -755,7 +761,7 @@
for ( i = 0; i < num_tables; i++ )
{
- FT_Byte* p = face->ttf_data + 12 + 16 * i + 12;
+ FT_Byte* p = t42face->ttf_data + 12 + 16 * i + 12;
len = FT_PEEK_ULONG( p );
@@ -781,7 +787,7 @@
FT_TRACE2(( " allocating %ld bytes\n", ttf_reserved ));
FT_TRACE2(( "\n" ));
- if ( FT_QREALLOC( face->ttf_data, ttf_reserved_prev,
+ if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev,
ttf_reserved ) )
goto Fail;
}
@@ -795,7 +801,7 @@
error = FT_THROW( Invalid_File_Format );
goto Fail;
}
- face->ttf_data[ttf_count++] = string_buf[n];
+ t42face->ttf_data[ttf_count++] = string_buf[n];
}
}
@@ -811,8 +817,8 @@
Exit:
if ( parser->root.error )
{
- FT_FREE( face->ttf_data );
- face->ttf_size = 0;
+ FT_FREE( t42face->ttf_data );
+ t42face->ttf_size = 0;
}
if ( allocated )
FT_FREE( string_buf );
@@ -820,9 +826,11 @@
static void
- t42_parse_charstrings( T42_Face face,
- T42_Loader loader )
+ t42_parse_charstrings( FT_Face face, /* T42_Face */
+ void* loader_ )
{
+ T42_Face t42face = (T42_Face)face;
+ T42_Loader loader = (T42_Loader)loader_;
T42_Parser parser = &loader->parser;
PS_Table code_table = &loader->charstrings;
PS_Table name_table = &loader->glyph_names;
@@ -830,7 +838,7 @@
FT_Memory memory = parser->root.memory;
FT_Error error;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t42face->psaux;
FT_Byte* cur;
FT_Byte* limit = parser->root.limit;
diff --git a/thirdparty/freetype/src/winfonts/winfnt.c b/thirdparty/freetype/src/winfonts/winfnt.c
index fa73ae4a93..1160e4ef36 100644
--- a/thirdparty/freetype/src/winfonts/winfnt.c
+++ b/thirdparty/freetype/src/winfonts/winfnt.c
@@ -624,31 +624,34 @@
static FT_Error
- fnt_cmap_init( FNT_CMap cmap,
+ fnt_cmap_init( FT_CMap cmap, /* FNT_CMap */
FT_Pointer pointer )
{
- FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap );
- FNT_Font font = face->font;
+ FNT_CMap fntcmap = (FNT_CMap)cmap;
+ FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap );
+ FNT_Font font = face->font;
FT_UNUSED( pointer );
- cmap->first = (FT_UInt32) font->header.first_char;
- cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 );
+ fntcmap->first = (FT_UInt32)font->header.first_char;
+ fntcmap->count = (FT_UInt32)( font->header.last_char -
+ fntcmap->first + 1 );
return 0;
}
static FT_UInt
- fnt_cmap_char_index( FNT_CMap cmap,
+ fnt_cmap_char_index( FT_CMap cmap, /* FNT_CMap */
FT_UInt32 char_code )
{
- FT_UInt gindex = 0;
+ FNT_CMap fntcmap = (FNT_CMap)cmap;
+ FT_UInt gindex = 0;
- char_code -= cmap->first;
- if ( char_code < cmap->count )
+ char_code -= fntcmap->first;
+ if ( char_code < fntcmap->count )
/* we artificially increase the glyph index; */
/* FNT_Load_Glyph reverts to the right one */
gindex = (FT_UInt)( char_code + 1 );
@@ -656,26 +659,27 @@
}
- static FT_UInt32
- fnt_cmap_char_next( FNT_CMap cmap,
+ static FT_UInt
+ fnt_cmap_char_next( FT_CMap cmap, /* FNT_CMap */
FT_UInt32 *pchar_code )
{
- FT_UInt gindex = 0;
- FT_UInt32 result = 0;
+ FNT_CMap fntcmap = (FNT_CMap)cmap;
+ FT_UInt gindex = 0;
+ FT_UInt32 result = 0;
FT_UInt32 char_code = *pchar_code + 1;
- if ( char_code <= cmap->first )
+ if ( char_code <= fntcmap->first )
{
- result = cmap->first;
+ result = fntcmap->first;
gindex = 1;
}
else
{
- char_code -= cmap->first;
- if ( char_code < cmap->count )
+ char_code -= fntcmap->first;
+ if ( char_code < fntcmap->count )
{
- result = cmap->first + char_code;
+ result = fntcmap->first + char_code;
gindex = (FT_UInt)( char_code + 1 );
}
}
diff --git a/thirdparty/harfbuzz/src/OT/Color/CBDT/CBDT.hh b/thirdparty/harfbuzz/src/OT/Color/CBDT/CBDT.hh
index b125052344..457039bfc6 100644
--- a/thirdparty/harfbuzz/src/OT/Color/CBDT/CBDT.hh
+++ b/thirdparty/harfbuzz/src/OT/Color/CBDT/CBDT.hh
@@ -397,7 +397,6 @@ struct IndexSubtableRecord
TRACE_SERIALIZE (this);
auto *subtable = c->serializer->start_embed<IndexSubtable> ();
- if (unlikely (!subtable)) return_trace (false);
if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false);
auto *old_subtable = get_subtable (base);
@@ -545,7 +544,8 @@ struct IndexSubtableArray
const IndexSubtableRecord*>> *lookup /* OUT */) const
{
bool start_glyph_is_set = false;
- for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++)
+ unsigned num_glyphs = c->plan->num_output_glyphs ();
+ for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
{
hb_codepoint_t old_gid;
if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue;
@@ -576,9 +576,6 @@ struct IndexSubtableArray
{
TRACE_SUBSET (this);
- auto *dst = c->serializer->start_embed<IndexSubtableArray> ();
- if (unlikely (!dst)) return_trace (false);
-
hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup;
build_lookup (c, bitmap_size_context, &lookup);
if (unlikely (!c->serializer->propagate_error (lookup)))
@@ -993,12 +990,10 @@ CBLC::subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- auto *cblc_prime = c->serializer->start_embed<CBLC> ();
-
// Use a vector as a secondary buffer as the tables need to be built in parallel.
hb_vector_t<char> cbdt_prime;
- if (unlikely (!cblc_prime)) return_trace (false);
+ auto *cblc_prime = c->serializer->start_embed<CBLC> ();
if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false);
cblc_prime->version = version;
diff --git a/thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh b/thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh
index 2a47984294..6591bb4380 100644
--- a/thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh
+++ b/thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh
@@ -409,7 +409,6 @@ struct ColorLine
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
- if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
@@ -1434,6 +1433,7 @@ struct PaintComposite
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ c->check_ops (this->min_size) && // PainComposite can get exponential
src.sanitize (c, this) &&
backdrop.sanitize (c, this));
}
@@ -2167,7 +2167,7 @@ struct COLR
if (version == 0 && (!base_it || !layer_it))
return_trace (false);
- COLR *colr_prime = c->serializer->start_embed<COLR> ();
+ auto *colr_prime = c->serializer->start_embed<COLR> ();
if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false);
if (version == 0)
diff --git a/thirdparty/harfbuzz/src/OT/Color/sbix/sbix.hh b/thirdparty/harfbuzz/src/OT/Color/sbix/sbix.hh
index 46ad3fd58e..ce8693cfb1 100644
--- a/thirdparty/harfbuzz/src/OT/Color/sbix/sbix.hh
+++ b/thirdparty/harfbuzz/src/OT/Color/sbix/sbix.hh
@@ -48,7 +48,6 @@ struct SBIXGlyph
{
TRACE_SERIALIZE (this);
SBIXGlyph* new_glyph = c->start_embed<SBIXGlyph> ();
- if (unlikely (!new_glyph)) return_trace (nullptr);
if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr);
new_glyph->xOffset = xOffset;
@@ -143,7 +142,6 @@ struct SBIXStrike
unsigned int num_output_glyphs = c->plan->num_output_glyphs ();
auto* out = c->serializer->start_embed<SBIXStrike> ();
- if (unlikely (!out)) return_trace (false);
auto snap = c->serializer->snapshot ();
if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false);
out->ppem = ppem;
@@ -388,7 +386,6 @@ struct sbix
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed<Array32OfOffset32To<SBIXStrike>> ();
- if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_vector_t<Offset32To<SBIXStrike>*> new_strikes;
@@ -423,8 +420,6 @@ struct sbix
{
TRACE_SUBSET (this);
- sbix *sbix_prime = c->serializer->start_embed<sbix> ();
- if (unlikely (!sbix_prime)) return_trace (false);
if (unlikely (!c->serializer->embed (this->version))) return_trace (false);
if (unlikely (!c->serializer->embed (this->flags))) return_trace (false);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
index 9ca88f788a..25056c9bc3 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
@@ -57,6 +57,9 @@ struct Coverage
public:
DEFINE_SIZE_UNION (2, format);
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
index 5d68e3d15e..3f598d40ef 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
@@ -79,7 +79,7 @@ struct CoverageFormat1_3
{
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
index fa501d659d..9c87542356 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
@@ -122,7 +122,7 @@ struct CoverageFormat2_4
{
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh b/thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh
index c1ff796199..d995ba0d4c 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh
@@ -49,8 +49,6 @@ struct AttachPoint : Array16Of<HBUINT16>
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
-
return_trace (out->serialize (c->serializer, + iter ()));
}
};
@@ -202,7 +200,6 @@ struct CaretValueFormat3
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
if (!c->serializer->embed (caretValueFormat)) return_trace (false);
if (!c->serializer->embed (coordinate)) return_trace (false);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh
index e7e3c5c6d1..8684f60ca5 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh
@@ -25,7 +25,9 @@ struct AnchorFormat3
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+ if (unlikely (!c->check_struct (this))) return_trace (false);
+
+ return_trace (xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
}
void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
@@ -35,9 +37,9 @@ struct AnchorFormat3
*x = font->em_fscale_x (xCoordinate);
*y = font->em_fscale_y (yCoordinate);
- if (font->x_ppem || font->num_coords)
+ if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this))
*x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
- if (font->y_ppem || font->num_coords)
+ if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this))
*y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
}
@@ -45,7 +47,6 @@ struct AnchorFormat3
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->embed (format))) return_trace (false);
if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false);
if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh
index c442efa1ea..bd9b189739 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh
@@ -21,18 +21,25 @@ struct AnchorMatrix
if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
unsigned int count = rows * cols;
if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
+
+ if (c->lazy_some_gpos)
+ return_trace (true);
+
for (unsigned int i = 0; i < count; i++)
if (!matrixZ[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
- const Anchor& get_anchor (unsigned int row, unsigned int col,
- unsigned int cols, bool *found) const
+ const Anchor& get_anchor (hb_ot_apply_context_t *c,
+ unsigned int row, unsigned int col,
+ unsigned int cols, bool *found) const
{
*found = false;
if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
- *found = !matrixZ[row * cols + col].is_null ();
- return this+matrixZ[row * cols + col];
+ auto &offset = matrixZ[row * cols + col];
+ if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor);
+ *found = !offset.is_null ();
+ return this+offset;
}
template <typename Iterator,
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
index b8773ba0aa..a459124dfe 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -278,7 +278,6 @@ struct CursivePosFormat1
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
auto it =
+ hb_zip (this+coverage, entryExitRecord)
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
index ff43ffb8c5..34e2ab8f6e 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
@@ -28,7 +28,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
const Anchor& mark_anchor = this + record.markAnchor;
bool found;
- const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
+ const Anchor& glyph_anchor = anchors.get_anchor (c, glyph_index, mark_class, class_count, &found);
/* If this subtable doesn't have an anchor for this base and this class,
* return false such that the subsequent subtables have a chance at it. */
if (unlikely (!found)) return_trace (false);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
index 31329dfcb5..05e6c0fa54 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -54,8 +54,9 @@ struct PairPosFormat2_4
return_trace (c->check_range ((const void *) values,
count,
stride) &&
- valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
- valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+ (c->lazy_some_gpos ||
+ (valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+ valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride))));
}
bool intersects (const hb_set_t *glyphs) const
@@ -298,11 +299,13 @@ struct PairPosFormat2_4
out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
}
+ unsigned total_len = len1 + len2;
+ hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map));
for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
{
- for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+ for (unsigned class2_idx : class2_idxs)
{
- unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * total_len;
valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map);
valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
index 9faff49909..db301bb816 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
@@ -52,8 +52,9 @@ struct PairSet
unsigned int count = len;
const PairValueRecord *record = &firstPairValueRecord;
- return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
- closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
+ return_trace (c->lazy_some_gpos ||
+ (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
+ closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
}
bool intersects (const hb_set_t *glyphs,
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
index 623e4e66b2..dff1f7316d 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -90,6 +90,7 @@ struct SinglePosFormat1
bool
position_single (hb_font_t *font,
+ hb_blob_t *table_blob,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
@@ -100,7 +101,7 @@ struct SinglePosFormat1
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
- OT::hb_ot_apply_context_t c (1, font, &buffer);
+ OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
valueFormat.apply_value (&c, this, values, pos);
return true;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
index e8f2d7c2c6..168ad3bb8c 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -94,6 +94,7 @@ struct SinglePosFormat2
bool
position_single (hb_font_t *font,
+ hb_blob_t *table_blob,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
@@ -105,7 +106,7 @@ struct SinglePosFormat2
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
- OT::hb_ot_apply_context_t c (1, font, &buffer);
+ OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
valueFormat.apply_value (&c, this,
&values[index * valueFormat.get_len ()],
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh
index 1aa451abcc..461a13d4b7 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh
@@ -118,21 +118,25 @@ struct ValueFormat : HBUINT16
auto *cache = c->var_store_cache;
/* pixel -> fractional pixel */
- if (format & xPlaDevice) {
- if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+ if (format & xPlaDevice)
+ {
+ if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
values++;
}
- if (format & yPlaDevice) {
- if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+ if (format & yPlaDevice)
+ {
+ if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
values++;
}
- if (format & xAdvDevice) {
- if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+ if (format & xAdvDevice)
+ {
+ if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
values++;
}
- if (format & yAdvDevice) {
+ if (format & yAdvDevice)
+ {
/* y_advance values grow downward but font-space grows upward, hence negation */
- if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+ if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
values++;
}
return ret;
@@ -174,6 +178,9 @@ struct ValueFormat : HBUINT16
if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++);
if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++);
+ if (!has_device ())
+ return;
+
if (format & xPlaDevice)
{
add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
@@ -233,14 +240,12 @@ struct ValueFormat : HBUINT16
if (format & ValueFormat::xAdvDevice)
{
-
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
if (format & ValueFormat::yAdvDevice)
{
-
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
@@ -277,11 +282,23 @@ struct ValueFormat : HBUINT16
{
return *static_cast<Offset16To<Device> *> (value);
}
- static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
+ static inline const Offset16To<Device>& get_device (const Value* value)
{
- if (worked) *worked |= bool (*value);
return *static_cast<const Offset16To<Device> *> (value);
}
+ static inline const Device& get_device (const Value* value,
+ bool *worked,
+ const void *base,
+ hb_sanitize_context_t &c)
+ {
+ if (worked) *worked |= bool (*value);
+ auto &offset = *static_cast<const Offset16To<Device> *> (value);
+
+ if (unlikely (!offset.sanitize (&c, base)))
+ return Null(Device);
+
+ return base + offset;
+ }
void add_delta_to_value (HBINT16 *value,
const void *base,
@@ -340,25 +357,26 @@ struct ValueFormat : HBUINT16
bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+
+ if (unlikely (!c->check_range (values, get_size ()))) return_trace (false);
+
+ if (c->lazy_some_gpos)
+ return_trace (true);
+
+ return_trace (!has_device () || sanitize_value_devices (c, base, values));
}
bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
{
TRACE_SANITIZE (this);
- unsigned int len = get_len ();
+ unsigned size = get_size ();
- if (!c->check_range (values, count, get_size ())) return_trace (false);
+ if (!c->check_range (values, count, size)) return_trace (false);
- if (!has_device ()) return_trace (true);
+ if (c->lazy_some_gpos)
+ return_trace (true);
- for (unsigned int i = 0; i < count; i++) {
- if (!sanitize_value_devices (c, base, values))
- return_trace (false);
- values += len;
- }
-
- return_trace (true);
+ return_trace (sanitize_values_stride_unsafe (c, base, values, count, size));
}
/* Just sanitize referenced Device tables. Doesn't check the values themselves. */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh
index 968bba0481..b849494d88 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh
@@ -8,8 +8,6 @@ namespace OT {
namespace Layout {
namespace GSUB_impl {
-typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
-
template<typename Iterator>
static void SingleSubst_serialize (hb_serialize_context_t *c,
Iterator it);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
index 8674a52fb5..db3fc55f77 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
@@ -13,12 +13,13 @@ struct Ligature
public:
typename Types::HBGlyphID
ligGlyph; /* GlyphID of ligature to substitute */
- HeadlessArrayOf<typename Types::HBGlyphID>
+ HeadlessArray16Of<typename Types::HBGlyphID>
component; /* Array of component GlyphIDs--start
* with the second component--ordered
* in writing direction */
public:
DEFINE_SIZE_ARRAY (Types::size + 2, component);
+ DEFINE_SIZE_MAX (65536 * Types::HBGlyphID::static_size);
bool sanitize (hb_sanitize_context_t *c) const
{
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
index 2c2e1aa44f..916fa281b3 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
@@ -191,7 +191,6 @@ struct ReverseChainSingleSubstFormat1
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed (this);
- if (unlikely (!c->serializer->check_success (out))) return_trace (false);
if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
index ae3292f329..a26cf8c6a6 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
@@ -53,7 +53,7 @@ struct Sequence
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
- "replaced glyph at %u (multiple subtitution)",
+ "replaced glyph at %u (multiple substitution)",
c->buffer->idx - 1u);
}
diff --git a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
index d81fadf7c8..60858a5a58 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
@@ -90,24 +90,36 @@ struct CompositeGlyphRecord
static void transform (const float (&matrix)[4],
hb_array_t<contour_point_t> points)
{
- auto arrayZ = points.arrayZ;
- unsigned count = points.length;
-
if (matrix[0] != 1.f || matrix[1] != 0.f ||
matrix[2] != 0.f || matrix[3] != 1.f)
- for (unsigned i = 0; i < count; i++)
- arrayZ[i].transform (matrix);
+ for (auto &point : points)
+ point.transform (matrix);
}
static void translate (const contour_point_t &trans,
hb_array_t<contour_point_t> points)
{
- auto arrayZ = points.arrayZ;
- unsigned count = points.length;
-
- if (trans.x != 0.f || trans.y != 0.f)
- for (unsigned i = 0; i < count; i++)
- arrayZ[i].translate (trans);
+ if (HB_OPTIMIZE_SIZE_VAL)
+ {
+ if (trans.x != 0.f || trans.y != 0.f)
+ for (auto &point : points)
+ point.translate (trans);
+ }
+ else
+ {
+ if (trans.x != 0.f && trans.y != 0.f)
+ for (auto &point : points)
+ point.translate (trans);
+ else
+ {
+ if (trans.x != 0.f)
+ for (auto &point : points)
+ point.x += trans.x;
+ else if (trans.y != 0.f)
+ for (auto &point : points)
+ point.y += trans.y;
+ }
+ }
}
void transform_points (hb_array_t<contour_point_t> points,
@@ -131,9 +143,8 @@ struct CompositeGlyphRecord
float matrix[4];
contour_point_t trans;
get_transformation (matrix, trans);
- points.alloc (points.length + 4); // For phantom points
- if (unlikely (!points.resize (points.length + 1))) return false;
- points.arrayZ[points.length - 1] = trans;
+ if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points
+ points.push (trans);
return true;
}
@@ -382,7 +393,7 @@ struct CompositeGlyph
{
/* last 4 points in points_with_deltas are phantom points and should not be included */
if (i >= points_with_deltas.length - 4) {
- free (o);
+ hb_free (o);
return false;
}
diff --git a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
index 2bd5fe8206..2611c1e21d 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
@@ -114,8 +114,8 @@ struct Glyph
if (type != EMPTY)
{
- plan->bounds_width_map.set (new_gid, xMax - xMin);
- plan->bounds_height_map.set (new_gid, yMax - yMin);
+ plan->bounds_width_vec[new_gid] = xMax - xMin;
+ plan->bounds_height_vec[new_gid] = yMax - yMin;
}
unsigned len = all_points.length;
@@ -124,10 +124,12 @@ struct Glyph
float topSideY = all_points[len - 2].y;
float bottomSideY = all_points[len - 1].y;
+ uint32_t hash = hb_hash (new_gid);
+
signed hori_aw = roundf (rightSideX - leftSideX);
if (hori_aw < 0) hori_aw = 0;
int lsb = roundf (xMin - leftSideX);
- plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
+ plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb));
//flag value should be computed using non-empty glyphs
if (type != EMPTY && lsb != xMin)
plan->head_maxp_info.allXMinIsLsb = false;
@@ -135,7 +137,7 @@ struct Glyph
signed vert_aw = roundf (topSideY - bottomSideY);
if (vert_aw < 0) vert_aw = 0;
int tsb = roundf (topSideY - yMax);
- plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
+ plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb));
}
bool compile_header_bytes (const hb_subset_plan_t *plan,
@@ -369,9 +371,11 @@ struct Glyph
}
#ifndef HB_NO_VAR
- glyf_accelerator.gvar->apply_deltas_to_points (gid,
- coords,
- points.as_array ().sub_array (old_length));
+ if (coords)
+ glyf_accelerator.gvar->apply_deltas_to_points (gid,
+ coords,
+ points.as_array ().sub_array (old_length),
+ phantom_only && type == SIMPLE);
#endif
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
@@ -379,7 +383,7 @@ struct Glyph
if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
{
if (unlikely (!points_with_deltas->resize (points.length))) return false;
- points_with_deltas->copy_vector (points);
+ *points_with_deltas = points;
}
switch (type) {
@@ -417,14 +421,17 @@ struct Glyph
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
- float matrix[4];
- contour_point_t default_trans;
- item.get_transformation (matrix, default_trans);
+ if (comp_points) // Empty in case of phantom_only
+ {
+ float matrix[4];
+ contour_point_t default_trans;
+ item.get_transformation (matrix, default_trans);
- /* Apply component transformation & translation (with deltas applied) */
- item.transform_points (comp_points, matrix, points[comp_index]);
+ /* Apply component transformation & translation (with deltas applied) */
+ item.transform_points (comp_points, matrix, points[comp_index]);
+ }
- if (item.is_anchored ())
+ if (item.is_anchored () && !phantom_only)
{
unsigned int p1, p2;
item.get_anchor_points (p1, p2);
@@ -466,7 +473,10 @@ struct Glyph
assert (record_points.length == item_num_points);
auto component_coords = coords;
- if (item.is_reset_unspecified_axes ())
+ /* Copying coords is expensive; so we have put an arbitrary
+ * limit on the max number of coords for now. */
+ if (item.is_reset_unspecified_axes () ||
+ coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES)
component_coords = hb_array<int> ();
coord_setter_t coord_setter (component_coords);
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
index 555bcee346..1d42cc2925 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
@@ -154,10 +154,9 @@ struct SimpleGlyph
{
int v = 0;
- unsigned count = points_.length;
- for (unsigned i = 0; i < count; i++)
+ for (auto &point : points_)
{
- unsigned flag = points_.arrayZ[i].flag;
+ unsigned flag = point.flag;
if (flag & short_flag)
{
if (unlikely (p + 1 > end)) return false;
@@ -175,7 +174,7 @@ struct SimpleGlyph
p += HBINT16::static_size;
}
}
- points_.arrayZ[i].*m = v;
+ point.*m = v;
}
return true;
}
@@ -192,9 +191,10 @@ struct SimpleGlyph
unsigned old_length = points.length;
points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
- if (!points.resize (points.length + num_points, false)) return false;
+ if (unlikely (!points.resize (points.length + num_points, false))) return false;
auto points_ = points.as_array ().sub_array (old_length);
- hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points);
+ if (!phantom_only)
+ hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points);
if (phantom_only) return true;
for (int i = 0; i < num_contours; i++)
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
index 26dc374eab..8099d3c126 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
@@ -22,7 +22,7 @@ struct SubsetGlyph
bool serialize (hb_serialize_context_t *c,
bool use_short_loca,
- const hb_subset_plan_t *plan)
+ const hb_subset_plan_t *plan) const
{
TRACE_SERIALIZE (this);
@@ -40,7 +40,7 @@ struct SubsetGlyph
pad = 0;
while (pad_length > 0)
{
- c->embed (pad);
+ (void) c->embed (pad);
pad_length--;
}
diff --git a/thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh
index 6dc6fd9ded..50cbece3ca 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh
@@ -214,7 +214,7 @@ struct VarCompositeGlyphRecord
points.alloc (points.length + num_points + 4); // For phantom points
if (unlikely (!points.resize (points.length + num_points, false))) return false;
contour_point_t *rec_points = points.arrayZ + (points.length - num_points);
- memset (rec_points, 0, num_points * sizeof (rec_points[0]));
+ hb_memset (rec_points, 0, num_points * sizeof (rec_points[0]));
unsigned fl = flags;
diff --git a/thirdparty/harfbuzz/src/OT/glyf/coord-setter.hh b/thirdparty/harfbuzz/src/OT/glyf/coord-setter.hh
index df64ed5af7..cf05929362 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/coord-setter.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/coord-setter.hh
@@ -16,6 +16,8 @@ struct coord_setter_t
int& operator [] (unsigned idx)
{
+ if (unlikely (idx >= HB_GLYF_VAR_COMPOSITE_MAX_AXES))
+ return Crap(int);
if (coords.length < idx + 1)
coords.resize (idx + 1);
return coords[idx];
diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh
index 30106b2b98..d0a5a132f0 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh
@@ -12,24 +12,44 @@ namespace OT {
namespace glyf_impl {
-template<typename IteratorIn, typename IteratorOut,
- hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
- hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
+template<typename IteratorIn, typename TypeOut,
+ hb_requires (hb_is_source_of (IteratorIn, unsigned int))>
static void
-_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest)
+_write_loca (IteratorIn&& it,
+ const hb_sorted_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
+ bool short_offsets,
+ TypeOut *dest,
+ unsigned num_offsets)
{
unsigned right_shift = short_offsets ? 1 : 0;
- unsigned int offset = 0;
- dest << 0;
- + it
- | hb_map ([=, &offset] (unsigned int padded_size)
- {
- offset += padded_size;
- DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset);
- return offset >> right_shift;
- })
- | hb_sink (dest)
- ;
+ unsigned offset = 0;
+ TypeOut value;
+ value = 0;
+ *dest++ = value;
+ hb_codepoint_t last = 0;
+ for (auto _ : new_to_old_gid_list)
+ {
+ hb_codepoint_t gid = _.first;
+ for (; last < gid; last++)
+ {
+ DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset);
+ *dest++ = value;
+ }
+
+ unsigned padded_size = *it++;
+ offset += padded_size;
+ DEBUG_MSG (SUBSET, nullptr, "loca entry gid %u offset %u padded-size %u", gid, offset, padded_size);
+ value = offset >> right_shift;
+ *dest++ = value;
+
+ last++; // Skip over gid
+ }
+ unsigned num_glyphs = num_offsets - 1;
+ for (; last < num_glyphs; last++)
+ {
+ DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset);
+ *dest++ = value;
+ }
}
static bool
@@ -67,11 +87,14 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
template<typename Iterator,
hb_requires (hb_is_source_of (Iterator, unsigned int))>
static bool
-_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca)
+_add_loca_and_head (hb_subset_context_t *c,
+ Iterator padded_offsets,
+ bool use_short_loca)
{
- unsigned num_offsets = padded_offsets.len () + 1;
+ unsigned num_offsets = c->plan->num_output_glyphs () + 1;
unsigned entry_size = use_short_loca ? 2 : 4;
- char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
+
+ char *loca_prime_data = (char *) hb_malloc (entry_size * num_offsets);
if (unlikely (!loca_prime_data)) return false;
@@ -79,9 +102,9 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s
entry_size, num_offsets, entry_size * num_offsets);
if (use_short_loca)
- _write_loca (padded_offsets, true, hb_array ((HBUINT16 *) loca_prime_data, num_offsets));
+ _write_loca (padded_offsets, c->plan->new_to_old_gid_list, true, (HBUINT16 *) loca_prime_data, num_offsets);
else
- _write_loca (padded_offsets, false, hb_array ((HBUINT32 *) loca_prime_data, num_offsets));
+ _write_loca (padded_offsets, c->plan->new_to_old_gid_list, false, (HBUINT32 *) loca_prime_data, num_offsets);
hb_blob_t *loca_blob = hb_blob_create (loca_prime_data,
entry_size * num_offsets,
@@ -89,8 +112,8 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s
loca_prime_data,
hb_free);
- bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
- && _add_head_and_set_loca_version (plan, use_short_loca);
+ bool result = c->plan->add_table (HB_OT_TAG_loca, loca_blob)
+ && _add_head_and_set_loca_version (c->plan, use_short_loca);
hb_blob_destroy (loca_blob);
return result;
diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
index dd08dda6ee..6300cf4be0 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
@@ -85,75 +85,72 @@ struct glyf
return_trace (false);
}
- glyf *glyf_prime = c->serializer->start_embed <glyf> ();
- if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
-
hb_font_t *font = nullptr;
if (c->plan->normalized_coords)
{
font = _create_font_for_instancing (c->plan);
- if (unlikely (!font)) return false;
+ if (unlikely (!font))
+ return_trace (false);
}
hb_vector_t<unsigned> padded_offsets;
- unsigned num_glyphs = c->plan->num_output_glyphs ();
- if (unlikely (!padded_offsets.resize (num_glyphs)))
- {
- hb_font_destroy (font);
- return false;
- }
+ if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true)))
+ return_trace (false);
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
if (!_populate_subset_glyphs (c->plan, font, glyphs))
{
hb_font_destroy (font);
- return false;
+ return_trace (false);
}
if (font)
hb_font_destroy (font);
unsigned max_offset = 0;
- for (unsigned i = 0; i < num_glyphs; i++)
+ for (auto &g : glyphs)
{
- padded_offsets[i] = glyphs[i].padded_size ();
- max_offset += padded_offsets[i];
+ unsigned size = g.padded_size ();
+ padded_offsets.push (size);
+ max_offset += size;
}
bool use_short_loca = false;
if (likely (!c->plan->force_long_loca))
use_short_loca = max_offset < 0x1FFFF;
- if (!use_short_loca) {
- for (unsigned i = 0; i < num_glyphs; i++)
- padded_offsets[i] = glyphs[i].length ();
+ if (!use_short_loca)
+ {
+ padded_offsets.resize (0);
+ for (auto &g : glyphs)
+ padded_offsets.push (g.length ());
}
- bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan);
+ auto *glyf_prime = c->serializer->start_embed <glyf> ();
+ bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
if (c->plan->normalized_coords && !c->plan->pinned_at_default)
_free_compiled_subset_glyphs (glyphs);
- if (!result) return false;
-
- if (unlikely (c->serializer->in_error ())) return_trace (false);
+ if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c,
+ padded_offsets.iter (),
+ use_short_loca))))
+ return_trace (false);
- return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
- padded_offsets.iter (),
- use_short_loca)));
+ return result;
}
bool
_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_font_t *font,
- hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
+ hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const;
hb_font_t *
_create_font_for_instancing (const hb_subset_plan_t *plan) const;
void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const
{
- for (unsigned i = 0; i < glyphs.length; i++)
- glyphs[i].free_compiled_bytes ();
+ for (auto &g : glyphs)
+ g.free_compiled_bytes ();
}
protected:
@@ -222,13 +219,14 @@ struct glyf_accelerator_t
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only)))
return false;
+ unsigned count = all_points.length;
+ assert (count >= glyf_impl::PHANTOM_COUNT);
+ count -= glyf_impl::PHANTOM_COUNT;
+
if (consumer.is_consuming_contour_points ())
{
- unsigned count = all_points.length;
- assert (count >= glyf_impl::PHANTOM_COUNT);
- count -= glyf_impl::PHANTOM_COUNT;
- for (unsigned point_index = 0; point_index < count; point_index++)
- consumer.consume_point (all_points[point_index]);
+ for (auto &point : all_points.as_array ().sub_array (0, count))
+ consumer.consume_point (point);
consumer.points_end ();
}
@@ -236,7 +234,7 @@ struct glyf_accelerator_t
contour_point_t *phantoms = consumer.get_phantoms_sink ();
if (phantoms)
for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i)
- phantoms[i] = all_points[all_points.length - glyf_impl::PHANTOM_COUNT + i];
+ phantoms[i] = all_points.arrayZ[count + i];
return true;
}
@@ -299,6 +297,7 @@ struct glyf_accelerator_t
if (extents) bounds = contour_bounds_t ();
}
+ HB_ALWAYS_INLINE
void consume_point (const contour_point_t &point) { bounds.add (point); }
void points_end () { bounds.get_extents (font, extents, scaled); }
@@ -431,16 +430,17 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
{
OT::glyf_accelerator_t glyf (plan->source);
- unsigned num_glyphs = plan->num_output_glyphs ();
- if (!glyphs.resize (num_glyphs)) return false;
+ if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false;
- for (auto p : plan->glyph_map->iter ())
+ for (const auto &pair : plan->new_to_old_gid_list)
{
- unsigned new_gid = p.second;
- glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
- subset_glyph.old_gid = p.first;
+ hb_codepoint_t new_gid = pair.first;
+ hb_codepoint_t old_gid = pair.second;
+ glyf_impl::SubsetGlyph *p = glyphs.push ();
+ glyf_impl::SubsetGlyph& subset_glyph = *p;
+ subset_glyph.old_gid = old_gid;
- if (unlikely (new_gid == 0 &&
+ if (unlikely (old_gid == 0 && new_gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
!plan->normalized_coords)
subset_glyph.source_glyph = glyf_impl::Glyph ();
@@ -487,7 +487,7 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
{
hb_variation_t var;
var.tag = _.first;
- var.value = _.second;
+ var.value = _.second.middle;
vars.push (var);
}
diff --git a/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh b/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh
index f7f732d336..f550524503 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh
@@ -21,11 +21,11 @@ struct path_builder_t
operator bool () const { return has_data; }
bool has_data = false;
- float x = 0.;
- float y = 0.;
+ float x;
+ float y;
- optional_point_t lerp (optional_point_t p, float t)
- { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
+ optional_point_t mid (optional_point_t p)
+ { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); }
} first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2;
path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) :
@@ -37,6 +37,7 @@ struct path_builder_t
* https://stackoverflow.com/a/20772557
*
* Cubic support added. */
+ HB_ALWAYS_INLINE
void consume_point (const contour_point_t &point)
{
bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
@@ -46,7 +47,7 @@ struct path_builder_t
bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
#endif
optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
- if (!first_oncurve)
+ if (unlikely (!first_oncurve))
{
if (is_on_curve)
{
@@ -62,7 +63,7 @@ struct path_builder_t
}
else if (first_offcurve)
{
- optional_point_t mid = first_offcurve.lerp (p, .5f);
+ optional_point_t mid = first_offcurve.mid (p);
first_oncurve = mid;
last_offcurve = p;
draw_session->move_to (mid.x, mid.y);
@@ -98,7 +99,7 @@ struct path_builder_t
}
else
{
- optional_point_t mid = last_offcurve.lerp (p, .5f);
+ optional_point_t mid = last_offcurve.mid (p);
if (is_cubic)
{
@@ -123,13 +124,13 @@ struct path_builder_t
}
}
- if (point.is_end_point)
+ if (unlikely (point.is_end_point))
{
if (first_offcurve && last_offcurve)
{
- optional_point_t mid = last_offcurve.lerp (first_offcurve2 ?
- first_offcurve2 :
- first_offcurve, .5f);
+ optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
+ first_offcurve2 :
+ first_offcurve);
if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
diff --git a/thirdparty/harfbuzz/src/OT/name/name.hh b/thirdparty/harfbuzz/src/OT/name/name.hh
index c1839f3b68..c8de101345 100644
--- a/thirdparty/harfbuzz/src/OT/name/name.hh
+++ b/thirdparty/harfbuzz/src/OT/name/name.hh
@@ -359,7 +359,7 @@ struct name
record.nameID = ids.name_id;
record.length = 0; // handled in NameRecord copy()
record.offset = 0;
- memcpy (name_records, &record, NameRecord::static_size);
+ hb_memcpy (name_records, &record, NameRecord::static_size);
name_records++;
}
#endif
@@ -384,10 +384,7 @@ struct name
bool subset (hb_subset_context_t *c) const
{
- TRACE_SUBSET (this);
-
- name *name_prime = c->serializer->start_embed<name> ();
- if (unlikely (!name_prime)) return_trace (false);
+ auto *name_prime = c->serializer->start_embed<name> ();
#ifdef HB_EXPERIMENTAL_API
const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides =
@@ -436,7 +433,7 @@ struct name
if (!name_table_overrides->is_empty ())
{
if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true)))
- return_trace (false);
+ return false;
for (const auto& record_ids : name_table_overrides->keys ())
{
if (name_table_overrides->get (record_ids).length == 0)
@@ -448,13 +445,13 @@ struct name
}
#endif
- return (name_prime->serialize (c->serializer, it,
- std::addressof (this + stringOffset)
+ return name_prime->serialize (c->serializer, it,
+ std::addressof (this + stringOffset)
#ifdef HB_EXPERIMENTAL_API
- , insert_name_records
- , name_table_overrides
+ , insert_name_records
+ , name_table_overrides
#endif
- ));
+ );
}
bool sanitize_records (hb_sanitize_context_t *c) const
diff --git a/thirdparty/harfbuzz/src/graph/classdef-graph.hh b/thirdparty/harfbuzz/src/graph/classdef-graph.hh
index c2e24a7067..4ae0c13acc 100644
--- a/thirdparty/harfbuzz/src/graph/classdef-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/classdef-graph.hh
@@ -94,7 +94,13 @@ struct ClassDef : public OT::ClassDef
}
hb_bytes_t class_def_copy = serializer.copy_bytes ();
- c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+ if (!class_def_copy.arrayZ) return false;
+ // Give ownership to the context, it will cleanup the buffer.
+ if (!c.add_buffer ((char *) class_def_copy.arrayZ))
+ {
+ hb_free ((char *) class_def_copy.arrayZ);
+ return false;
+ }
auto& obj = c.graph.vertices_[dest_obj].obj;
obj.head = (char *) class_def_copy.arrayZ;
diff --git a/thirdparty/harfbuzz/src/graph/coverage-graph.hh b/thirdparty/harfbuzz/src/graph/coverage-graph.hh
index 49d0936315..bd6e91a1f2 100644
--- a/thirdparty/harfbuzz/src/graph/coverage-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/coverage-graph.hh
@@ -118,7 +118,13 @@ struct Coverage : public OT::Layout::Common::Coverage
}
hb_bytes_t coverage_copy = serializer.copy_bytes ();
- c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+ if (!coverage_copy.arrayZ) return false;
+ // Give ownership to the context, it will cleanup the buffer.
+ if (!c.add_buffer ((char *) coverage_copy.arrayZ))
+ {
+ hb_free ((char *) coverage_copy.arrayZ);
+ return false;
+ }
auto& obj = c.graph.vertices_[dest_obj].obj;
obj.head = (char *) coverage_copy.arrayZ;
diff --git a/thirdparty/harfbuzz/src/graph/graph.hh b/thirdparty/harfbuzz/src/graph/graph.hh
index 294a999918..53d0bc94e1 100644
--- a/thirdparty/harfbuzz/src/graph/graph.hh
+++ b/thirdparty/harfbuzz/src/graph/graph.hh
@@ -359,7 +359,6 @@ struct graph_t
~graph_t ()
{
- vertices_.fini ();
for (char* b : buffers)
hb_free (b);
}
@@ -401,9 +400,10 @@ struct graph_t
return vertices_[i].obj;
}
- void add_buffer (char* buffer)
+ bool add_buffer (char* buffer)
{
buffers.push (buffer);
+ return !buffers.in_error ();
}
/*
@@ -732,8 +732,7 @@ struct graph_t
remap_obj_indices (index_map, parents.iter (), true);
// Update roots set with new indices as needed.
- uint32_t next = HB_SET_VALUE_INVALID;
- while (roots.next (&next))
+ for (auto next : roots)
{
const uint32_t *v;
if (index_map.has (next, &v))
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc b/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc
index b2044426d4..d66eb49cfd 100644
--- a/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc
@@ -52,7 +52,11 @@ unsigned gsubgpos_graph_context_t::create_node (unsigned size)
if (!buffer)
return -1;
- add_buffer (buffer);
+ if (!add_buffer (buffer)) {
+ // Allocation did not get stored for freeing later.
+ hb_free (buffer);
+ return -1;
+ }
return graph.new_node (buffer, buffer + size);
}
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh
index 9fe9662e64..26b7cfe4d4 100644
--- a/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh
@@ -47,9 +47,9 @@ struct gsubgpos_graph_context_t
HB_INTERNAL unsigned create_node (unsigned size);
- void add_buffer (char* buffer)
+ bool add_buffer (char* buffer)
{
- graph.add_buffer (buffer);
+ return graph.add_buffer (buffer);
}
private:
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
index c170638409..78d5096325 100644
--- a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
@@ -166,7 +166,7 @@ struct Lookup : public OT::Lookup
}
if (all_new_subtables) {
- add_sub_tables (c, this_index, type, all_new_subtables);
+ return add_sub_tables (c, this_index, type, all_new_subtables);
}
return true;
@@ -184,7 +184,7 @@ struct Lookup : public OT::Lookup
return sub_table->split_subtables (c, parent_idx, objidx);
}
- void add_sub_tables (gsubgpos_graph_context_t& c,
+ bool add_sub_tables (gsubgpos_graph_context_t& c,
unsigned this_index,
unsigned type,
hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
@@ -200,7 +200,12 @@ struct Lookup : public OT::Lookup
size_t new_size = v.table_size ()
+ new_subtable_count * OT::Offset16::static_size;
char* buffer = (char*) hb_calloc (1, new_size);
- c.add_buffer (buffer);
+ if (!buffer) return false;
+ if (!c.add_buffer (buffer))
+ {
+ hb_free (buffer);
+ return false;
+ }
hb_memcpy (buffer, v.obj.head, v.table_size());
v.obj.head = buffer;
@@ -239,6 +244,7 @@ struct Lookup : public OT::Lookup
// The head location of the lookup has changed, invalidating the lookups map entry
// in the context. Update the map.
c.lookups.set (this_index, new_lookup);
+ return true;
}
void fix_existing_subtable_links (gsubgpos_graph_context_t& c,
diff --git a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
index 1c13eb24f9..f655b71558 100644
--- a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
@@ -215,7 +215,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
auto gid_and_class =
+ coverage->iter ()
| hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1->get_class (gid));
+ return hb_codepoint_pair_t (gid, class_def_1->get_class (gid));
})
;
class_def_size_estimator_t estimator (gid_and_class);
@@ -386,14 +386,14 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
auto klass_map =
+ coverage_table->iter ()
| hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid));
+ return hb_codepoint_pair_t (gid, class_def_1_table->get_class (gid));
})
| hb_filter ([&] (hb_codepoint_t klass) {
return klass >= start && klass < end;
}, hb_second)
- | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class) {
+ | hb_map_retains_sorting ([&] (hb_codepoint_pair_t gid_and_class) {
// Classes must be from 0...N so subtract start
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid_and_class.first, gid_and_class.second - start);
+ return hb_codepoint_pair_t (gid_and_class.first, gid_and_class.second - start);
})
;
@@ -519,7 +519,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
auto klass_map =
+ coverage.table->iter ()
| hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1.table->get_class (gid));
+ return hb_codepoint_pair_t (gid, class_def_1.table->get_class (gid));
})
| hb_filter ([&] (hb_codepoint_t klass) {
return klass < count;
diff --git a/thirdparty/harfbuzz/src/graph/serialize.hh b/thirdparty/harfbuzz/src/graph/serialize.hh
index 2e0b845baa..06e4bf44d8 100644
--- a/thirdparty/harfbuzz/src/graph/serialize.hh
+++ b/thirdparty/harfbuzz/src/graph/serialize.hh
@@ -226,6 +226,9 @@ inline hb_blob_t* serialize (const graph_t& graph)
{
hb_vector_t<char> buffer;
size_t size = graph.total_size_in_bytes ();
+
+ if (!size) return hb_blob_get_empty ();
+
if (!buffer.alloc (size)) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer.");
return nullptr;
diff --git a/thirdparty/harfbuzz/src/hb-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh
index da383e050a..374965d56e 100644
--- a/thirdparty/harfbuzz/src/hb-algs.hh
+++ b/thirdparty/harfbuzz/src/hb-algs.hh
@@ -87,6 +87,19 @@ static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
+#ifndef HB_FAST_INT_ACCESS
+#if defined(__OPTIMIZE__) && \
+ defined(__BYTE_ORDER) && \
+ (__BYTE_ORDER == __BIG_ENDIAN || \
+ (__BYTE_ORDER == __LITTLE_ENDIAN && \
+ hb_has_builtin(__builtin_bswap16) && \
+ hb_has_builtin(__builtin_bswap32)))
+#define HB_FAST_INT_ACCESS 1
+#else
+#define HB_FAST_INT_ACCESS 0
+#endif
+#endif
+
template <typename Type, int Bytes = sizeof (Type)>
struct BEInt;
template <typename Type>
@@ -101,21 +114,25 @@ struct BEInt<Type, 1>
template <typename Type>
struct BEInt<Type, 2>
{
+ struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
+
public:
BEInt () = default;
- constexpr BEInt (Type V) : v {uint8_t ((V >> 8) & 0xFF),
- uint8_t ((V ) & 0xFF)} {}
- struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
- constexpr operator Type () const
- {
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
- defined(__BYTE_ORDER) && \
- (__BYTE_ORDER == __BIG_ENDIAN || \
- (__BYTE_ORDER == __LITTLE_ENDIAN && \
- hb_has_builtin(__builtin_bswap16)))
- /* Spoon-feed the compiler a big-endian integer with alignment 1.
- * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+ BEInt (Type V)
+#if HB_FAST_INT_ACCESS
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ { ((packed_uint16_t *) v)->v = __builtin_bswap16 (V); }
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+ { ((packed_uint16_t *) v)->v = V; }
+#endif
+#else
+ : v {uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+#endif
+
+ constexpr operator Type () const {
+#if HB_FAST_INT_ACCESS
#if __BYTE_ORDER == __LITTLE_ENDIAN
return __builtin_bswap16 (((packed_uint16_t *) v)->v);
#else /* __BYTE_ORDER == __BIG_ENDIAN */
@@ -146,22 +163,27 @@ struct BEInt<Type, 3>
template <typename Type>
struct BEInt<Type, 4>
{
+ struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+
public:
BEInt () = default;
- constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF),
- uint8_t ((V >> 16) & 0xFF),
- uint8_t ((V >> 8) & 0xFF),
- uint8_t ((V ) & 0xFF)} {}
- struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+ BEInt (Type V)
+#if HB_FAST_INT_ACCESS
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ { ((packed_uint32_t *) v)->v = __builtin_bswap32 (V); }
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+ { ((packed_uint32_t *) v)->v = V; }
+#endif
+#else
+ : v {uint8_t ((V >> 24) & 0xFF),
+ uint8_t ((V >> 16) & 0xFF),
+ uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+#endif
+
constexpr operator Type () const {
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
- defined(__BYTE_ORDER) && \
- (__BYTE_ORDER == __BIG_ENDIAN || \
- (__BYTE_ORDER == __LITTLE_ENDIAN && \
- hb_has_builtin(__builtin_bswap32)))
- /* Spoon-feed the compiler a big-endian integer with alignment 1.
- * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+#if HB_FAST_INT_ACCESS
#if __BYTE_ORDER == __LITTLE_ENDIAN
return __builtin_bswap32 (((packed_uint32_t *) v)->v);
#else /* __BYTE_ORDER == __BIG_ENDIAN */
@@ -231,12 +253,119 @@ struct
}
HB_FUNCOBJ (hb_bool);
+
+/* The MIT License
+
+ Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
+
+ 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.
+*/
+
+
+// Compression function for Merkle-Damgard construction.
+// This function is generated using the framework provided.
+#define mix(h) ( \
+ (h) ^= (h) >> 23, \
+ (h) *= 0x2127599bf4325c37ULL, \
+ (h) ^= (h) >> 47)
+
+static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
+{
+ struct __attribute__((packed)) packed_uint64_t { uint64_t v; };
+ const uint64_t m = 0x880355f21e6d1965ULL;
+ const packed_uint64_t *pos = (const packed_uint64_t *)buf;
+ const packed_uint64_t *end = pos + (len / 8);
+ const unsigned char *pos2;
+ uint64_t h = seed ^ (len * m);
+ uint64_t v;
+
+#ifndef HB_OPTIMIZE_SIZE
+ if (((uintptr_t) pos & 7) == 0)
+ {
+ while (pos != end)
+ {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+ v = * (const uint64_t *) (pos++);
+#pragma GCC diagnostic pop
+ h ^= mix(v);
+ h *= m;
+ }
+ }
+ else
+#endif
+ {
+ while (pos != end)
+ {
+ v = pos++->v;
+ h ^= mix(v);
+ h *= m;
+ }
+ }
+
+ pos2 = (const unsigned char*)pos;
+ v = 0;
+
+ switch (len & 7) {
+ case 7: v ^= (uint64_t)pos2[6] << 48; HB_FALLTHROUGH;
+ case 6: v ^= (uint64_t)pos2[5] << 40; HB_FALLTHROUGH;
+ case 5: v ^= (uint64_t)pos2[4] << 32; HB_FALLTHROUGH;
+ case 4: v ^= (uint64_t)pos2[3] << 24; HB_FALLTHROUGH;
+ case 3: v ^= (uint64_t)pos2[2] << 16; HB_FALLTHROUGH;
+ case 2: v ^= (uint64_t)pos2[1] << 8; HB_FALLTHROUGH;
+ case 1: v ^= (uint64_t)pos2[0];
+ h ^= mix(v);
+ h *= m;
+ }
+
+ return mix(h);
+}
+
+static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed)
+{
+ // the following trick converts the 64-bit hashcode to Fermat
+ // residue, which shall retain information from both the higher
+ // and lower parts of hashcode.
+ uint64_t h = fasthash64(buf, len, seed);
+ return h - (h >> 32);
+}
+
struct
{
private:
template <typename T> constexpr auto
- impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
+ impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
+
+ // Horrible: std:hash() of integers seems to be identity in gcc / clang?!
+ // https://github.com/harfbuzz/harfbuzz/pull/4228
+ //
+ // For performance characteristics see:
+ // https://github.com/harfbuzz/harfbuzz/pull/4228#issuecomment-1565079537
+ template <typename T,
+ hb_enable_if (std::is_integral<T>::value && sizeof (T) <= sizeof (uint32_t))> constexpr auto
+ impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, v * 2654435761u /* Knuh's multiplicative hash */)
+ template <typename T,
+ hb_enable_if (std::is_integral<T>::value && sizeof (T) > sizeof (uint32_t))> constexpr auto
+ impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (v ^ (v >> 32)) * 2654435761u /* Knuth's multiplicative hash */)
template <typename T> constexpr auto
impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v)))
@@ -551,6 +680,8 @@ struct hb_pair_t
template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
+typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
+
struct
{
template <typename Pair> constexpr typename Pair::first_t
@@ -853,7 +984,7 @@ static inline void *
hb_memset (void *s, int c, unsigned int n)
{
/* It's illegal to pass NULL to memset(), even if n is zero. */
- if (unlikely (!n)) return 0;
+ if (unlikely (!n)) return s;
return memset (s, c, n);
}
diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh
index 1a22e15c0f..760f90259c 100644
--- a/thirdparty/harfbuzz/src/hb-array.hh
+++ b/thirdparty/harfbuzz/src/hb-array.hh
@@ -75,11 +75,25 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
*/
typedef Type& __item_t__;
static constexpr bool is_random_access_iterator = true;
+ static constexpr bool has_fast_len = true;
+ Type& __item__ () const
+ {
+ if (unlikely (!length)) return CrapOrNull (Type);
+ return *arrayZ;
+ }
Type& __item_at__ (unsigned i) const
{
if (unlikely (i >= length)) return CrapOrNull (Type);
return arrayZ[i];
}
+ void __next__ ()
+ {
+ if (unlikely (!length))
+ return;
+ length--;
+ backwards_length++;
+ arrayZ++;
+ }
void __forward__ (unsigned n)
{
if (unlikely (n > length))
@@ -88,6 +102,14 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
backwards_length += n;
arrayZ += n;
}
+ void __prev__ ()
+ {
+ if (unlikely (!backwards_length))
+ return;
+ length++;
+ backwards_length--;
+ arrayZ--;
+ }
void __rewind__ (unsigned n)
{
if (unlikely (n > backwards_length))
@@ -123,6 +145,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
uint32_t hash () const
{
// FNV-1a hash function
+ // https://github.com/harfbuzz/harfbuzz/pull/4228
uint32_t current = /*cbf29ce4*/0x84222325;
for (auto &v : *this)
{
@@ -326,6 +349,7 @@ struct hb_sorted_array_t :
HB_ITER_USING (iter_base_t);
static constexpr bool is_random_access_iterator = true;
static constexpr bool is_sorted_iterator = true;
+ static constexpr bool has_fast_len = true;
hb_sorted_array_t () = default;
hb_sorted_array_t (const hb_sorted_array_t&) = default;
@@ -453,55 +477,21 @@ inline bool hb_array_t<const unsigned char>::operator == (const hb_array_t<const
/* Specialize hash() for byte arrays. */
+#ifndef HB_OPTIMIZE_SIZE_MORE
template <>
inline uint32_t hb_array_t<const char>::hash () const
{
- // FNV-1a hash function
- uint32_t current = /*cbf29ce4*/0x84222325;
- unsigned i = 0;
-
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
- ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
- struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
- for (; i + 4 <= this->length; i += 4)
- {
- current = current ^ hb_hash ((uint32_t) ((const packed_uint32_t *) &this->arrayZ[i])->v);
- current = current * 16777619;
- }
-#endif
-
- for (; i < this->length; i++)
- {
- current = current ^ hb_hash (this->arrayZ[i]);
- current = current * 16777619;
- }
- return current;
+ // https://github.com/harfbuzz/harfbuzz/pull/4228
+ return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */);
}
template <>
inline uint32_t hb_array_t<const unsigned char>::hash () const
{
- // FNV-1a hash function
- uint32_t current = /*cbf29ce4*/0x84222325;
- unsigned i = 0;
-
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
- ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
- struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
- for (; i + 4 <= this->length; i += 4)
- {
- current = current ^ hb_hash ((uint32_t) ((const packed_uint32_t *) &this->arrayZ[i])->v);
- current = current * 16777619;
- }
-#endif
-
- for (; i < this->length; i++)
- {
- current = current ^ hb_hash (this->arrayZ[i]);
- current = current * 16777619;
- }
- return current;
+ // https://github.com/harfbuzz/harfbuzz/pull/4228
+ return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */);
}
+#endif
typedef hb_array_t<const char> hb_bytes_t;
diff --git a/thirdparty/harfbuzz/src/hb-atomic.hh b/thirdparty/harfbuzz/src/hb-atomic.hh
index a6283de140..303dfe6d04 100644
--- a/thirdparty/harfbuzz/src/hb-atomic.hh
+++ b/thirdparty/harfbuzz/src/hb-atomic.hh
@@ -204,6 +204,7 @@ struct hb_atomic_ptr_t
hb_atomic_ptr_t () = default;
constexpr hb_atomic_ptr_t (T* v) : v (v) {}
+ hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
diff --git a/thirdparty/harfbuzz/src/hb-bimap.hh b/thirdparty/harfbuzz/src/hb-bimap.hh
index 9edefd9710..4006fc4ebd 100644
--- a/thirdparty/harfbuzz/src/hb-bimap.hh
+++ b/thirdparty/harfbuzz/src/hb-bimap.hh
@@ -39,10 +39,10 @@ struct hb_bimap_t
back_map.reset ();
}
- void resize (unsigned pop)
+ void alloc (unsigned pop)
{
- forw_map.resize (pop);
- back_map.resize (pop);
+ forw_map.alloc (pop);
+ back_map.alloc (pop);
}
bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
@@ -83,7 +83,6 @@ struct hb_bimap_t
unsigned int get_population () const { return forw_map.get_population (); }
-
protected:
hb_map_t forw_map;
hb_map_t back_map;
@@ -95,8 +94,30 @@ struct hb_bimap_t
};
/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
-struct hb_inc_bimap_t : hb_bimap_t
+struct hb_inc_bimap_t
{
+ bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
+
+ unsigned int get_population () const { return forw_map.get_population (); }
+
+ void reset ()
+ {
+ forw_map.reset ();
+ back_map.reset ();
+ }
+
+ void alloc (unsigned pop)
+ {
+ forw_map.alloc (pop);
+ back_map.alloc (pop);
+ }
+
+ void clear ()
+ {
+ forw_map.clear ();
+ back_map.resize (0);
+ }
+
/* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
* Return the rhs value as the result.
*/
@@ -105,32 +126,41 @@ struct hb_inc_bimap_t : hb_bimap_t
hb_codepoint_t rhs = forw_map[lhs];
if (rhs == HB_MAP_VALUE_INVALID)
{
- rhs = next_value++;
- set (lhs, rhs);
+ rhs = back_map.length;
+ forw_map.set (lhs, rhs);
+ back_map.push (lhs);
}
return rhs;
}
hb_codepoint_t skip ()
- { return next_value++; }
+ {
+ hb_codepoint_t start = back_map.length;
+ back_map.push (HB_MAP_VALUE_INVALID);
+ return start;
+ }
hb_codepoint_t skip (unsigned count)
- { return next_value += count; }
+ {
+ hb_codepoint_t start = back_map.length;
+ for (unsigned i = 0; i < count; i++)
+ back_map.push (HB_MAP_VALUE_INVALID);
+ return start;
+ }
hb_codepoint_t get_next_value () const
- { return next_value; }
+ { return back_map.length; }
void add_set (const hb_set_t *set)
{
- hb_codepoint_t i = HB_SET_VALUE_INVALID;
- while (hb_set_next (set, &i)) add (i);
+ for (auto i : *set) add (i);
}
/* Create an identity map. */
bool identity (unsigned int size)
{
clear ();
- for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
+ for (hb_codepoint_t i = 0; i < size; i++) add (i);
return !in_error ();
}
@@ -145,20 +175,30 @@ struct hb_inc_bimap_t : hb_bimap_t
{
hb_codepoint_t count = get_population ();
hb_vector_t <hb_codepoint_t> work;
- work.resize (count);
+ if (unlikely (!work.resize (count, false))) return;
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
- work[rhs] = back_map[rhs];
+ work.arrayZ[rhs] = back_map[rhs];
work.qsort (cmp_id);
clear ();
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
- set (work[rhs], rhs);
+ add (work.arrayZ[rhs]);
}
+ hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
+ hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map[rhs]; }
+
+ hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
+ bool has (hb_codepoint_t lhs) const { return forw_map.has (lhs); }
+
protected:
- unsigned int next_value = 0;
+ hb_map_t forw_map;
+ hb_vector_t<hb_codepoint_t> back_map;
+
+ public:
+ auto keys () const HB_AUTO_RETURN (+ back_map.iter())
};
#endif /* HB_BIMAP_HH */
diff --git a/thirdparty/harfbuzz/src/hb-bit-page.hh b/thirdparty/harfbuzz/src/hb-bit-page.hh
index 9b027ac590..e578d2643f 100644
--- a/thirdparty/harfbuzz/src/hb-bit-page.hh
+++ b/thirdparty/harfbuzz/src/hb-bit-page.hh
@@ -104,10 +104,7 @@ struct hb_bit_page_t
}
uint32_t hash () const
{
- return
- + hb_iter (v)
- | hb_reduce ([] (uint32_t h, const elt_t &_) { return h * 31 + hb_hash (_); }, (uint32_t) 0u)
- ;
+ return hb_bytes_t ((const char *) &v, sizeof (v)).hash ();
}
void add (hb_codepoint_t g) { elt (g) |= mask (g); }
diff --git a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
index 1eb1b1c209..e765a479ae 100644
--- a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
+++ b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
@@ -136,7 +136,7 @@ struct hb_bit_set_invertible_t
/* Sink interface. */
hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
{ add (v); return *this; }
- hb_bit_set_invertible_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+ hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -162,7 +162,7 @@ struct hb_bit_set_invertible_t
auto it1 = iter ();
auto it2 = other.iter ();
return hb_all (+ hb_zip (it1, it2)
- | hb_map ([](hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return _.first == _.second; }));
+ | hb_map ([](hb_codepoint_pair_t _) { return _.first == _.second; }));
}
}
@@ -345,6 +345,7 @@ struct hb_bit_set_invertible_t
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
+ static constexpr bool has_fast_len = true;
iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
bool init = true) : s (&s_), v (INVALID), l(0)
{
@@ -363,7 +364,7 @@ struct hb_bit_set_invertible_t
unsigned __len__ () const { return l; }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
- { return s != o.s || v != o.v; }
+ { return v != o.v || s != o.s; }
protected:
const hb_bit_set_invertible_t *s;
diff --git a/thirdparty/harfbuzz/src/hb-bit-set.hh b/thirdparty/harfbuzz/src/hb-bit-set.hh
index d290f6114c..a84d751fb3 100644
--- a/thirdparty/harfbuzz/src/hb-bit-set.hh
+++ b/thirdparty/harfbuzz/src/hb-bit-set.hh
@@ -134,7 +134,11 @@ struct hb_bit_set_t
{
uint32_t h = 0;
for (auto &map : page_map)
- h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]);
+ {
+ auto &page = pages.arrayZ[map.index];
+ if (unlikely (page.is_empty ())) continue;
+ h = h * 31 + hb_hash (map.major) + hb_hash (page);
+ }
return h;
}
@@ -342,7 +346,7 @@ struct hb_bit_set_t
/* Sink interface. */
hb_bit_set_t& operator << (hb_codepoint_t v)
{ add (v); return *this; }
- hb_bit_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+ hb_bit_set_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -862,6 +866,7 @@ struct hb_bit_set_t
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
+ static constexpr bool has_fast_len = true;
iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
bool init = true) : s (&s_), v (INVALID), l(0)
{
diff --git a/thirdparty/harfbuzz/src/hb-buffer-verify.cc b/thirdparty/harfbuzz/src/hb-buffer-verify.cc
index f111b2d8dc..15a53919de 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-verify.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer-verify.cc
@@ -162,14 +162,8 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
hb_buffer_set_flags (fragment, flags);
hb_buffer_append (fragment, text_buffer, text_start, text_end);
- if (!hb_shape_full (font, fragment, features, num_features, shapers))
- {
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
- hb_buffer_destroy (reconstruction);
- hb_buffer_destroy (fragment);
- return false;
- }
- else if (!fragment->successful || fragment->shaping_failed)
+ if (!hb_shape_full (font, fragment, features, num_features, shapers) ||
+ fragment->successful || fragment->shaping_failed)
{
hb_buffer_destroy (reconstruction);
hb_buffer_destroy (fragment);
@@ -185,15 +179,18 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
}
bool ret = true;
- hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
- if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ if (likely (reconstruction->successful))
{
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
- ret = false;
+ hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+ if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ {
+ buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
+ ret = false;
- /* Return the reconstructed result instead so it can be inspected. */
- hb_buffer_set_length (buffer, 0);
- hb_buffer_append (buffer, reconstruction, 0, -1);
+ /* Return the reconstructed result instead so it can be inspected. */
+ hb_buffer_set_length (buffer, 0);
+ hb_buffer_append (buffer, reconstruction, 0, -1);
+ }
}
hb_buffer_destroy (reconstruction);
@@ -316,28 +313,13 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
/*
* Shape the two fragment streams.
*/
- if (!hb_shape_full (font, fragments[0], features, num_features, shapers))
- {
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
- ret = false;
- goto out;
- }
- else if (!fragments[0]->successful || fragments[0]->shaping_failed)
- {
- ret = true;
- goto out;
- }
- if (!hb_shape_full (font, fragments[1], features, num_features, shapers))
- {
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
- ret = false;
+ if (!hb_shape_full (font, fragments[0], features, num_features, shapers) ||
+ !fragments[0]->successful || fragments[0]->shaping_failed)
goto out;
- }
- else if (!fragments[1]->successful || fragments[1]->shaping_failed)
- {
- ret = true;
+
+ if (!hb_shape_full (font, fragments[1], features, num_features, shapers) ||
+ !fragments[1]->successful || fragments[1]->shaping_failed)
goto out;
- }
if (!forward)
{
@@ -377,21 +359,23 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
hb_buffer_reverse (reconstruction);
}
- /*
- * Diff results.
- */
- diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
- if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ if (likely (reconstruction->successful))
{
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
- ret = false;
+ /*
+ * Diff results.
+ */
+ diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+ if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ {
+ buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
+ ret = false;
- /* Return the reconstructed result instead so it can be inspected. */
- hb_buffer_set_length (buffer, 0);
- hb_buffer_append (buffer, reconstruction, 0, -1);
+ /* Return the reconstructed result instead so it can be inspected. */
+ hb_buffer_set_length (buffer, 0);
+ hb_buffer_append (buffer, reconstruction, 0, -1);
+ }
}
-
out:
hb_buffer_destroy (reconstruction);
hb_buffer_destroy (fragments[0]);
diff --git a/thirdparty/harfbuzz/src/hb-buffer.hh b/thirdparty/harfbuzz/src/hb-buffer.hh
index 7a97fc7168..4d48b7f167 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer.hh
@@ -493,6 +493,13 @@ struct hb_buffer_t
HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
+ HB_NODISCARD bool resize (unsigned length)
+ {
+ assert (!have_output);
+ if (unlikely (!ensure (length))) return false;
+ len = length;
+ return true;
+ }
HB_NODISCARD bool ensure (unsigned int size)
{ return likely (!size || size < allocated) ? true : enlarge (size); }
diff --git a/thirdparty/harfbuzz/src/hb-cache.hh b/thirdparty/harfbuzz/src/hb-cache.hh
index 8371465c6c..6d8a54cf10 100644
--- a/thirdparty/harfbuzz/src/hb-cache.hh
+++ b/thirdparty/harfbuzz/src/hb-cache.hh
@@ -62,14 +62,12 @@ struct hb_cache_t
static_assert ((key_bits >= cache_bits), "");
static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
- hb_cache_t () { init (); }
-
- void init () { clear (); }
+ hb_cache_t () { clear (); }
void clear ()
{
- for (unsigned i = 0; i < ARRAY_LENGTH (values); i++)
- values[i] = -1;
+ for (auto &v : values)
+ v = -1;
}
bool get (unsigned int key, unsigned int *value) const
diff --git a/thirdparty/harfbuzz/src/hb-cairo-utils.cc b/thirdparty/harfbuzz/src/hb-cairo-utils.cc
index 0f94d8169f..ec1499e861 100644
--- a/thirdparty/harfbuzz/src/hb-cairo-utils.cc
+++ b/thirdparty/harfbuzz/src/hb-cairo-utils.cc
@@ -80,7 +80,7 @@ hb_cairo_read_blob (void *closure,
if (r->offset + length > size)
return CAIRO_STATUS_READ_ERROR;
- memcpy (data, d + r->offset, length);
+ hb_memcpy (data, d + r->offset, length);
r->offset += length;
return CAIRO_STATUS_SUCCESS;
@@ -763,7 +763,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
}
//assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span);
- span = fabs (span);
+ span = fabsf (span);
for (signed l = k; l < 1000; l++)
{
diff --git a/thirdparty/harfbuzz/src/hb-cairo.cc b/thirdparty/harfbuzz/src/hb-cairo.cc
index f005afd17e..68c7bc064f 100644
--- a/thirdparty/harfbuzz/src/hb-cairo.cc
+++ b/thirdparty/harfbuzz/src/hb-cairo.cc
@@ -956,7 +956,7 @@ hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
if (clusters && *num_clusters && utf8)
{
- memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0]));
+ hb_memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0]));
hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
*cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
unsigned int cluster = 0;
diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh
index 949bfebf9b..1d1f10f2bf 100644
--- a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh
+++ b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh
@@ -26,6 +26,8 @@
#ifndef HB_CFF_INTERP_COMMON_HH
#define HB_CFF_INTERP_COMMON_HH
+extern HB_INTERNAL const unsigned char *endchar_str;
+
namespace CFF {
using namespace OT;
@@ -336,8 +338,6 @@ struct byte_str_ref_t
hb_ubytes_t str;
};
-using byte_str_array_t = hb_vector_t<hb_ubytes_t>;
-
/* stack */
template <typename ELEM, int LIMIT>
struct cff_stack_t
diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh
index f40be51f0d..28a777eb0d 100644
--- a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh
+++ b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh
@@ -883,14 +883,12 @@ struct cs_interpreter_t : interpreter_t<ENV>
unsigned max_ops = HB_CFF_MAX_OPS;
for (;;) {
- if (unlikely (!--max_ops))
+ OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
+ if (unlikely (SUPER::env.in_error () || !--max_ops))
{
SUPER::env.set_error ();
- break;
- }
- OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
- if (unlikely (SUPER::env.in_error ()))
return false;
+ }
if (SUPER::env.is_endchar ())
break;
}
diff --git a/thirdparty/harfbuzz/src/hb-common.h b/thirdparty/harfbuzz/src/hb-common.h
index a5da4e76a3..a9fe666b39 100644
--- a/thirdparty/harfbuzz/src/hb-common.h
+++ b/thirdparty/harfbuzz/src/hb-common.h
@@ -104,6 +104,16 @@ typedef int hb_bool_t;
*
**/
typedef uint32_t hb_codepoint_t;
+
+/**
+ * HB_CODEPOINT_INVALID:
+ *
+ * Unused #hb_codepoint_t value.
+ *
+ * Since: 8.0.0
+ */
+#define HB_CODEPOINT_INVALID ((hb_codepoint_t) -1)
+
/**
* hb_position_t:
*
diff --git a/thirdparty/harfbuzz/src/hb-config.hh b/thirdparty/harfbuzz/src/hb-config.hh
index 26f7cba83e..335c6976f6 100644
--- a/thirdparty/harfbuzz/src/hb-config.hh
+++ b/thirdparty/harfbuzz/src/hb-config.hh
@@ -113,7 +113,6 @@
/* Closure of options. */
#ifdef HB_NO_BORING_EXPANSION
-#define HB_NO_AVAR2
#define HB_NO_BEYOND_64K
#define HB_NO_CUBIC_GLYF
#define HB_NO_VAR_COMPOSITES
diff --git a/thirdparty/harfbuzz/src/hb-debug.hh b/thirdparty/harfbuzz/src/hb-debug.hh
index 0ac4515fa8..6055fce962 100644
--- a/thirdparty/harfbuzz/src/hb-debug.hh
+++ b/thirdparty/harfbuzz/src/hb-debug.hh
@@ -389,6 +389,10 @@ struct hb_no_trace_t {
#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
#endif
+#ifndef HB_DEBUG_WASM
+#define HB_DEBUG_WASM (HB_DEBUG+0)
+#endif
+
/*
* With tracing.
*/
diff --git a/thirdparty/harfbuzz/src/hb-deprecated.h b/thirdparty/harfbuzz/src/hb-deprecated.h
index b032a941b2..9fcce6d9ac 100644
--- a/thirdparty/harfbuzz/src/hb-deprecated.h
+++ b/thirdparty/harfbuzz/src/hb-deprecated.h
@@ -255,6 +255,52 @@ HB_EXTERN hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
+
+/**
+ * hb_font_get_glyph_shape_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @draw_funcs: The draw functions to send the shape data to
+ * @draw_data: The data accompanying the draw functions
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 4.0.0
+ * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead
+ **/
+typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs, void *draw_data,
+ void *user_data);
+
+/**
+ * hb_font_funcs_set_glyph_shape_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_get_glyph_shape_func_t,
+ * which is the same as #hb_font_draw_glyph_func_t.
+ *
+ * Since: 4.0.0
+ * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead
+ **/
+HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_func)
+HB_EXTERN void
+hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_shape_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+HB_DEPRECATED_FOR (hb_font_draw_glyph)
+HB_EXTERN void
+hb_font_get_glyph_shape (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *dfuncs, void *draw_data);
+
+
#endif
diff --git a/thirdparty/harfbuzz/src/hb-draw.hh b/thirdparty/harfbuzz/src/hb-draw.hh
index 768f51a875..25dee1261e 100644
--- a/thirdparty/harfbuzz/src/hb-draw.hh
+++ b/thirdparty/harfbuzz/src/hb-draw.hh
@@ -93,50 +93,57 @@ struct hb_draw_funcs_t
!user_data ? nullptr : user_data->close_path); }
- void move_to (void *draw_data, hb_draw_state_t &st,
- float to_x, float to_y)
+ void
+ HB_ALWAYS_INLINE
+ move_to (void *draw_data, hb_draw_state_t &st,
+ float to_x, float to_y)
{
- if (st.path_open) close_path (draw_data, st);
+ if (unlikely (st.path_open)) close_path (draw_data, st);
st.current_x = to_x;
st.current_y = to_y;
}
- void line_to (void *draw_data, hb_draw_state_t &st,
- float to_x, float to_y)
+ void
+ HB_ALWAYS_INLINE
+ line_to (void *draw_data, hb_draw_state_t &st,
+ float to_x, float to_y)
{
- if (!st.path_open) start_path (draw_data, st);
+ if (unlikely (!st.path_open)) start_path (draw_data, st);
emit_line_to (draw_data, st, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
void
+ HB_ALWAYS_INLINE
quadratic_to (void *draw_data, hb_draw_state_t &st,
float control_x, float control_y,
float to_x, float to_y)
{
- if (!st.path_open) start_path (draw_data, st);
+ if (unlikely (!st.path_open)) start_path (draw_data, st);
emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
void
+ HB_ALWAYS_INLINE
cubic_to (void *draw_data, hb_draw_state_t &st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y)
{
- if (!st.path_open) start_path (draw_data, st);
+ if (unlikely (!st.path_open)) start_path (draw_data, st);
emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
void
+ HB_ALWAYS_INLINE
close_path (void *draw_data, hb_draw_state_t &st)
{
- if (st.path_open)
+ if (likely (st.path_open))
{
if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y))
emit_line_to (draw_data, st, st.path_start_x, st.path_start_y);
@@ -168,6 +175,7 @@ struct hb_draw_session_t
~hb_draw_session_t () { close_path (); }
+ HB_ALWAYS_INLINE
void move_to (float to_x, float to_y)
{
if (likely (not_slanted))
@@ -177,6 +185,7 @@ struct hb_draw_session_t
funcs->move_to (draw_data, st,
to_x + to_y * slant, to_y);
}
+ HB_ALWAYS_INLINE
void line_to (float to_x, float to_y)
{
if (likely (not_slanted))
@@ -187,6 +196,7 @@ struct hb_draw_session_t
to_x + to_y * slant, to_y);
}
void
+ HB_ALWAYS_INLINE
quadratic_to (float control_x, float control_y,
float to_x, float to_y)
{
@@ -200,6 +210,7 @@ struct hb_draw_session_t
to_x + to_y * slant, to_y);
}
void
+ HB_ALWAYS_INLINE
cubic_to (float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y)
@@ -215,6 +226,7 @@ struct hb_draw_session_t
control2_x + control2_y * slant, control2_y,
to_x + to_y * slant, to_y);
}
+ HB_ALWAYS_INLINE
void close_path ()
{
funcs->close_path (draw_data, st);
diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc
index 688513112a..f062bfaf75 100644
--- a/thirdparty/harfbuzz/src/hb-font.cc
+++ b/thirdparty/harfbuzz/src/hb-font.cc
@@ -1389,6 +1389,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
return font->get_glyph_from_name (name, len, glyph);
}
+#ifndef HB_DISABLE_DEPRECATED
/**
* hb_font_get_glyph_shape:
* @font: #hb_font_t to work upon
@@ -1410,6 +1411,7 @@ hb_font_get_glyph_shape (hb_font_t *font,
{
hb_font_draw_glyph (font, glyph, dfuncs, draw_data);
}
+#endif
/**
* hb_font_draw_glyph:
@@ -2648,7 +2650,6 @@ hb_font_set_variations (hb_font_t *font,
if (axes[axis_index].axisTag == tag)
design_coords[axis_index] = v;
}
- font->face->table.avar->map_coords (normalized, coords_length);
hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
_hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
@@ -2720,8 +2721,6 @@ hb_font_set_variation (hb_font_t *font,
if (axes[axis_index].axisTag == tag)
design_coords[axis_index] = value;
- font->face->table.avar->map_coords (normalized, coords_length);
-
hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
_hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
@@ -3058,6 +3057,7 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
#endif
+#ifndef HB_DISABLE_DEPRECATED
void
hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_shape_func_t func,
@@ -3066,3 +3066,4 @@ hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
{
hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy);
}
+#endif
diff --git a/thirdparty/harfbuzz/src/hb-font.h b/thirdparty/harfbuzz/src/hb-font.h
index f3b589bd0d..3c2355af2d 100644
--- a/thirdparty/harfbuzz/src/hb-font.h
+++ b/thirdparty/harfbuzz/src/hb-font.h
@@ -486,25 +486,6 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
void *user_data);
/**
- * hb_font_get_glyph_shape_func_t:
- * @font: #hb_font_t to work upon
- * @font_data: @font user data pointer
- * @glyph: The glyph ID to query
- * @draw_funcs: The draw functions to send the shape data to
- * @draw_data: The data accompanying the draw functions
- * @user_data: User data pointer passed by the caller
- *
- * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
- *
- * Since: 4.0.0
- * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead
- **/
-typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
- hb_codepoint_t glyph,
- hb_draw_funcs_t *draw_funcs, void *draw_data,
- void *user_data);
-
-/**
* hb_font_draw_glyph_func_t:
* @font: #hb_font_t to work upon
* @font_data: @font user data pointer
@@ -804,32 +785,13 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
void *user_data, hb_destroy_func_t destroy);
/**
- * hb_font_funcs_set_glyph_shape_func:
- * @ffuncs: A font-function structure
- * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
- * @user_data: Data to pass to @func
- * @destroy: (nullable): The function to call when @user_data is not needed anymore
- *
- * Sets the implementation function for #hb_font_get_glyph_shape_func_t,
- * which is the same as #hb_font_draw_glyph_func_t.
- *
- * Since: 4.0.0
- * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead
- **/
-HB_EXTERN void
-hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
- hb_font_get_glyph_shape_func_t func,
- void *user_data, hb_destroy_func_t destroy);
-
-/**
* hb_font_funcs_set_draw_glyph_func:
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
* @destroy: (nullable): The function to call when @user_data is not needed anymore
*
- * Sets the implementation function for #hb_font_draw_glyph_func_t,
- * which is the same as #hb_font_get_glyph_shape_func_t.
+ * Sets the implementation function for #hb_font_draw_glyph_func_t.
*
* Since: 7.0.0
**/
@@ -935,11 +897,6 @@ hb_font_get_glyph_from_name (hb_font_t *font,
hb_codepoint_t *glyph);
HB_EXTERN void
-hb_font_get_glyph_shape (hb_font_t *font,
- hb_codepoint_t glyph,
- hb_draw_funcs_t *dfuncs, void *draw_data);
-
-HB_EXTERN void
hb_font_draw_glyph (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_funcs_t *dfuncs, void *draw_data);
diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc
index 1105862fbc..6ca3f85465 100644
--- a/thirdparty/harfbuzz/src/hb-ft.cc
+++ b/thirdparty/harfbuzz/src/hb-ft.cc
@@ -114,7 +114,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
ft_font->cached_serial = (unsigned) -1;
- ft_font->advance_cache.init ();
+ new (&ft_font->advance_cache) hb_ft_advance_cache_t;
return ft_font;
}
diff --git a/thirdparty/harfbuzz/src/hb-gobject-structs.cc b/thirdparty/harfbuzz/src/hb-gobject-structs.cc
index 332cc84888..d66de0b237 100644
--- a/thirdparty/harfbuzz/src/hb-gobject-structs.cc
+++ b/thirdparty/harfbuzz/src/hb-gobject-structs.cc
@@ -29,7 +29,7 @@
#ifdef HAVE_GOBJECT
-/**
+/*
* SECTION:hb-gobject
* @title: hb-gobject
* @short_description: GObject integration support
diff --git a/thirdparty/harfbuzz/src/hb-graphite2.cc b/thirdparty/harfbuzz/src/hb-graphite2.cc
index 9e068f8d84..7ea0386223 100644
--- a/thirdparty/harfbuzz/src/hb-graphite2.cc
+++ b/thirdparty/harfbuzz/src/hb-graphite2.cc
@@ -248,6 +248,21 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
gr_fref_set_feature_value (fref, features[i].value, feats);
}
+ hb_direction_t direction = buffer->props.direction;
+ hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
+ /* TODO vertical:
+ * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
+ * Ogham fonts are supposed to be implemented BTT or not. Need to research that
+ * first. */
+ if ((HB_DIRECTION_IS_HORIZONTAL (direction) &&
+ direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) ||
+ (HB_DIRECTION_IS_VERTICAL (direction) &&
+ direction != HB_DIRECTION_TTB))
+ {
+ hb_buffer_reverse_clusters (buffer);
+ direction = HB_DIRECTION_REVERSE (direction);
+ }
+
gr_segment *seg = nullptr;
const gr_slot *is;
unsigned int ci = 0, ic = 0;
@@ -261,21 +276,11 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
for (unsigned int i = 0; i < buffer->len; ++i)
chars[i] = buffer->info[i].codepoint;
- /* TODO ensure_native_direction. */
-
- hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT];
- unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT;
- hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer),
- HB_LANGUAGE_INVALID,
- &count,
- script_tag,
- nullptr, nullptr);
-
seg = gr_make_seg (nullptr, grface,
- count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT,
+ HB_TAG_NONE, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148
feats,
gr_utf32, chars, buffer->len,
- 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
+ 2 | (direction == HB_DIRECTION_RTL ? 1 : 0));
if (unlikely (!seg)) {
if (feats) gr_featureval_destroy (feats);
@@ -327,7 +332,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
float yscale = (float) font->y_scale / upem;
yscale *= yscale / xscale;
unsigned int curradv = 0;
- if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ if (HB_DIRECTION_IS_BACKWARD (direction))
{
curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
@@ -356,16 +361,17 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
c->num_chars = before - c->base_char;
c->base_glyph = ic;
c->num_glyphs = 0;
- if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ if (HB_DIRECTION_IS_BACKWARD (direction))
{
c->advance = curradv - gr_slot_origin_X(is) * xscale;
curradv -= c->advance;
}
else
{
+ auto origin_X = gr_slot_origin_X (is) * xscale;
c->advance = 0;
- clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv;
- curradv += clusters[ci].advance;
+ clusters[ci].advance += origin_X - curradv;
+ curradv = origin_X;
}
ci++;
}
@@ -375,7 +381,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
}
- if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ if (HB_DIRECTION_IS_BACKWARD (direction))
clusters[ci].advance += curradv;
else
clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
@@ -397,7 +403,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
unsigned int currclus = UINT_MAX;
const hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
- if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ if (!HB_DIRECTION_IS_BACKWARD (direction))
{
curradvx = 0;
for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
diff --git a/thirdparty/harfbuzz/src/hb-iter.hh b/thirdparty/harfbuzz/src/hb-iter.hh
index b123b2f27c..61e05180be 100644
--- a/thirdparty/harfbuzz/src/hb-iter.hh
+++ b/thirdparty/harfbuzz/src/hb-iter.hh
@@ -63,6 +63,7 @@ struct hb_iter_t
static constexpr bool is_iterator = true;
static constexpr bool is_random_access_iterator = false;
static constexpr bool is_sorted_iterator = false;
+ static constexpr bool has_fast_len = false; // Should be checked in combination with is_random_access_iterator.
private:
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -393,7 +394,7 @@ struct hb_map_iter_t :
private:
Iter it;
- hb_reference_wrapper<Proj> f;
+ mutable hb_reference_wrapper<Proj> f;
};
template <typename Proj, hb_function_sortedness_t Sorted>
@@ -456,8 +457,8 @@ struct hb_filter_iter_t :
private:
Iter it;
- hb_reference_wrapper<Pred> p;
- hb_reference_wrapper<Proj> f;
+ mutable hb_reference_wrapper<Pred> p;
+ mutable hb_reference_wrapper<Proj> f;
};
template <typename Pred, typename Proj>
struct hb_filter_iter_factory_t
@@ -841,7 +842,7 @@ struct
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN
- ( hb_zip (hb_range (count), it) | hb_map (hb_second) )
+ ( hb_zip (hb_range (count), it) | hb_map_retains_sorting (hb_second) )
/* Specialization arrays. */
diff --git a/thirdparty/harfbuzz/src/hb-kern.hh b/thirdparty/harfbuzz/src/hb-kern.hh
index 9ea945caed..9ac744c9dd 100644
--- a/thirdparty/harfbuzz/src/hb-kern.hh
+++ b/thirdparty/harfbuzz/src/hb-kern.hh
@@ -53,7 +53,7 @@ struct hb_kern_machine_t
return;
buffer->unsafe_to_concat ();
- OT::hb_ot_apply_context_t c (1, font, buffer);
+ OT::hb_ot_apply_context_t c (1, font, buffer, hb_blob_get_empty ());
c.set_lookup_mask (kern_mask);
c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
auto &skippy_iter = c.iter_input;
diff --git a/thirdparty/harfbuzz/src/hb-limits.hh b/thirdparty/harfbuzz/src/hb-limits.hh
index 0f60e9e210..c503b30652 100644
--- a/thirdparty/harfbuzz/src/hb-limits.hh
+++ b/thirdparty/harfbuzz/src/hb-limits.hh
@@ -89,6 +89,10 @@
#endif
+#ifndef HB_GLYF_VAR_COMPOSITE_MAX_AXES
+#define HB_GLYF_VAR_COMPOSITE_MAX_AXES 4096
+#endif
+
#ifndef HB_GLYF_MAX_POINTS
#define HB_GLYF_MAX_POINTS 20000
#endif
diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh
index 1084725af2..cde1e99d6f 100644
--- a/thirdparty/harfbuzz/src/hb-machinery.hh
+++ b/thirdparty/harfbuzz/src/hb-machinery.hh
@@ -131,6 +131,10 @@ static inline Type& StructAfter(TObject &X)
unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \
DEFINE_SIZE_ARRAY(size, array)
+#define DEFINE_SIZE_MAX(size) \
+ DEFINE_INSTANCE_ASSERTION (sizeof (*this) <= (size)) \
+ static constexpr unsigned max_size = (size)
+
/*
@@ -180,6 +184,9 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored>
>::value Funcs;
+ hb_lazy_loader_t () = default;
+ hb_lazy_loader_t (const hb_lazy_loader_t &other) = delete;
+
void init0 () {} /* Init, when memory is already set to 0. No-op for us. */
void init () { instance.set_relaxed (nullptr); }
void fini () { do_destroy (instance.get_acquire ()); init (); }
@@ -278,7 +285,11 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
template <typename T, unsigned int WheresFace>
struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
hb_face_lazy_loader_t<T, WheresFace>,
- hb_face_t, WheresFace> {};
+ hb_face_t, WheresFace>
+{
+ // Hack; have them here for API parity with hb_table_lazy_loader_t
+ hb_blob_t *get_blob () { return this->get ()->get_blob (); }
+};
template <typename T, unsigned int WheresFace, bool core=false>
struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
@@ -288,7 +299,7 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
{
static hb_blob_t *create (hb_face_t *face)
{
- auto c = hb_sanitize_context_t ();
+ hb_sanitize_context_t c;
if (core)
c.set_num_glyphs (0); // So we don't recurse ad infinitum, or doesn't need num_glyphs
return c.reference_table<T> (face);
diff --git a/thirdparty/harfbuzz/src/hb-map.h b/thirdparty/harfbuzz/src/hb-map.h
index e928628fa7..0ae171714e 100644
--- a/thirdparty/harfbuzz/src/hb-map.h
+++ b/thirdparty/harfbuzz/src/hb-map.h
@@ -44,7 +44,7 @@ HB_BEGIN_DECLS
*
* Since: 1.7.7
*/
-#define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1)
+#define HB_MAP_VALUE_INVALID HB_CODEPOINT_INVALID
/**
* hb_map_t:
diff --git a/thirdparty/harfbuzz/src/hb-map.hh b/thirdparty/harfbuzz/src/hb-map.hh
index c685a9a3e1..e8abeec636 100644
--- a/thirdparty/harfbuzz/src/hb-map.hh
+++ b/thirdparty/harfbuzz/src/hb-map.hh
@@ -45,9 +45,9 @@ struct hb_hashmap_t
hb_hashmap_t () { init (); }
~hb_hashmap_t () { fini (); }
- hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (o.population); hb_copy (o, *this); }
+ hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { alloc (o.population); hb_copy (o, *this); }
hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); }
- hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); resize (o.population); hb_copy (o, *this); return *this; }
+ hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; }
hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; }
hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t ()
@@ -60,29 +60,28 @@ struct hb_hashmap_t
hb_hashmap_t (const Iterable &o) : hb_hashmap_t ()
{
auto iter = hb_iter (o);
- if (iter.is_random_access_iterator)
- resize (hb_len (iter));
+ if (iter.is_random_access_iterator || iter.has_fast_len)
+ alloc (hb_len (iter));
hb_copy (iter, *this);
}
struct item_t
{
K key;
- uint32_t hash : 30;
+ uint32_t is_real_ : 1;
uint32_t is_used_ : 1;
- uint32_t is_tombstone_ : 1;
+ uint32_t hash : 30;
V value;
item_t () : key (),
+ is_real_ (false), is_used_ (false),
hash (0),
- is_used_ (false), is_tombstone_ (false),
value () {}
bool is_used () const { return is_used_; }
void set_used (bool is_used) { is_used_ = is_used; }
- bool is_tombstone () const { return is_tombstone_; }
- void set_tombstone (bool is_tombstone) { is_tombstone_ = is_tombstone; }
- bool is_real () const { return is_used_ && !is_tombstone_; }
+ void set_real (bool is_real) { is_real_ = is_real; }
+ bool is_real () const { return is_real_; }
template <bool v = minus_one,
hb_enable_if (v == false)>
@@ -98,10 +97,15 @@ struct hb_hashmap_t
bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); }
bool operator == (const item_t &o) const { return *this == o.key; }
hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
- hb_pair_t<const K &, const V &> get_pair_ref() const { return hb_pair_t<const K &, const V &> (key, value); }
+ hb_pair_t<const K &, V &> get_pair_ref() { return hb_pair_t<const K &, V &> (key, value); }
uint32_t total_hash () const
{ return (hash * 31) + hb_hash (value); }
+
+ static constexpr bool is_trivial = std::is_trivially_constructible<K>::value &&
+ std::is_trivially_destructible<K>::value &&
+ std::is_trivially_constructible<V>::value &&
+ std::is_trivially_destructible<V>::value;
};
hb_object_header_t header;
@@ -110,6 +114,7 @@ struct hb_hashmap_t
unsigned int occupancy; /* Including tombstones. */
unsigned int mask;
unsigned int prime;
+ unsigned int max_chain_length;
item_t *items;
friend void swap (hb_hashmap_t& a, hb_hashmap_t& b)
@@ -123,6 +128,7 @@ struct hb_hashmap_t
hb_swap (a.occupancy, b.occupancy);
hb_swap (a.mask, b.mask);
hb_swap (a.prime, b.prime);
+ hb_swap (a.max_chain_length, b.max_chain_length);
hb_swap (a.items, b.items);
}
void init ()
@@ -133,16 +139,19 @@ struct hb_hashmap_t
population = occupancy = 0;
mask = 0;
prime = 0;
+ max_chain_length = 0;
items = nullptr;
}
void fini ()
{
hb_object_fini (this);
- if (likely (items)) {
+ if (likely (items))
+ {
unsigned size = mask + 1;
- for (unsigned i = 0; i < size; i++)
- items[i].~item_t ();
+ if (!item_t::is_trivial)
+ for (unsigned i = 0; i < size; i++)
+ items[i].~item_t ();
hb_free (items);
items = nullptr;
}
@@ -157,7 +166,7 @@ struct hb_hashmap_t
bool in_error () const { return !successful; }
- bool resize (unsigned new_population = 0)
+ bool alloc (unsigned new_population = 0)
{
if (unlikely (!successful)) return false;
@@ -171,8 +180,11 @@ struct hb_hashmap_t
successful = false;
return false;
}
- for (auto &_ : hb_iter (new_items, new_size))
- new (&_) item_t ();
+ if (!item_t::is_trivial)
+ for (auto &_ : hb_iter (new_items, new_size))
+ new (&_) item_t ();
+ else
+ hb_memset (new_items, 0, (size_t) new_size * sizeof (item_t));
unsigned int old_size = size ();
item_t *old_items = items;
@@ -181,6 +193,7 @@ struct hb_hashmap_t
population = occupancy = 0;
mask = new_size - 1;
prime = prime_for (power);
+ max_chain_length = power * 2;
items = new_items;
/* Insert back old items. */
@@ -192,7 +205,8 @@ struct hb_hashmap_t
old_items[i].hash,
std::move (old_items[i].value));
}
- old_items[i].~item_t ();
+ if (!item_t::is_trivial)
+ old_items[i].~item_t ();
}
hb_free (old_items);
@@ -201,72 +215,124 @@ struct hb_hashmap_t
}
template <typename KK, typename VV>
- bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool is_delete=false)
+ bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool overwrite = true)
{
if (unlikely (!successful)) return false;
- if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
- item_t &item = item_for_hash (key, hash);
+ if (unlikely ((occupancy + occupancy / 2) >= mask && !alloc ())) return false;
+
+ hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
+ unsigned int tombstone = (unsigned int) -1;
+ unsigned int i = hash % prime;
+ unsigned length = 0;
+ unsigned step = 0;
+ while (items[i].is_used ())
+ {
+ if ((std::is_integral<K>::value || items[i].hash == hash) &&
+ items[i] == key)
+ {
+ if (!overwrite)
+ return false;
+ else
+ break;
+ }
+ if (!items[i].is_real () && tombstone == (unsigned) -1)
+ tombstone = i;
+ i = (i + ++step) & mask;
+ length++;
+ }
- if (is_delete && !(item == key))
- return true; /* Trying to delete non-existent key. */
+ item_t &item = items[tombstone == (unsigned) -1 ? i : tombstone];
if (item.is_used ())
{
occupancy--;
- if (!item.is_tombstone ())
- population--;
+ population -= item.is_real ();
}
item.key = std::forward<KK> (key);
item.value = std::forward<VV> (value);
item.hash = hash;
item.set_used (true);
- item.set_tombstone (is_delete);
+ item.set_real (true);
occupancy++;
- if (!is_delete)
- population++;
+ population++;
+
+ if (unlikely (length > max_chain_length) && occupancy * 8 > mask)
+ alloc (mask - 8); // This ensures we jump to next larger size
return true;
}
template <typename VV>
- bool set (const K &key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value)); }
+ bool set (const K &key, VV&& value, bool overwrite = true) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value), overwrite); }
template <typename VV>
- bool set (K &&key, VV&& value) { return set_with_hash (std::move (key), hb_hash (key), std::forward<VV> (value)); }
+ bool set (K &&key, VV&& value, bool overwrite = true)
+ {
+ uint32_t hash = hb_hash (key);
+ return set_with_hash (std::move (key), hash, std::forward<VV> (value), overwrite);
+ }
const V& get_with_hash (const K &key, uint32_t hash) const
{
- if (unlikely (!items)) return item_t::default_value ();
- auto &item = item_for_hash (key, hash);
- return item.is_real () && item == key ? item.value : item_t::default_value ();
+ if (!items) return item_t::default_value ();
+ auto *item = fetch_item (key, hb_hash (key));
+ if (item)
+ return item->value;
+ return item_t::default_value ();
}
const V& get (const K &key) const
{
- if (unlikely (!items)) return item_t::default_value ();
+ if (!items) return item_t::default_value ();
return get_with_hash (key, hb_hash (key));
}
- void del (const K &key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); }
+ void del (const K &key)
+ {
+ if (!items) return;
+ auto *item = fetch_item (key, hb_hash (key));
+ if (item)
+ {
+ item->set_real (false);
+ population--;
+ }
+ }
/* Has interface. */
const V& operator [] (K k) const { return get (k); }
template <typename VV=V>
- bool has (K key, VV **vp = nullptr) const
+ bool has (const K &key, VV **vp = nullptr) const
{
- if (unlikely (!items))
- return false;
- auto &item = item_for_hash (key, hb_hash (key));
- if (item.is_real () && item == key)
+ if (!items) return false;
+ auto *item = fetch_item (key, hb_hash (key));
+ if (item)
{
- if (vp) *vp = std::addressof (item.value);
+ if (vp) *vp = std::addressof (item->value);
return true;
}
- else
- return false;
+ return false;
+ }
+ item_t *fetch_item (const K &key, uint32_t hash) const
+ {
+ hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
+ unsigned int i = hash % prime;
+ unsigned step = 0;
+ while (items[i].is_used ())
+ {
+ if ((std::is_integral<K>::value || items[i].hash == hash) &&
+ items[i] == key)
+ {
+ if (items[i].is_real ())
+ return &items[i];
+ else
+ return nullptr;
+ }
+ i = (i + ++step) & mask;
+ }
+ return nullptr;
}
/* Projection. */
- V operator () (K k) const { return get (k); }
+ const V& operator () (K k) const { return get (k); }
unsigned size () const { return mask ? mask + 1 : 0; }
@@ -393,24 +459,6 @@ struct hb_hashmap_t
hb_hashmap_t& operator << (const hb_pair_t<K&&, V&&>& v)
{ set (std::move (v.first), std::move (v.second)); return *this; }
- item_t& item_for_hash (const K &key, uint32_t hash) const
- {
- hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
- unsigned int i = hash % prime;
- unsigned int step = 0;
- unsigned int tombstone = (unsigned) -1;
- while (items[i].is_used ())
- {
- if ((hb_is_same (K, hb_codepoint_t) || items[i].hash == hash) &&
- items[i] == key)
- return items[i];
- if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
- tombstone = i;
- i = (i + ++step) & mask;
- }
- return items[tombstone == (unsigned) -1 ? i : tombstone];
- }
-
static unsigned int prime_for (unsigned int shift)
{
/* Following comment and table copied from glib. */
@@ -481,7 +529,7 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {}
hb_map_t& operator= (const hb_map_t&) = default;
hb_map_t& operator= (hb_map_t&&) = default;
- hb_map_t (std::initializer_list<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> lst) : hashmap (lst) {}
+ hb_map_t (std::initializer_list<hb_codepoint_pair_t> lst) : hashmap (lst) {}
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
hb_map_t (const Iterable &o) : hashmap (o) {}
diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh
index 31aa7fa6f1..52ff4a8412 100644
--- a/thirdparty/harfbuzz/src/hb-meta.hh
+++ b/thirdparty/harfbuzz/src/hb-meta.hh
@@ -153,8 +153,8 @@ struct hb_reference_wrapper
hb_reference_wrapper (T v) : v (v) {}
bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
- operator T () const { return v; }
- T get () const { return v; }
+ operator T& () { return v; }
+ T& get () { return v; }
T v;
};
template <typename T>
@@ -163,8 +163,8 @@ struct hb_reference_wrapper<T&>
hb_reference_wrapper (T& v) : v (std::addressof (v)) {}
bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
- operator T& () const { return *v; }
- T& get () const { return *v; }
+ operator T& () { return *v; }
+ T& get () { return *v; }
T* v;
};
diff --git a/thirdparty/harfbuzz/src/hb-multimap.hh b/thirdparty/harfbuzz/src/hb-multimap.hh
index b4a8cc62a3..0184279c12 100644
--- a/thirdparty/harfbuzz/src/hb-multimap.hh
+++ b/thirdparty/harfbuzz/src/hb-multimap.hh
@@ -38,10 +38,10 @@ struct hb_multimap_t
{
void add (hb_codepoint_t k, hb_codepoint_t v)
{
- hb_codepoint_t *i;
- if (multiples_indices.has (k, &i))
+ hb_vector_t<hb_codepoint_t> *m;
+ if (multiples.has (k, &m))
{
- multiples_values[*i].push (v);
+ m->push (v);
return;
}
@@ -51,12 +51,7 @@ struct hb_multimap_t
hb_codepoint_t old = *old_v;
singulars.del (k);
- multiples_indices.set (k, multiples_values.length);
- auto *vec = multiples_values.push ();
-
- vec->push (old);
- vec->push (v);
-
+ multiples.set (k, hb_vector_t<hb_codepoint_t> {old, v});
return;
}
@@ -69,22 +64,31 @@ struct hb_multimap_t
if (singulars.has (k, &v))
return hb_array (v, 1);
- hb_codepoint_t *i;
- if (multiples_indices.has (k, &i))
- return multiples_values[*i].as_array ();
+ hb_vector_t<hb_codepoint_t> *m;
+ if (multiples.has (k, &m))
+ return m->as_array ();
return hb_array_t<const hb_codepoint_t> ();
}
bool in_error () const
{
- return singulars.in_error () || multiples_indices.in_error () || multiples_values.in_error ();
+ if (singulars.in_error () || multiples.in_error ())
+ return true;
+ for (const auto &m : multiples.values_ref ())
+ if (m.in_error ())
+ return true;
+ return false;
+ }
+
+ void alloc (unsigned size)
+ {
+ singulars.alloc (size);
}
protected:
hb_map_t singulars;
- hb_map_t multiples_indices;
- hb_vector_t<hb_vector_t<hb_codepoint_t>> multiples_values;
+ hb_hashmap_t<hb_codepoint_t, hb_vector_t<hb_codepoint_t>> multiples;
};
diff --git a/thirdparty/harfbuzz/src/hb-null.hh b/thirdparty/harfbuzz/src/hb-null.hh
index 3da2d75ef5..2982516283 100644
--- a/thirdparty/harfbuzz/src/hb-null.hh
+++ b/thirdparty/harfbuzz/src/hb-null.hh
@@ -49,6 +49,15 @@ using hb_has_min_size = _hb_has_min_size<T, void>;
#define hb_has_min_size(T) hb_has_min_size<T>::value
template <typename T, typename>
+struct _hb_has_max_size : hb_false_type {};
+template <typename T>
+struct _hb_has_max_size<T, hb_void_t<decltype (T::max_size)>>
+ : hb_true_type {};
+template <typename T>
+using hb_has_max_size = _hb_has_max_size<T, void>;
+#define hb_has_max_size(T) hb_has_max_size<T>::value
+
+template <typename T, typename>
struct _hb_has_null_size : hb_false_type {};
template <typename T>
struct _hb_has_null_size<T, hb_void_t<decltype (T::null_size)>>
@@ -176,7 +185,7 @@ template <typename Type>
static inline Type& Crap () {
static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
- memcpy (obj, &Null (Type), sizeof (*obj));
+ memcpy (obj, std::addressof (Null (Type)), sizeof (*obj));
return *obj;
}
template <typename QType>
@@ -211,11 +220,11 @@ struct hb_nonnull_ptr_t
T * operator = (T *v_) { return v = v_; }
T * operator -> () const { return get (); }
T & operator * () const { return *get (); }
- T ** operator & () const { return &v; }
+ T ** operator & () const { return std::addressof (v); }
/* Only auto-cast to const types. */
template <typename C> operator const C * () const { return get (); }
operator const char * () const { return (const char *) get (); }
- T * get () const { return v ? v : const_cast<T *> (&Null (T)); }
+ T * get () const { return v ? v : const_cast<T *> (std::addressof (Null (T))); }
T * get_raw () const { return v; }
private:
diff --git a/thirdparty/harfbuzz/src/hb-open-file.hh b/thirdparty/harfbuzz/src/hb-open-file.hh
index 13570a46e0..04f144a72c 100644
--- a/thirdparty/harfbuzz/src/hb-open-file.hh
+++ b/thirdparty/harfbuzz/src/hb-open-file.hh
@@ -131,7 +131,7 @@ typedef struct OpenTypeOffsetTable
sfnt_version = sfnt_tag;
/* Take space for numTables, searchRange, entrySelector, RangeShift
* and the TableRecords themselves. */
- unsigned num_items = it.len ();
+ unsigned num_items = hb_len (it);
if (unlikely (!tables.serialize (c, num_items))) return_trace (false);
const char *dir_end = (const char *) c->head;
@@ -145,7 +145,7 @@ typedef struct OpenTypeOffsetTable
unsigned len = blob->length;
/* Allocate room for the table and copy it. */
- char *start = (char *) c->allocate_size<void> (len);
+ char *start = (char *) c->allocate_size<void> (len, false);
if (unlikely (!start)) return false;
TableRecord &rec = tables.arrayZ[i];
diff --git a/thirdparty/harfbuzz/src/hb-open-type.hh b/thirdparty/harfbuzz/src/hb-open-type.hh
index 4c9bfebcec..6d464a3535 100644
--- a/thirdparty/harfbuzz/src/hb-open-type.hh
+++ b/thirdparty/harfbuzz/src/hb-open-type.hh
@@ -312,6 +312,8 @@ struct _hb_has_null<Type, true>
template <typename Type, typename OffsetType, bool has_null=true>
struct OffsetTo : Offset<OffsetType, has_null>
{
+ using target_t = Type;
+
// Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time.
static_assert (has_null == false ||
(hb_has_null_size (Type) || !hb_has_min_size (Type)), "");
@@ -416,12 +418,15 @@ struct OffsetTo : Offset<OffsetType, has_null>
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false);
- if (unlikely (this->is_null ())) return_trace (true);
+ //if (unlikely (this->is_null ())) return_trace (true);
if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
return_trace (true);
}
template <typename ...Ts>
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
{
TRACE_SANITIZE (this);
@@ -462,24 +467,16 @@ struct UnsizedArrayOf
HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
- const Type& operator [] (int i_) const
+ const Type& operator [] (unsigned int i) const
{
- unsigned int i = (unsigned int) i_;
- const Type *p = &arrayZ[i];
- if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */
- _hb_compiler_memory_r_barrier ();
- return *p;
+ return arrayZ[i];
}
- Type& operator [] (int i_)
+ Type& operator [] (unsigned int i)
{
- unsigned int i = (unsigned int) i_;
- Type *p = &arrayZ[i];
- if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */
- _hb_compiler_memory_r_barrier ();
- return *p;
+ return arrayZ[i];
}
- unsigned int get_size (unsigned int len) const
+ static unsigned int get_size (unsigned int len)
{ return len * Type::static_size; }
template <typename T> operator T * () { return arrayZ; }
@@ -533,6 +530,7 @@ struct UnsizedArrayOf
}
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
{
TRACE_SANITIZE (this);
@@ -720,7 +718,32 @@ struct ArrayOf
return_trace (out);
}
+ /* Special-case ArrayOf Offset16To structs with a maximum size. */
+ template <typename T = Type,
+ typename Base = void,
+ hb_enable_if (hb_has_max_size (typename T::target_t) &&
+ sizeof (T) == 2)>
+ HB_ALWAYS_INLINE
+ bool sanitize (hb_sanitize_context_t *c, const Base *base) const
+ {
+ TRACE_SANITIZE (this);
+
+ if (unlikely (!sanitize_shallow (c))) return_trace (false);
+
+ unsigned max_len = 65536 + Type::target_t::max_size;
+
+ if (unlikely (c->check_range_fast (base, max_len)))
+ return_trace (true);
+
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!c->dispatch (arrayZ[i], base)))
+ return_trace (false);
+ return_trace (true);
+ }
+
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
@@ -736,7 +759,7 @@ struct ArrayOf
bool sanitize_shallow (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
+ return_trace (len.sanitize (c) && c->check_array_sized (arrayZ, len, sizeof (LenType)));
}
public:
@@ -797,7 +820,7 @@ template <typename Type>
using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>;
/* An array starting at second element. */
-template <typename Type, typename LenType=HBUINT16>
+template <typename Type, typename LenType>
struct HeadlessArrayOf
{
static constexpr unsigned item_size = Type::static_size;
@@ -861,6 +884,7 @@ struct HeadlessArrayOf
}
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
@@ -878,7 +902,7 @@ struct HeadlessArrayOf
{
TRACE_SANITIZE (this);
return_trace (lenP1.sanitize (c) &&
- (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
+ (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType))));
}
public:
@@ -887,6 +911,7 @@ struct HeadlessArrayOf
public:
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
};
+template <typename Type> using HeadlessArray16Of = HeadlessArrayOf<Type, HBUINT16>;
/* An array storing length-1. */
template <typename Type, typename LenType=HBUINT16>
@@ -912,6 +937,7 @@ struct ArrayOfM1
{ return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
@@ -929,7 +955,7 @@ struct ArrayOfM1
{
TRACE_SANITIZE (this);
return_trace (lenM1.sanitize (c) &&
- (c->check_array (arrayZ, lenM1 + 1)));
+ (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType))));
}
public:
@@ -1096,6 +1122,7 @@ struct VarSizedBinSearchArrayOf
{ return header.static_size + header.nUnits * header.unitSize; }
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
index f22824fc69..a2f90c8f5e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
@@ -48,12 +48,24 @@ static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offs
struct code_pair_t
{
- hb_codepoint_t code;
+ unsigned code;
hb_codepoint_t glyph;
};
+
using str_buff_t = hb_vector_t<unsigned char>;
using str_buff_vec_t = hb_vector_t<str_buff_t>;
+using glyph_to_sid_map_t = hb_vector_t<code_pair_t>;
+
+struct length_f_t
+{
+ template <typename Iterable,
+ hb_requires (hb_is_iterable (Iterable))>
+ unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); }
+
+ unsigned operator () (unsigned _) const { return _; }
+}
+HB_FUNCOBJ (length_f);
/* CFF INDEX */
template <typename COUNT>
@@ -62,42 +74,52 @@ struct CFFIndex
unsigned int offset_array_size () const
{ return offSize * (count + 1); }
- CFFIndex *copy (hb_serialize_context_t *c) const
- {
- TRACE_SERIALIZE (this);
- unsigned int size = get_size ();
- CFFIndex *out = c->allocate_size<CFFIndex> (size, false);
- if (likely (out))
- hb_memcpy (out, this, size);
- return_trace (out);
- }
-
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
bool serialize (hb_serialize_context_t *c,
- const Iterable &iterable)
+ const Iterable &iterable,
+ const unsigned *p_data_size = nullptr)
{
TRACE_SERIALIZE (this);
+ unsigned data_size;
+ if (p_data_size)
+ data_size = *p_data_size;
+ else
+ total_size (iterable, &data_size);
+
auto it = hb_iter (iterable);
- serialize_header(c, + it | hb_map (hb_iter) | hb_map (hb_len));
+ if (unlikely (!serialize_header (c, +it, data_size))) return_trace (false);
+ unsigned char *ret = c->allocate_size<unsigned char> (data_size, false);
+ if (unlikely (!ret)) return_trace (false);
for (const auto &_ : +it)
- hb_iter (_).copy (c);
+ {
+ unsigned len = _.length;
+ if (len <= 1)
+ {
+ if (!len)
+ continue;
+ *ret++ = *_.arrayZ;
+ continue;
+ }
+ hb_memcpy (ret, _.arrayZ, len);
+ ret += len;
+ }
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize_header (hb_serialize_context_t *c,
- Iterator it)
+ Iterator it,
+ unsigned data_size)
{
TRACE_SERIALIZE (this);
- unsigned total = + it | hb_reduce (hb_add, 0);
- unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
+ unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8;
/* serialize CFFIndex header */
if (unlikely (!c->extend_min (this))) return_trace (false);
- this->count = it.len ();
+ this->count = hb_len (it);
if (!this->count) return_trace (true);
if (unlikely (!c->extend (this->offSize))) return_trace (false);
this->offSize = off_size;
@@ -106,25 +128,88 @@ struct CFFIndex
/* serialize indices */
unsigned int offset = 1;
- unsigned int i = 0;
- for (unsigned _ : +it)
+ if (HB_OPTIMIZE_SIZE_VAL)
{
- set_offset_at (i++, offset);
- offset += _;
+ unsigned int i = 0;
+ for (const auto &_ : +it)
+ {
+ set_offset_at (i++, offset);
+ offset += length_f (_);
+ }
+ set_offset_at (i, offset);
}
- set_offset_at (i, offset);
-
+ else
+ switch (off_size)
+ {
+ case 1:
+ {
+ HBUINT8 *p = (HBUINT8 *) offsets;
+ for (const auto &_ : +it)
+ {
+ *p++ = offset;
+ offset += length_f (_);
+ }
+ *p = offset;
+ }
+ break;
+ case 2:
+ {
+ HBUINT16 *p = (HBUINT16 *) offsets;
+ for (const auto &_ : +it)
+ {
+ *p++ = offset;
+ offset += length_f (_);
+ }
+ *p = offset;
+ }
+ break;
+ case 3:
+ {
+ HBUINT24 *p = (HBUINT24 *) offsets;
+ for (const auto &_ : +it)
+ {
+ *p++ = offset;
+ offset += length_f (_);
+ }
+ *p = offset;
+ }
+ break;
+ case 4:
+ {
+ HBUINT32 *p = (HBUINT32 *) offsets;
+ for (const auto &_ : +it)
+ {
+ *p++ = offset;
+ offset += length_f (_);
+ }
+ *p = offset;
+ }
+ break;
+ default:
+ break;
+ }
+
+ assert (offset == data_size + 1);
return_trace (true);
}
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
- static unsigned total_size (const Iterable &iterable)
+ static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr)
{
- auto it = + hb_iter (iterable) | hb_map (hb_iter) | hb_map (hb_len);
- if (!it) return 0;
+ auto it = + hb_iter (iterable);
+ if (!it)
+ {
+ if (data_size) *data_size = 0;
+ return min_size;
+ }
+
+ unsigned total = 0;
+ for (const auto &_ : +it)
+ total += length_f (_);
+
+ if (data_size) *data_size = total;
- unsigned total = + it | hb_reduce (hb_add, 0);
unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
@@ -133,13 +218,16 @@ struct CFFIndex
void set_offset_at (unsigned int index, unsigned int offset)
{
assert (index <= count);
- HBUINT8 *p = offsets + offSize * index + offSize;
+
unsigned int size = offSize;
- for (; size; size--)
+ const HBUINT8 *p = offsets;
+ switch (size)
{
- --p;
- *p = offset & 0xFF;
- offset >>= 8;
+ case 1: ((HBUINT8 *) p)[index] = offset; break;
+ case 2: ((HBUINT16 *) p)[index] = offset; break;
+ case 3: ((HBUINT24 *) p)[index] = offset; break;
+ case 4: ((HBUINT32 *) p)[index] = offset; break;
+ default: return;
}
}
@@ -149,37 +237,30 @@ struct CFFIndex
assert (index <= count);
unsigned int size = offSize;
- const HBUINT8 *p = offsets + size * index;
+ const HBUINT8 *p = offsets;
switch (size)
{
- case 1: return * (HBUINT8 *) p;
- case 2: return * (HBUINT16 *) p;
- case 3: return * (HBUINT24 *) p;
- case 4: return * (HBUINT32 *) p;
+ case 1: return ((HBUINT8 *) p)[index];
+ case 2: return ((HBUINT16 *) p)[index];
+ case 3: return ((HBUINT24 *) p)[index];
+ case 4: return ((HBUINT32 *) p)[index];
default: return 0;
}
}
- unsigned int length_at (unsigned int index) const
- {
- unsigned offset0 = offset_at (index);
- unsigned offset1 = offset_at (index + 1);
- if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
- return 0;
- return offset1 - offset0;
- }
-
const unsigned char *data_base () const
- { return (const unsigned char *) this + min_size + offSize.static_size + offset_array_size (); }
+ { return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); }
public:
hb_ubytes_t operator [] (unsigned int index) const
{
if (unlikely (index >= count)) return hb_ubytes_t ();
_hb_compiler_memory_r_barrier ();
- unsigned length = length_at (index);
- if (unlikely (!length)) return hb_ubytes_t ();
- return hb_ubytes_t (data_base () + offset_at (index) - 1, length);
+ unsigned offset0 = offset_at (index);
+ unsigned offset1 = offset_at (index + 1);
+ if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
+ return hb_ubytes_t ();
+ return hb_ubytes_t (data_base () + offset0, offset1 - offset0);
}
unsigned int get_size () const
@@ -197,7 +278,7 @@ struct CFFIndex
(count < count + 1u &&
c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1u) &&
- c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count) - 1)))));
+ c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count))))));
}
public:
@@ -211,47 +292,6 @@ struct CFFIndex
DEFINE_SIZE_MIN (COUNT::static_size);
};
-template <typename COUNT, typename TYPE>
-struct CFFIndexOf : CFFIndex<COUNT>
-{
- template <typename DATA, typename PARAM1, typename PARAM2>
- bool serialize (hb_serialize_context_t *c,
- unsigned int offSize_,
- const DATA *dataArray,
- unsigned int dataArrayLen,
- const hb_vector_t<unsigned int> &dataSizeArray,
- const PARAM1 &param1,
- const PARAM2 &param2)
- {
- TRACE_SERIALIZE (this);
- /* serialize CFFIndex header */
- if (unlikely (!c->extend_min (this))) return_trace (false);
- this->count = dataArrayLen;
- this->offSize = offSize_;
- if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1), false)))
- return_trace (false);
-
- /* serialize indices */
- unsigned int offset = 1;
- unsigned int i = 0;
- for (; i < dataArrayLen; i++)
- {
- this->set_offset_at (i, offset);
- offset += dataSizeArray[i];
- }
- this->set_offset_at (i, offset);
-
- /* serialize data */
- for (unsigned int i = 0; i < dataArrayLen; i++)
- {
- TYPE *dest = c->start_embed<TYPE> ();
- if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2)))
- return_trace (false);
- }
- return_trace (true);
- }
-};
-
/* Top Dict, Font Dict, Private Dict */
struct Dict : UnsizedByteStr
{
@@ -327,7 +367,7 @@ struct table_info_t
};
template <typename COUNT>
-struct FDArray : CFFIndexOf<COUNT, FontDict>
+struct FDArray : CFFIndex<COUNT>
{
template <typename DICTVAL, typename INFO, typename Iterator, typename OP_SERIALIZER>
bool serialize (hb_serialize_context_t *c,
@@ -338,7 +378,11 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
/* serialize INDEX data */
hb_vector_t<unsigned> sizes;
+ if (it.is_random_access_iterator)
+ sizes.alloc (hb_len (it));
+
c->push ();
+ char *data_base = c->head;
+ it
| hb_map ([&] (const hb_pair_t<const DICTVAL&, const INFO&> &_)
{
@@ -348,10 +392,16 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
})
| hb_sink (sizes)
;
+ unsigned data_size = c->head - data_base;
c->pop_pack (false);
+ if (unlikely (sizes.in_error ())) return_trace (false);
+
+ /* It just happens that the above is packed right after the header below.
+ * Such a hack. */
+
/* serialize INDEX header */
- return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes)));
+ return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes), data_size));
}
};
@@ -368,8 +418,11 @@ struct FDSelect0 {
return_trace (true);
}
- hb_codepoint_t get_fd (hb_codepoint_t glyph) const
- { return (hb_codepoint_t) fds[glyph]; }
+ unsigned get_fd (hb_codepoint_t glyph) const
+ { return fds[glyph]; }
+
+ hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const
+ { return {fds[glyph], glyph + 1}; }
unsigned int get_size (unsigned int num_glyphs) const
{ return HBUINT8::static_size * num_glyphs; }
@@ -427,12 +480,20 @@ struct FDSelect3_4
return +1;
}
- hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+ unsigned get_fd (hb_codepoint_t glyph) const
{
auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
return range ? range->fd : ranges[nRanges () - 1].fd;
}
+ hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const
+ {
+ auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
+ unsigned fd = range ? range->fd : ranges[nRanges () - 1].fd;
+ hb_codepoint_t end = range ? range[1].first : ranges[nRanges () - 1].first;
+ return {fd, end};
+ }
+
GID_TYPE &nRanges () { return ranges.len; }
GID_TYPE nRanges () const { return ranges.len; }
GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
@@ -469,7 +530,7 @@ struct FDSelect
}
}
- hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+ unsigned get_fd (hb_codepoint_t glyph) const
{
if (this == &Null (FDSelect)) return 0;
@@ -480,6 +541,18 @@ struct FDSelect
default:return 0;
}
}
+ /* Returns pair of fd and one after last glyph in range. */
+ hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const
+ {
+ if (this == &Null (FDSelect)) return {0, 1};
+
+ switch (format)
+ {
+ case 0: return u.format0.get_fd_range (glyph);
+ case 3: return u.format3.get_fd_range (glyph);
+ default:return {0, 1};
+ }
+ }
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
index 5040c74623..66df28aae1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
@@ -574,11 +574,11 @@ bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h
struct get_seac_param_t
{
- get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {}
+ get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {}
bool has_seac () const { return base && accent; }
- const OT::cff1::accelerator_t *cff;
+ const OT::cff1::accelerator_subset_t *cff;
hb_codepoint_t base = 0;
hb_codepoint_t accent = 0;
};
@@ -596,7 +596,7 @@ struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_par
}
};
-bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
+bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
{
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
index 4d0a965eee..3d658ac626 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
@@ -28,7 +28,7 @@
#define HB_OT_CFF1_TABLE_HH
#include "hb-ot-cff-common.hh"
-#include "hb-subset-cff1.hh"
+#include "hb-subset-cff-common.hh"
#include "hb-draw.hh"
#include "hb-paint.hh"
@@ -52,7 +52,6 @@ enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 };
enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 };
typedef CFFIndex<HBUINT16> CFF1Index;
-template <typename Type> struct CFF1IndexOf : CFFIndexOf<HBUINT16, Type> {};
typedef CFFIndex<HBUINT16> CFF1Index;
typedef CFF1Index CFF1CharStrings;
@@ -110,6 +109,7 @@ struct Encoding1 {
hb_codepoint_t get_code (hb_codepoint_t glyph) const
{
+ /* TODO: Add cache like get_sid. */
assert (glyph > 0);
glyph--;
for (unsigned int i = 0; i < nRanges (); i++)
@@ -173,11 +173,7 @@ struct Encoding
bool serialize (hb_serialize_context_t *c, const Encoding &src)
{
TRACE_SERIALIZE (this);
- unsigned int size = src.get_size ();
- Encoding *dest = c->allocate_size<Encoding> (size);
- if (unlikely (!dest)) return_trace (false);
- hb_memcpy (dest, &src, size);
- return_trace (true);
+ return_trace (c->embed (src));
}
/* serialize a subset Encoding */
@@ -312,26 +308,29 @@ struct Encoding
};
/* Charset */
-struct Charset0 {
- bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
+struct Charset0
+{
+ bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c));
+ if (num_charset_entries) *num_charset_entries = num_glyphs;
+ return_trace (sids.sanitize (c, num_glyphs - 1));
}
hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const
{
if (unlikely (glyph >= num_glyphs)) return 0;
- if (glyph == 0)
+ if (unlikely (glyph == 0))
return 0;
else
return sids[glyph - 1];
}
- void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const
+ void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
{
+ mapping->resize (num_glyphs, false);
for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++)
- mapping->set (gid, sids[gid - 1]);
+ mapping->arrayZ[gid] = {sids[gid - 1], gid};
}
hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
@@ -347,13 +346,13 @@ struct Charset0 {
return 0;
}
- unsigned int get_size (unsigned int num_glyphs) const
+ static unsigned int get_size (unsigned int num_glyphs)
{
assert (num_glyphs > 0);
- return HBUINT16::static_size * (num_glyphs - 1);
+ return UnsizedArrayOf<HBUINT16>::get_size (num_glyphs - 1);
}
- HBUINT16 sids[HB_VAR_ARRAY];
+ UnsizedArrayOf<HBUINT16> sids;
DEFINE_SIZE_ARRAY(0, sids);
};
@@ -374,38 +373,62 @@ struct Charset_Range {
template <typename TYPE>
struct Charset1_2 {
- bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
+ bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
num_glyphs--;
- for (unsigned int i = 0; num_glyphs > 0; i++)
+ unsigned i;
+ for (i = 0; num_glyphs > 0; i++)
{
if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1)))
return_trace (false);
num_glyphs -= (ranges[i].nLeft + 1);
}
+ if (num_charset_entries)
+ *num_charset_entries = i;
return_trace (true);
}
- hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const
+ hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs,
+ code_pair_t *cache = nullptr) const
{
if (unlikely (glyph >= num_glyphs)) return 0;
- if (glyph == 0) return 0;
- glyph--;
- for (unsigned int i = 0;; i++)
+ unsigned i;
+ hb_codepoint_t start_glyph;
+ if (cache && likely (cache->glyph <= glyph))
{
- if (glyph <= ranges[i].nLeft)
- return (hb_codepoint_t) ranges[i].first + glyph;
- glyph -= (ranges[i].nLeft + 1);
+ i = cache->code;
+ start_glyph = cache->glyph;
+ }
+ else
+ {
+ if (unlikely (glyph == 0)) return 0;
+ i = 0;
+ start_glyph = 1;
+ }
+ glyph -= start_glyph;
+ for (;; i++)
+ {
+ unsigned count = ranges[i].nLeft;
+ if (glyph <= count)
+ {
+ if (cache)
+ *cache = {i, start_glyph};
+ return ranges[i].first + glyph;
+ }
+ count++;
+ start_glyph += count;
+ glyph -= count;
}
return 0;
}
- void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const
+ void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
{
+ mapping->resize (num_glyphs, false);
hb_codepoint_t gid = 1;
if (gid >= num_glyphs)
return;
@@ -413,8 +436,9 @@ struct Charset1_2 {
{
hb_codepoint_t sid = ranges[i].first;
unsigned count = ranges[i].nLeft + 1;
+ unsigned last = gid + count;
for (unsigned j = 0; j < count; j++)
- mapping->set (gid++, sid++);
+ mapping->arrayZ[gid++] = {sid++, last - 1};
if (gid >= num_glyphs)
break;
@@ -439,21 +463,26 @@ struct Charset1_2 {
unsigned int get_size (unsigned int num_glyphs) const
{
- unsigned int size = HBUINT8::static_size;
- int glyph = (int)num_glyphs;
+ int glyph = (int) num_glyphs;
+ unsigned num_ranges = 0;
assert (glyph > 0);
glyph--;
for (unsigned int i = 0; glyph > 0; i++)
{
glyph -= (ranges[i].nLeft + 1);
- size += Charset_Range<TYPE>::static_size;
+ num_ranges++;
}
- return size;
+ return get_size_for_ranges (num_ranges);
+ }
+
+ static unsigned int get_size_for_ranges (unsigned int num_ranges)
+ {
+ return UnsizedArrayOf<Charset_Range<TYPE> >::get_size (num_ranges);
}
- Charset_Range<TYPE> ranges[HB_VAR_ARRAY];
+ UnsizedArrayOf<Charset_Range<TYPE>> ranges;
DEFINE_SIZE_ARRAY (0, ranges);
};
@@ -469,11 +498,7 @@ struct Charset
bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs)
{
TRACE_SERIALIZE (this);
- unsigned int size = src.get_size (num_glyphs);
- Charset *dest = c->allocate_size<Charset> (size);
- if (unlikely (!dest)) return_trace (false);
- hb_memcpy (dest, &src, size);
- return_trace (true);
+ return_trace (c->embed ((const char *) &src, src.get_size (num_glyphs)));
}
/* serialize a subset Charset */
@@ -490,13 +515,13 @@ struct Charset
{
case 0:
{
- Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1));
+ Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::get_size (num_glyphs), false);
if (unlikely (!fmt0)) return_trace (false);
unsigned int glyph = 0;
for (unsigned int i = 0; i < sid_ranges.length; i++)
{
- hb_codepoint_t sid = sid_ranges[i].code;
- for (int left = (int)sid_ranges[i].glyph; left >= 0; left--)
+ hb_codepoint_t sid = sid_ranges.arrayZ[i].code;
+ for (int left = (int)sid_ranges.arrayZ[i].glyph; left >= 0; left--)
fmt0->sids[glyph++] = sid++;
}
}
@@ -504,29 +529,35 @@ struct Charset
case 1:
{
- Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length);
+ Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::get_size_for_ranges (sid_ranges.length), false);
if (unlikely (!fmt1)) return_trace (false);
+ hb_codepoint_t all_glyphs = 0;
for (unsigned int i = 0; i < sid_ranges.length; i++)
{
- if (unlikely (!(sid_ranges[i].glyph <= 0xFF)))
- return_trace (false);
- fmt1->ranges[i].first = sid_ranges[i].code;
- fmt1->ranges[i].nLeft = sid_ranges[i].glyph;
+ auto &_ = sid_ranges.arrayZ[i];
+ all_glyphs |= _.glyph;
+ fmt1->ranges[i].first = _.code;
+ fmt1->ranges[i].nLeft = _.glyph;
}
+ if (unlikely (!(all_glyphs <= 0xFF)))
+ return_trace (false);
}
break;
case 2:
{
- Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length);
+ Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::get_size_for_ranges (sid_ranges.length), false);
if (unlikely (!fmt2)) return_trace (false);
+ hb_codepoint_t all_glyphs = 0;
for (unsigned int i = 0; i < sid_ranges.length; i++)
{
- if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF)))
- return_trace (false);
- fmt2->ranges[i].first = sid_ranges[i].code;
- fmt2->ranges[i].nLeft = sid_ranges[i].glyph;
+ auto &_ = sid_ranges.arrayZ[i];
+ all_glyphs |= _.glyph;
+ fmt2->ranges[i].first = _.code;
+ fmt2->ranges[i].nLeft = _.glyph;
}
+ if (unlikely (!(all_glyphs <= 0xFFFF)))
+ return_trace (false);
}
break;
@@ -545,18 +576,19 @@ struct Charset
}
}
- hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const
+ hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs,
+ code_pair_t *cache = nullptr) const
{
switch (format)
{
case 0: return u.format0.get_sid (glyph, num_glyphs);
- case 1: return u.format1.get_sid (glyph, num_glyphs);
- case 2: return u.format2.get_sid (glyph, num_glyphs);
+ case 1: return u.format1.get_sid (glyph, num_glyphs, cache);
+ case 2: return u.format2.get_sid (glyph, num_glyphs, cache);
default:return 0;
}
}
- void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const
+ void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
{
switch (format)
{
@@ -578,7 +610,7 @@ struct Charset
}
}
- bool sanitize (hb_sanitize_context_t *c) const
+ bool sanitize (hb_sanitize_context_t *c, unsigned *num_charset_entries) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
@@ -586,9 +618,9 @@ struct Charset
switch (format)
{
- case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
- case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
- case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
+ case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+ case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+ case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs (), num_charset_entries));
default:return_trace (false);
}
}
@@ -606,10 +638,10 @@ struct Charset
struct CFF1StringIndex : CFF1Index
{
bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings,
- const hb_inc_bimap_t &sidmap)
+ const hb_vector_t<unsigned> &sidmap)
{
TRACE_SERIALIZE (this);
- if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0)))
+ if (unlikely ((strings.count == 0) || (sidmap.length == 0)))
{
if (unlikely (!c->extend_min (this->count)))
return_trace (false);
@@ -617,15 +649,13 @@ struct CFF1StringIndex : CFF1Index
return_trace (true);
}
- byte_str_array_t bytesArray;
- if (!bytesArray.resize (sidmap.get_population ()))
- return_trace (false);
- for (unsigned int i = 0; i < strings.count; i++)
- {
- hb_codepoint_t j = sidmap[i];
- if (j != HB_MAP_VALUE_INVALID)
- bytesArray[j] = strings[i];
- }
+ if (unlikely (sidmap.in_error ())) return_trace (false);
+
+ // Save this in a vector since serialize() iterates it twice.
+ hb_vector_t<hb_ubytes_t> bytesArray (+ hb_iter (sidmap)
+ | hb_map (strings));
+
+ if (unlikely (bytesArray.in_error ())) return_trace (false);
bool result = CFF1Index::serialize (c, bytesArray);
return_trace (result);
@@ -932,7 +962,7 @@ struct cff1_private_dict_opset_t : dict_opset_t
}
};
-struct cff1_private_dict_opset_subset : dict_opset_t
+struct cff1_private_dict_opset_subset_t : dict_opset_t
{
static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval)
{
@@ -978,7 +1008,7 @@ typedef dict_interpreter_t<cff1_top_dict_opset_t, cff1_top_dict_values_t, cff1_t
typedef dict_interpreter_t<cff1_font_dict_opset_t, cff1_font_dict_values_t> cff1_font_dict_interpreter_t;
typedef CFF1Index CFF1NameIndex;
-typedef CFF1IndexOf<TopDict> CFF1TopDictIndex;
+typedef CFF1Index CFF1TopDictIndex;
struct cff1_font_dict_values_mod_t
{
@@ -1031,8 +1061,10 @@ struct cff1
template <typename PRIVOPSET, typename PRIVDICTVAL>
struct accelerator_templ_t
{
- void init (hb_face_t *face)
+ accelerator_templ_t (hb_face_t *face)
{
+ if (!face) return;
+
topDict.init ();
fontDicts.init ();
privateDicts.init ();
@@ -1046,22 +1078,22 @@ struct cff1
const OT::cff1 *cff = this->blob->template as<OT::cff1> ();
if (cff == &Null (OT::cff1))
- { fini (); return; }
+ goto fail;
nameIndex = &cff->nameIndex (cff);
if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc))
- { fini (); return; }
+ goto fail;
topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
- { fini (); return; }
+ goto fail;
{ /* parse top dict */
const hb_ubytes_t topDictStr = (*topDictIndex)[0];
- if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
+ if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
cff1_top_dict_interp_env_t env (topDictStr);
cff1_top_dict_interpreter_t top_interp (env);
- if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
+ if (unlikely (!top_interp.interpret (topDict))) goto fail;
}
if (is_predef_charset ())
@@ -1069,7 +1101,7 @@ struct cff1
else
{
charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
- if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; }
+ if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc, &num_charset_entries))) goto fail;
}
fdCount = 1;
@@ -1079,7 +1111,7 @@ struct cff1
fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) ||
(fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
- { fini (); return; }
+ goto fail;
fdCount = fdArray->count;
}
@@ -1092,36 +1124,36 @@ struct cff1
encoding = &Null (Encoding);
if (is_CID ())
{
- if (unlikely (charset == &Null (Charset))) { fini (); return; }
+ if (unlikely (charset == &Null (Charset))) goto fail;
}
else
{
if (!is_predef_encoding ())
{
encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
- if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; }
+ if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) goto fail;
}
}
stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
- { fini (); return; }
+ goto fail;
globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc))
- { fini (); return; }
+ goto fail;
charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
- { fini (); return; }
+ goto fail;
num_glyphs = charStrings->count;
if (num_glyphs != sc.get_num_glyphs ())
- { fini (); return; }
+ goto fail;
if (unlikely (!privateDicts.resize (fdCount)))
- { fini (); return; }
+ goto fail;
for (unsigned int i = 0; i < fdCount; i++)
privateDicts[i].init ();
@@ -1131,27 +1163,27 @@ struct cff1
for (unsigned int i = 0; i < fdCount; i++)
{
hb_ubytes_t fontDictStr = (*fdArray)[i];
- if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
+ if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
cff1_font_dict_values_t *font;
cff1_top_dict_interp_env_t env (fontDictStr);
cff1_font_dict_interpreter_t font_interp (env);
font = fontDicts.push ();
- if (unlikely (fontDicts.in_error ())) { fini (); return; }
+ if (unlikely (fontDicts.in_error ())) goto fail;
font->init ();
- if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
+ if (unlikely (!font_interp.interpret (*font))) goto fail;
PRIVDICTVAL *priv = &privateDicts[i];
const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
+ if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
num_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
priv->init ();
- if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
+ if (unlikely (!priv_interp.interpret (*priv))) goto fail;
priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
if (priv->localSubrs != &Null (CFF1Subrs) &&
unlikely (!priv->localSubrs->sanitize (&sc)))
- { fini (); return; }
+ goto fail;
}
}
else /* non-CID */
@@ -1160,20 +1192,25 @@ struct cff1
PRIVDICTVAL *priv = &privateDicts[0];
const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
+ if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
num_interp_env_t env (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
priv->init ();
- if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
+ if (unlikely (!priv_interp.interpret (*priv))) goto fail;
priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
if (priv->localSubrs != &Null (CFF1Subrs) &&
unlikely (!priv->localSubrs->sanitize (&sc)))
- { fini (); return; }
+ goto fail;
}
- }
- void fini ()
+ return;
+
+ fail:
+ _fini ();
+ }
+ ~accelerator_templ_t () { _fini (); }
+ void _fini ()
{
sc.end_processing ();
topDict.fini ();
@@ -1183,6 +1220,8 @@ struct cff1
blob = nullptr;
}
+ hb_blob_t *get_blob () const { return blob; }
+
bool is_valid () const { return blob; }
bool is_CID () const { return topDict.is_CID (); }
@@ -1203,13 +1242,14 @@ struct cff1
bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; }
- hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const
+ hb_codepoint_t glyph_to_code (hb_codepoint_t glyph,
+ code_pair_t *glyph_to_sid_cache = nullptr) const
{
if (encoding != &Null (Encoding))
return encoding->get_code (glyph);
else
{
- hb_codepoint_t sid = glyph_to_sid (glyph);
+ hb_codepoint_t sid = glyph_to_sid (glyph, glyph_to_sid_cache);
if (sid == 0) return 0;
hb_codepoint_t code = 0;
switch (topDict.EncodingOffset)
@@ -1227,12 +1267,14 @@ struct cff1
}
}
- hb_map_t *create_glyph_to_sid_map () const
+ glyph_to_sid_map_t *create_glyph_to_sid_map () const
{
if (charset != &Null (Charset))
{
- hb_map_t *mapping = hb_map_create ();
- mapping->set (0, 0);
+ auto *mapping = (glyph_to_sid_map_t *) hb_malloc (sizeof (glyph_to_sid_map_t));
+ if (unlikely (!mapping)) return nullptr;
+ mapping = new (mapping) glyph_to_sid_map_t ();
+ mapping->push (code_pair_t {0, 1});
charset->collect_glyph_to_sid_map (mapping, num_glyphs);
return mapping;
}
@@ -1240,10 +1282,11 @@ struct cff1
return nullptr;
}
- hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const
+ hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph,
+ code_pair_t *cache = nullptr) const
{
if (charset != &Null (Charset))
- return charset->get_sid (glyph, num_glyphs);
+ return charset->get_sid (glyph, num_glyphs, cache);
else
{
hb_codepoint_t sid = 0;
@@ -1312,19 +1355,17 @@ struct cff1
hb_vector_t<PRIVDICTVAL> privateDicts;
unsigned int num_glyphs = 0;
+ unsigned int num_charset_entries = 0;
};
struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
{
- accelerator_t (hb_face_t *face)
+ accelerator_t (hb_face_t *face) : SUPER (face)
{
- SUPER::init (face);
-
glyph_names.set_relaxed (nullptr);
if (!is_valid ()) return;
if (is_CID ()) return;
-
}
~accelerator_t ()
{
@@ -1334,8 +1375,6 @@ struct cff1
names->fini ();
hb_free (names);
}
-
- SUPER::fini ();
}
bool get_glyph_name (hb_codepoint_t glyph,
@@ -1386,9 +1425,10 @@ struct cff1
/* TODO */
/* fill glyph names */
+ code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
{
- hb_codepoint_t sid = glyph_to_sid (gid);
+ hb_codepoint_t sid = glyph_to_sid (gid, &glyph_to_sid_cache);
gname_t gname;
gname.sid = sid;
if (sid < cff1_std_strings_length)
@@ -1426,7 +1466,6 @@ struct cff1
HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
- HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
private:
@@ -1453,9 +1492,24 @@ struct cff1
typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER;
};
- struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> {};
+ struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset_t, cff1_private_dict_values_subset_t>
+ {
+ accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
+ ~accelerator_subset_t ()
+ {
+ if (cff_accelerator)
+ cff_subset_accelerator_t::destroy (cff_accelerator);
+ }
+
+ HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+ HB_INTERNAL bool serialize (hb_serialize_context_t *c,
+ struct cff1_subset_plan &plan) const;
+ HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
+
+ mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
- bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); }
+ typedef accelerator_templ_t<cff1_private_dict_opset_subset_t, cff1_private_dict_values_subset_t> SUPER;
+ };
protected:
HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid);
@@ -1479,6 +1533,10 @@ struct cff1_accelerator_t : cff1::accelerator_t {
cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {}
};
+struct cff1_subset_accelerator_t : cff1::accelerator_subset_t {
+ cff1_subset_accelerator_t (hb_face_t *face) : cff1::accelerator_subset_t (face) {}
+};
+
} /* namespace OT */
#endif /* HB_OT_CFF1_TABLE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
index 2134d48660..9913cdad0c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
@@ -28,7 +28,7 @@
#define HB_OT_CFF2_TABLE_HH
#include "hb-ot-cff-common.hh"
-#include "hb-subset-cff2.hh"
+#include "hb-subset-cff-common.hh"
#include "hb-draw.hh"
#include "hb-paint.hh"
@@ -41,7 +41,6 @@ namespace CFF {
#define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2')
typedef CFFIndex<HBUINT32> CFF2Index;
-template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {};
typedef CFF2Index CFF2CharStrings;
typedef Subrs<HBUINT32> CFF2Subrs;
@@ -393,6 +392,8 @@ struct cff2
{
accelerator_templ_t (hb_face_t *face)
{
+ if (!face) return;
+
topDict.init ();
fontDicts.init ();
privateDicts.init ();
@@ -464,7 +465,6 @@ struct cff2
goto fail;
}
-
return;
fail:
@@ -481,11 +481,13 @@ struct cff2
blob = nullptr;
}
- hb_map_t *create_glyph_to_sid_map () const
+ hb_vector_t<uint16_t> *create_glyph_to_sid_map () const
{
return nullptr;
}
+ hb_blob_t *get_blob () const { return blob; }
+
bool is_valid () const { return blob; }
protected:
@@ -518,9 +520,24 @@ struct cff2
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
};
- typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
+ struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t>
+ {
+ accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
+ ~accelerator_subset_t ()
+ {
+ if (cff_accelerator)
+ cff_subset_accelerator_t::destroy (cff_accelerator);
+ }
- bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); }
+ HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+ HB_INTERNAL bool serialize (hb_serialize_context_t *c,
+ struct cff2_subset_plan &plan,
+ hb_array_t<int> normalized_coords) const;
+
+ mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
+
+ typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> SUPER;
+ };
public:
FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */
@@ -535,6 +552,10 @@ struct cff2_accelerator_t : cff2::accelerator_t {
cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {}
};
+struct cff2_subset_accelerator_t : cff2::accelerator_subset_t {
+ cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {}
+};
+
} /* namespace OT */
#endif /* HB_OT_CFF2_TABLE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
index cf5ccd53e9..30401b1926 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
@@ -277,10 +277,10 @@ struct CmapSubtableFormat4
}
} writer(c);
- writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
- c->allocate_size<HBUINT16> (2); // padding
- writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
- writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount);
+ writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
+ (void) c->allocate_size<HBUINT16> (2); // padding
+ writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
+ writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount, false);
if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
@@ -325,7 +325,7 @@ struct CmapSubtableFormat4
{
auto format4_iter =
+ it
- | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+ | hb_filter ([&] (const hb_codepoint_pair_t _)
{ return _.first <= 0xFFFF; })
;
@@ -335,7 +335,7 @@ struct CmapSubtableFormat4
if (unlikely (!c->extend_min (this))) return;
this->format = 4;
- hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> cp_to_gid {
+ hb_vector_t<hb_codepoint_pair_t> cp_to_gid {
format4_iter
};
@@ -757,8 +757,7 @@ struct CmapSubtableLongSegmented
hb_codepoint_t gid = this->groups[i].glyphID;
if (!gid)
{
- /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
- if (! T::group_get_glyph (this->groups[i], end)) continue;
+ if (T::formatNumber == 13) continue;
start++;
gid++;
}
@@ -766,11 +765,13 @@ struct CmapSubtableLongSegmented
if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
end = start + (hb_codepoint_t) num_glyphs - gid;
+ mapping->alloc (mapping->get_population () + end - start + 1);
+
for (unsigned cp = start; cp <= end; cp++)
{
unicodes->add (cp);
mapping->set (cp, gid);
- gid++;
+ gid += T::increment;
}
}
}
@@ -794,6 +795,9 @@ struct CmapSubtableLongSegmented
struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
{
+ static constexpr int increment = 1;
+ static constexpr int formatNumber = 12;
+
static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
hb_codepoint_t u)
{ return likely (group.startCharCode <= group.endCharCode) ?
@@ -866,6 +870,9 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
{
+ static constexpr int increment = 0;
+ static constexpr int formatNumber = 13;
+
static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
hb_codepoint_t u HB_UNUSED)
{ return group.glyphID; }
@@ -917,8 +924,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
DefaultUVS* copy (hb_serialize_context_t *c,
const hb_set_t *unicodes) const
{
- DefaultUVS *out = c->start_embed<DefaultUVS> ();
- if (unlikely (!out)) return nullptr;
+ auto *out = c->start_embed<DefaultUVS> ();
auto snap = c->snapshot ();
HBUINT32 len;
@@ -931,8 +937,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
hb_codepoint_t start = HB_SET_VALUE_INVALID;
hb_codepoint_t end = HB_SET_VALUE_INVALID;
- for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
- unicodes->next (&u);)
+ for (auto u : *unicodes)
{
if (!as_array ().bsearch (u))
continue;
@@ -1067,9 +1072,7 @@ struct NonDefaultUVS : SortedArray32Of<UVSMapping>
const hb_set_t *glyphs_requested,
const hb_map_t *glyph_map) const
{
- NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
- if (unlikely (!out)) return nullptr;
-
+ auto *out = c->start_embed<NonDefaultUVS> ();
auto it =
+ as_array ()
| hb_filter ([&] (const UVSMapping& _)
@@ -1767,7 +1770,6 @@ struct cmap
TRACE_SUBSET (this);
cmap *cmap_prime = c->serializer->start_embed<cmap> ();
- if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
auto encodingrec_iter =
+ hb_iter (encodingRecord)
@@ -1798,7 +1800,7 @@ struct cmap
auto it =
+ c->plan->unicode_to_new_gid_list.iter ()
- | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+ | hb_filter ([&] (const hb_codepoint_pair_t _)
{ return (_.second != HB_MAP_VALUE_INVALID); })
;
diff --git a/thirdparty/harfbuzz/src/hb-ot-font.cc b/thirdparty/harfbuzz/src/hb-ot-font.cc
index c89a1954a9..b3677c6a4c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-font.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-font.cc
@@ -38,8 +38,8 @@
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
-#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
+#include "hb-ot-cff1-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
@@ -98,7 +98,7 @@ _hb_ot_font_create (hb_font_t *font)
{
cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t));
if (unlikely (!cmap_cache)) goto out;
- cmap_cache->init ();
+ new (cmap_cache) hb_ot_font_cmap_cache_t ();
if (unlikely (!hb_face_set_user_data (font->face,
&hb_ot_font_cmap_cache_user_data_key,
cmap_cache,
@@ -230,8 +230,8 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
use_cache = false;
goto out;
}
+ new (cache) hb_ot_font_advance_cache_t;
- cache->init ();
if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache)))
{
hb_free (cache);
@@ -255,7 +255,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
{ /* Use cache. */
if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords)
{
- ot_font->advance_cache->init ();
+ ot_font->advance_cache->clear ();
ot_font->cached_coords_serial.set_release (font->serial_coords);
}
@@ -436,8 +436,8 @@ hb_ot_get_glyph_extents (hb_font_t *font,
#endif
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
#ifndef HB_NO_OT_FONT_CFF
- if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
+ if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
#endif
return false;
@@ -525,8 +525,8 @@ hb_ot_draw_glyph (hb_font_t *font,
embolden ? &outline : draw_data, font->slant_xy);
if (!font->face->table.glyf->get_path (font, glyph, draw_session))
#ifndef HB_NO_CFF
- if (!font->face->table.cff1->get_path (font, glyph, draw_session))
if (!font->face->table.cff2->get_path (font, glyph, draw_session))
+ if (!font->face->table.cff1->get_path (font, glyph, draw_session))
#endif
{}
}
@@ -565,8 +565,8 @@ hb_ot_paint_glyph (hb_font_t *font,
#endif
if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#ifndef HB_NO_CFF
- if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
+ if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#endif
}
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-hdmx-table.hh b/thirdparty/harfbuzz/src/hb-ot-hdmx-table.hh
index 3bfd75502a..cbcf6f5f22 100644
--- a/thirdparty/harfbuzz/src/hb-ot-hdmx-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-hdmx-table.hh
@@ -46,21 +46,23 @@ struct DeviceRecord
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
+ bool serialize (hb_serialize_context_t *c,
+ unsigned pixelSize,
+ Iterator it,
+ const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
+ unsigned num_glyphs)
{
TRACE_SERIALIZE (this);
- unsigned length = it.len ();
-
- if (unlikely (!c->extend (this, length))) return_trace (false);
+ if (unlikely (!c->extend (this, num_glyphs))) return_trace (false);
this->pixelSize = pixelSize;
this->maxWidth =
+ it
| hb_reduce (hb_max, 0u);
- + it
- | hb_sink (widthsZ.as_array (length));
+ for (auto &_ : new_to_old_gid_list)
+ widthsZ[_.first] = *it++;
return_trace (true);
}
@@ -89,7 +91,11 @@ struct hdmx
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
+ bool serialize (hb_serialize_context_t *c,
+ unsigned version,
+ Iterator it,
+ const hb_vector_t<hb_codepoint_pair_t> &new_to_old_gid_list,
+ unsigned num_glyphs)
{
TRACE_SERIALIZE (this);
@@ -97,10 +103,10 @@ struct hdmx
this->version = version;
this->numRecords = it.len ();
- this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
+ this->sizeDeviceRecord = DeviceRecord::get_size (num_glyphs);
for (const hb_item_type<Iterator>& _ : +it)
- c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
+ c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second, new_to_old_gid_list, num_glyphs);
return_trace (c->successful ());
}
@@ -110,31 +116,30 @@ struct hdmx
{
TRACE_SUBSET (this);
- hdmx *hdmx_prime = c->serializer->start_embed <hdmx> ();
- if (unlikely (!hdmx_prime)) return_trace (false);
+ auto *hdmx_prime = c->serializer->start_embed <hdmx> ();
+ unsigned num_input_glyphs = get_num_glyphs ();
auto it =
+ hb_range ((unsigned) numRecords)
- | hb_map ([c, this] (unsigned _)
+ | hb_map ([c, num_input_glyphs, this] (unsigned _)
{
const DeviceRecord *device_record =
&StructAtOffset<DeviceRecord> (&firstDeviceRecord,
_ * sizeDeviceRecord);
auto row =
- + hb_range (c->plan->num_output_glyphs ())
- | hb_map (c->plan->reverse_glyph_map)
- | hb_map ([this, c, device_record] (hb_codepoint_t _)
+ + hb_iter (c->plan->new_to_old_gid_list)
+ | hb_map ([num_input_glyphs, device_record] (hb_codepoint_pair_t _)
{
- if (c->plan->is_empty_glyph (_))
- return Null (HBUINT8);
- return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
+ return device_record->widthsZ.as_array (num_input_glyphs) [_.second];
})
;
return hb_pair ((unsigned) device_record->pixelSize, +row);
})
;
- hdmx_prime->serialize (c->serializer, version, it);
+ hdmx_prime->serialize (c->serializer, version, it,
+ c->plan->new_to_old_gid_list,
+ c->plan->num_output_glyphs ());
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
index 835a1a585e..fed6ca1c7a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
@@ -83,7 +83,7 @@ struct hmtxvmtx
bool subset_update_header (hb_subset_context_t *c,
unsigned int num_hmetrics,
const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map,
- const hb_map_t *bounds_map) const
+ const hb_vector_t<unsigned> &bounds_vec) const
{
hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (c->plan->source, H::tableTag);
hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
@@ -114,6 +114,7 @@ struct hmtxvmtx
HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET, caretOffset);
}
+ bool empty = true;
int min_lsb = 0x7FFF;
int min_rsb = 0x7FFF;
int max_extent = -0x7FFF;
@@ -125,9 +126,10 @@ struct hmtxvmtx
int lsb = _.second.second;
max_adv = hb_max (max_adv, adv);
- if (bounds_map->has (gid))
+ if (bounds_vec[gid] != 0xFFFFFFFF)
{
- unsigned bound_width = bounds_map->get (gid);
+ empty = false;
+ unsigned bound_width = bounds_vec[gid];
int rsb = adv - lsb - bound_width;
int extent = lsb + bound_width;
min_lsb = hb_min (min_lsb, lsb);
@@ -137,7 +139,7 @@ struct hmtxvmtx
}
table->advanceMax = max_adv;
- if (!bounds_map->is_empty ())
+ if (!empty)
{
table->minLeadingBearing = min_lsb;
table->minTrailingBearing = min_rsb;
@@ -156,32 +158,31 @@ struct hmtxvmtx
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
Iterator it,
- unsigned num_long_metrics)
+ const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
+ unsigned num_long_metrics,
+ unsigned total_num_metrics)
{
- unsigned idx = 0;
- for (auto _ : it)
+ LongMetric* long_metrics = c->allocate_size<LongMetric> (num_long_metrics * LongMetric::static_size);
+ FWORD* short_metrics = c->allocate_size<FWORD> ((total_num_metrics - num_long_metrics) * FWORD::static_size);
+ if (!long_metrics || !short_metrics) return;
+
+ short_metrics -= num_long_metrics;
+
+ for (auto _ : new_to_old_gid_list)
{
- if (idx < num_long_metrics)
- {
- LongMetric lm;
- lm.advance = _.first;
- lm.sb = _.second;
- if (unlikely (!c->embed<LongMetric> (&lm))) return;
- }
- else if (idx < 0x10000u)
+ hb_codepoint_t gid = _.first;
+ auto mtx = *it++;
+
+ if (gid < num_long_metrics)
{
- FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
- if (unlikely (!sb)) return;
- *sb = _.second;
+ LongMetric& lm = long_metrics[gid];
+ lm.advance = mtx.first;
+ lm.sb = mtx.second;
}
+ else if (gid < 0x10000u)
+ short_metrics[gid] = mtx.second;
else
- {
- // TODO: This does not do tail optimization.
- UFWORD *adv = c->allocate_size<UFWORD> (UFWORD::static_size);
- if (unlikely (!adv)) return;
- *adv = _.first;
- }
- idx++;
+ ((UFWORD*) short_metrics)[gid] = mtx.first;
}
}
@@ -189,8 +190,7 @@ struct hmtxvmtx
{
TRACE_SUBSET (this);
- T *table_prime = c->serializer->start_embed <T> ();
- if (unlikely (!table_prime)) return_trace (false);
+ auto *table_prime = c->serializer->start_embed <T> ();
accelerator_t _mtx (c->plan->source);
unsigned num_long_metrics;
@@ -209,31 +209,36 @@ struct hmtxvmtx
}
auto it =
- + hb_range (c->plan->num_output_glyphs ())
- | hb_map ([c, &_mtx, mtx_map] (unsigned _)
+ + hb_iter (c->plan->new_to_old_gid_list)
+ | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _)
{
- if (!mtx_map->has (_))
+ hb_codepoint_t new_gid = _.first;
+ hb_codepoint_t old_gid = _.second;
+
+ hb_pair_t<unsigned, int> *v = nullptr;
+ if (!mtx_map->has (new_gid, &v))
{
- hb_codepoint_t old_gid;
- if (!c->plan->old_gid_for_new_gid (_, &old_gid))
- return hb_pair (0u, 0);
int lsb = 0;
if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
(void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb);
return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
}
- return mtx_map->get (_);
+ return *v;
})
;
- table_prime->serialize (c->serializer, it, num_long_metrics);
+ table_prime->serialize (c->serializer,
+ it,
+ c->plan->new_to_old_gid_list,
+ num_long_metrics,
+ c->plan->num_output_glyphs ());
if (unlikely (c->serializer->in_error ()))
return_trace (false);
// Amend header num hmetrics
if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map,
- T::is_horizontal ? &c->plan->bounds_width_map : &c->plan->bounds_height_map)))
+ T::is_horizontal ? c->plan->bounds_width_vec : c->plan->bounds_height_vec)))
return_trace (false);
return_trace (true);
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh
index 8179e5acd5..2b7e9e4b18 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh
@@ -170,8 +170,8 @@ struct FeatMinMaxRecord
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
- minCoord.sanitize (c, this) &&
- maxCoord.sanitize (c, this)));
+ minCoord.sanitize (c, base) &&
+ maxCoord.sanitize (c, base)));
}
protected:
@@ -187,7 +187,6 @@ struct FeatMinMaxRecord
* of MinMax table (may be NULL) */
public:
DEFINE_SIZE_STATIC (8);
-
};
struct MinMax
@@ -274,7 +273,7 @@ struct BaseLangSysRecord
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
- minMax.sanitize (c, this)));
+ minMax.sanitize (c, base)));
}
protected:
@@ -297,7 +296,8 @@ struct BaseScript
const BaseCoord &get_base_coord (int baseline_tag_index) const
{ return (this+baseValues).get_base_coord (baseline_tag_index); }
- bool has_data () const { return baseValues; }
+ bool has_values () const { return baseValues; }
+ bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -383,7 +383,7 @@ struct Axis
const BaseCoord **coord) const
{
const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
- if (!base_script.has_data ())
+ if (!base_script.has_values ())
{
*coord = nullptr;
return false;
@@ -410,7 +410,7 @@ struct Axis
const BaseCoord **max_coord) const
{
const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
- if (!base_script.has_data ())
+ if (!base_script.has_min_max ())
{
*min_coord = *max_coord = nullptr;
return false;
@@ -425,8 +425,8 @@ struct Axis
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
- (this+baseTagList).sanitize (c) &&
- (this+baseScriptList).sanitize (c)));
+ baseTagList.sanitize (c, this) &&
+ baseScriptList.sanitize (c, this)));
}
protected:
@@ -473,14 +473,13 @@ struct BASE
return true;
}
- /* TODO: Expose this separately sometime? */
bool get_min_max (hb_font_t *font,
hb_direction_t direction,
hb_tag_t script_tag,
hb_tag_t language_tag,
hb_tag_t feature_tag,
hb_position_t *min,
- hb_position_t *max)
+ hb_position_t *max) const
{
const BaseCoord *min_coord, *max_coord;
if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
index 36f123b559..b3af128e02 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
@@ -55,19 +55,22 @@ static bool ClassDef_remap_and_serialize (
hb_serialize_context_t *c,
const hb_set_t &klasses,
bool use_class_zero,
- hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */
+ hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */
hb_map_t *klass_map /*IN/OUT*/);
struct hb_collect_feature_substitutes_with_var_context_t
{
const hb_map_t *axes_index_tag_map;
- const hb_hashmap_t<hb_tag_t, int> *axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple> *axes_location;
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+ bool& insert_catch_all_feature_variation_record;
// not stored in subset_plan
hb_set_t *feature_indices;
bool apply;
+ bool variation_applied;
+ bool universal;
unsigned cur_record_idx;
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map;
};
@@ -807,7 +810,7 @@ struct Feature
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->featureParams.serialize_subset (c, featureParams, this, tag);
@@ -981,7 +984,7 @@ struct RecordListOfFeature : RecordListOf<Feature>
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ hb_enumerate (*this)
| hb_filter (l->feature_index_map, hb_first)
@@ -1078,7 +1081,7 @@ struct LangSys
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
const uint32_t *v;
out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
@@ -1188,7 +1191,7 @@ struct Script
return false;
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
bool defaultLang = false;
if (has_default_lang_sys ())
@@ -1247,7 +1250,7 @@ struct RecordListOfScript : RecordListOf<Script>
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
for (auto _ : + hb_enumerate (*this))
{
@@ -1367,7 +1370,7 @@ struct Lookup
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->lookupType = lookupType;
out->lookupFlag = lookupFlag;
@@ -1456,7 +1459,7 @@ struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ hb_enumerate (*this)
| hb_filter (l->lookup_index_map, hb_first)
@@ -1482,7 +1485,7 @@ struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c,
const hb_set_t &klasses,
bool use_class_zero,
- hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */
+ hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */
hb_map_t *klass_map /*IN/OUT*/)
{
if (!klass_map)
@@ -1573,7 +1576,7 @@ struct ClassDefFormat1_3
TRACE_SUBSET (this);
const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
- hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass;
+ hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
hb_set_t orig_klasses;
hb_codepoint_t start = startGlyph;
@@ -1592,10 +1595,13 @@ struct ClassDefFormat1_3
orig_klasses.add (klass);
}
- unsigned glyph_count = glyph_filter
- ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter))
- : glyph_map.get_population ();
- use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length;
+ if (use_class_zero)
+ {
+ unsigned glyph_count = glyph_filter
+ ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter))
+ : glyph_map.get_population ();
+ use_class_zero = glyph_count <= glyph_and_klass.length;
+ }
if (!ClassDef_remap_and_serialize (c->serializer,
orig_klasses,
use_class_zero,
@@ -1830,7 +1836,7 @@ struct ClassDefFormat2_4
const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
const hb_set_t &glyph_set = *c->plan->glyphset_gsub ();
- hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass;
+ hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
hb_set_t orig_klasses;
if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2
@@ -1916,7 +1922,7 @@ struct ClassDefFormat2_4
{
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (auto g : *glyphs)
if (get_class (g))
return true;
return false;
@@ -1976,8 +1982,7 @@ struct ClassDefFormat2_4
unsigned count = rangeRecord.len;
if (count > glyphs->get_population () * hb_bit_storage (count) * 8)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID;
- glyphs->next (&g);)
+ for (auto g : *glyphs)
{
unsigned i;
if (rangeRecord.as_array ().bfind (g, &i) &&
@@ -2377,7 +2382,7 @@ struct VarRegionList
return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount));
}
- bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t &region_map)
+ bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_inc_bimap_t &region_map)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
@@ -2494,7 +2499,7 @@ struct VarData
bool serialize (hb_serialize_context_t *c,
const VarData *src,
const hb_inc_bimap_t &inner_map,
- const hb_bimap_t &region_map)
+ const hb_inc_bimap_t &region_map)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
@@ -2905,9 +2910,9 @@ struct VariationStore
enum Cond_with_Var_flag_t
{
KEEP_COND_WITH_VAR = 0,
- DROP_COND_WITH_VAR = 1,
- DROP_RECORD_WITH_VAR = 2,
- MEM_ERR_WITH_VAR = 3,
+ KEEP_RECORD_WITH_VAR = 1,
+ DROP_COND_WITH_VAR = 2,
+ DROP_RECORD_WITH_VAR = 3,
};
struct ConditionFormat1
@@ -2940,29 +2945,42 @@ struct ConditionFormat1
hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
- //axis not pinned, keep the condition
- if (!c->axes_location->has (axis_tag))
+ Triple axis_range (-1.f, 0.f, 1.f);
+ if (c->axes_location->has (axis_tag))
+ axis_range = c->axes_location->get (axis_tag);
+
+ int axis_min_val = axis_range.minimum;
+ int axis_default_val = axis_range.middle;
+ int axis_max_val = axis_range.maximum;
+
+ int16_t filter_min_val = filterRangeMinValue.to_int ();
+ int16_t filter_max_val = filterRangeMaxValue.to_int ();
+
+ if (axis_default_val < filter_min_val ||
+ axis_default_val > filter_max_val)
+ c->apply = false;
+
+ //condition not met, drop the entire record
+ if (axis_min_val > filter_max_val || axis_max_val < filter_min_val ||
+ filter_min_val > filter_max_val)
+ return DROP_RECORD_WITH_VAR;
+
+ //condition met and axis pinned, drop the condition
+ if (c->axes_location->has (axis_tag) &&
+ c->axes_location->get (axis_tag).is_point ())
+ return DROP_COND_WITH_VAR;
+
+ if (filter_max_val != axis_max_val || filter_min_val != axis_min_val)
{
// add axisIndex->value into the hashmap so we can check if the record is
// unique with variations
- int16_t min_val = filterRangeMinValue.to_int ();
- int16_t max_val = filterRangeMaxValue.to_int ();
- hb_codepoint_t val = (max_val << 16) + min_val;
+ hb_codepoint_t val = (filter_max_val << 16) + filter_min_val;
condition_map->set (axisIndex, val);
return KEEP_COND_WITH_VAR;
}
- //axis pinned, check if condition is met
- //TODO: add check for axis Ranges
- int v = c->axes_location->get (axis_tag);
-
- //condition not met, drop the entire record
- if (v < filterRangeMinValue.to_int () || v > filterRangeMaxValue.to_int ())
- return DROP_RECORD_WITH_VAR;
-
- //axis pinned and condition met, drop the condition
- return DROP_COND_WITH_VAR;
+ return KEEP_RECORD_WITH_VAR;
}
bool evaluate (const int *coords, unsigned int coord_len) const
@@ -3001,7 +3019,7 @@ struct Condition
{
switch (u.format) {
case 1: return u.format1.keep_with_variations (c, condition_map);
- default:return KEEP_COND_WITH_VAR;
+ default: c->apply = false; return KEEP_COND_WITH_VAR;
}
}
@@ -3046,45 +3064,50 @@ struct ConditionSet
return true;
}
- Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ void keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
{
hb_map_t *condition_map = hb_map_create ();
- if (unlikely (!condition_map)) return MEM_ERR_WITH_VAR;
+ if (unlikely (!condition_map)) return;
hb::shared_ptr<hb_map_t> p {condition_map};
hb_set_t *cond_set = hb_set_create ();
- if (unlikely (!cond_set)) return MEM_ERR_WITH_VAR;
+ if (unlikely (!cond_set)) return;
hb::shared_ptr<hb_set_t> s {cond_set};
+ c->apply = true;
+ bool should_keep = false;
unsigned num_kept_cond = 0, cond_idx = 0;
for (const auto& offset : conditions)
{
Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
- // one condition is not met, drop the entire record
+ // condition is not met or condition out of range, drop the entire record
if (ret == DROP_RECORD_WITH_VAR)
- return DROP_RECORD_WITH_VAR;
+ return;
- // axis not pinned, keep this condition
if (ret == KEEP_COND_WITH_VAR)
{
+ should_keep = true;
cond_set->add (cond_idx);
num_kept_cond++;
}
+
+ if (ret == KEEP_RECORD_WITH_VAR)
+ should_keep = true;
+
cond_idx++;
}
- // all conditions met
- if (num_kept_cond == 0) return DROP_COND_WITH_VAR;
+ if (!should_keep) return;
//check if condition_set is unique with variations
if (c->conditionset_map->has (p))
//duplicate found, drop the entire record
- return DROP_RECORD_WITH_VAR;
+ return;
c->conditionset_map->set (p, 1);
c->record_cond_idx_map->set (c->cur_record_idx, s);
-
- return KEEP_COND_WITH_VAR;
+ if (should_keep && num_kept_cond == 0)
+ c->universal = true;
}
bool subset (hb_subset_context_t *c,
@@ -3289,12 +3312,11 @@ struct FeatureVariationRecord
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
const void *base) const
{
- // ret == 1, all conditions met
- if ((base+conditions).keep_with_variations (c) == DROP_COND_WITH_VAR &&
- c->apply)
+ (base+conditions).keep_with_variations (c);
+ if (c->apply && !c->variation_applied)
{
(base+substitutions).collect_feature_substitutes_with_variations (c);
- c->apply = false; // set variations only once
+ c->variation_applied = true; // set variations only once
}
}
@@ -3361,7 +3383,12 @@ struct FeatureVariations
{
c->cur_record_idx = i;
varRecords[i].collect_feature_substitutes_with_variations (c, this);
+ if (c->universal)
+ break;
}
+ if (c->variation_applied && !c->universal &&
+ !c->record_cond_idx_map->is_empty ())
+ c->insert_catch_all_feature_variation_record = true;
}
FeatureVariations* copy (hb_serialize_context_t *c) const
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
index 8e5be92d12..e10adb78be 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
@@ -143,9 +143,12 @@ struct hb_closure_context_t :
return active_glyphs_stack.tail ();
}
- hb_set_t& push_cur_active_glyphs ()
+ hb_set_t* push_cur_active_glyphs ()
{
- return *active_glyphs_stack.push ();
+ hb_set_t *s = active_glyphs_stack.push ();
+ if (unlikely (active_glyphs_stack.in_error ()))
+ return nullptr;
+ return s;
}
bool pop_cur_done_glyphs ()
@@ -427,6 +430,9 @@ struct hb_ot_apply_context_t :
MATCH_MAYBE
};
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
may_match_t may_match (hb_glyph_info_t &info,
hb_codepoint_t glyph_data) const
{
@@ -446,6 +452,9 @@ struct hb_ot_apply_context_t :
SKIP_MAYBE
};
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
may_skip_t may_skip (const hb_ot_apply_context_t *c,
const hb_glyph_info_t &info) const
{
@@ -516,6 +525,9 @@ struct hb_ot_apply_context_t :
}
#endif
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
void reset (unsigned int start_index_,
unsigned int num_items_)
{
@@ -525,6 +537,9 @@ struct hb_ot_apply_context_t :
matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
void reset_fast (unsigned int start_index_,
unsigned int num_items_)
{
@@ -540,6 +555,9 @@ struct hb_ot_apply_context_t :
}
matcher_t::may_skip_t
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
may_skip (const hb_glyph_info_t &info) const
{ return matcher.may_skip (c, info); }
@@ -549,6 +567,9 @@ struct hb_ot_apply_context_t :
SKIP
};
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
match_t match (hb_glyph_info_t &info)
{
matcher_t::may_skip_t skip = matcher.may_skip (c, info);
@@ -567,6 +588,9 @@ struct hb_ot_apply_context_t :
return SKIP;
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool next (unsigned *unsafe_to = nullptr)
{
assert (num_items > 0);
@@ -600,6 +624,9 @@ struct hb_ot_apply_context_t :
*unsafe_to = end;
return false;
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool prev (unsigned *unsafe_from = nullptr)
{
assert (num_items > 0);
@@ -703,6 +730,7 @@ struct hb_ot_apply_context_t :
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
+ hb_sanitize_context_t sanitizer;
recurse_func_t recurse_func = nullptr;
const GDEF &gdef;
const GDEF::accelerator_t &gdef_accel;
@@ -729,9 +757,11 @@ struct hb_ot_apply_context_t :
hb_ot_apply_context_t (unsigned int table_index_,
hb_font_t *font_,
- hb_buffer_t *buffer_) :
+ hb_buffer_t *buffer_,
+ hb_blob_t *table_blob_) :
table_index (table_index_),
font (font_), face (font->face), buffer (buffer_),
+ sanitizer (table_blob_),
gdef (
#ifndef HB_NO_OT_LAYOUT
*face->table.GDEF->table
@@ -808,6 +838,9 @@ struct hb_ot_apply_context_t :
return true;
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool check_glyph_property (const hb_glyph_info_t *info,
unsigned int match_props) const
{
@@ -1213,14 +1246,17 @@ static inline bool would_match_input (hb_would_apply_context_t *c,
return true;
}
template <typename HBUINT>
-static inline bool match_input (hb_ot_apply_context_t *c,
- unsigned int count, /* Including the first glyph (not matched) */
- const HBUINT input[], /* Array of input values--start with second glyph */
- match_func_t match_func,
- const void *match_data,
- unsigned int *end_position,
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
- unsigned int *p_total_component_count = nullptr)
+#ifndef HB_OPTIMIZE_SIZE
+HB_ALWAYS_INLINE
+#endif
+static bool match_input (hb_ot_apply_context_t *c,
+ unsigned int count, /* Including the first glyph (not matched) */
+ const HBUINT input[], /* Array of input values--start with second glyph */
+ match_func_t match_func,
+ const void *match_data,
+ unsigned int *end_position,
+ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
+ unsigned int *p_total_component_count = nullptr)
{
TRACE_APPLY (nullptr);
@@ -1456,12 +1492,15 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
}
template <typename HBUINT>
-static inline bool match_backtrack (hb_ot_apply_context_t *c,
- unsigned int count,
- const HBUINT backtrack[],
- match_func_t match_func,
- const void *match_data,
- unsigned int *match_start)
+#ifndef HB_OPTIMIZE_SIZE
+HB_ALWAYS_INLINE
+#endif
+static bool match_backtrack (hb_ot_apply_context_t *c,
+ unsigned int count,
+ const HBUINT backtrack[],
+ match_func_t match_func,
+ const void *match_data,
+ unsigned int *match_start)
{
TRACE_APPLY (nullptr);
@@ -1485,13 +1524,16 @@ static inline bool match_backtrack (hb_ot_apply_context_t *c,
}
template <typename HBUINT>
-static inline bool match_lookahead (hb_ot_apply_context_t *c,
- unsigned int count,
- const HBUINT lookahead[],
- match_func_t match_func,
- const void *match_data,
- unsigned int start_index,
- unsigned int *end_index)
+#ifndef HB_OPTIMIZE_SIZE
+HB_ALWAYS_INLINE
+#endif
+static bool match_lookahead (hb_ot_apply_context_t *c,
+ unsigned int count,
+ const HBUINT lookahead[],
+ match_func_t match_func,
+ const void *match_data,
+ unsigned int start_index,
+ unsigned int *end_index)
{
TRACE_APPLY (nullptr);
@@ -1615,10 +1657,13 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
}
covered_seq_indicies.add (seqIndex);
+ hb_set_t *cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs))
+ return;
if (has_pos_glyphs) {
- c->push_cur_active_glyphs () = std::move (pos_glyphs);
+ *cur_active_glyphs = std::move (pos_glyphs);
} else {
- c->push_cur_active_glyphs ().set (*c->glyphs);
+ *cur_active_glyphs = *c->glyphs;
}
unsigned endIndex = inputCount;
@@ -2001,8 +2046,7 @@ struct Rule
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (inputCount.sanitize (c) &&
- lookupCount.sanitize (c) &&
+ return_trace (c->check_struct (this) &&
c->check_range (inputZ.arrayZ,
inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
LookupRecord::static_size * lookupCount));
@@ -2021,6 +2065,7 @@ struct Rule
* design order */
public:
DEFINE_SIZE_ARRAY (4, inputZ);
+ DEFINE_SIZE_MAX (65536 * (Types::HBUINT::static_size + LookupRecord::static_size));
};
template <typename Types>
@@ -2168,8 +2213,9 @@ struct ContextFormat1_4
void closure (hb_closure_context_t *c) const
{
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
- get_coverage ().intersect_set (c->previous_parent_active_glyphs (), cur_active_glyphs);
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
+ get_coverage ().intersect_set (c->previous_parent_active_glyphs (), *cur_active_glyphs);
struct ContextClosureLookupContext lookup_context = {
{intersects_glyph, intersected_glyph},
@@ -2338,9 +2384,10 @@ struct ContextFormat2_5
if (!(this+coverage).intersects (c->glyphs))
return;
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
+ *cur_active_glyphs);
const ClassDef &class_def = this+classDef;
@@ -2583,10 +2630,10 @@ struct ContextFormat3
if (!(this+coverageZ[0]).intersects (c->glyphs))
return;
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
-
+ *cur_active_glyphs);
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
struct ContextClosureLookupContext lookup_context = {
@@ -2687,14 +2734,14 @@ struct ContextFormat3
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!c->check_struct (this)) return_trace (false);
+ if (unlikely (!c->check_struct (this))) return_trace (false);
unsigned int count = glyphCount;
- if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
- if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
+ if (unlikely (!count)) return_trace (false); /* We want to access coverageZ[0] freely. */
+ if (unlikely (!c->check_array (coverageZ.arrayZ, count))) return_trace (false);
for (unsigned int i = 0; i < count; i++)
- if (!coverageZ[i].sanitize (c, this)) return_trace (false);
+ if (unlikely (!coverageZ[i].sanitize (c, this))) return_trace (false);
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
- return_trace (c->check_array (lookupRecord, lookupCount));
+ return_trace (likely (c->check_array (lookupRecord, lookupCount)));
}
protected:
@@ -3014,8 +3061,6 @@ struct ChainRule
const hb_map_t *lookahead_map = nullptr) const
{
TRACE_SERIALIZE (this);
- auto *out = c->start_embed (this);
- if (unlikely (!out)) return_trace (false);
const hb_map_t *mapping = backtrack_map;
serialize_array (c, backtrack.len, + backtrack.iter ()
@@ -3077,13 +3122,14 @@ struct ChainRule
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!backtrack.sanitize (c)) return_trace (false);
+ /* Hyper-optimized sanitized because this is really hot. */
+ if (unlikely (!backtrack.len.sanitize (c))) return_trace (false);
const auto &input = StructAfter<decltype (inputX)> (backtrack);
- if (!input.sanitize (c)) return_trace (false);
+ if (unlikely (!input.lenP1.sanitize (c))) return_trace (false);
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
- if (!lookahead.sanitize (c)) return_trace (false);
+ if (unlikely (!lookahead.len.sanitize (c))) return_trace (false);
const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
- return_trace (lookup.sanitize (c));
+ return_trace (likely (lookup.sanitize (c)));
}
protected:
@@ -3091,7 +3137,7 @@ struct ChainRule
backtrack; /* Array of backtracking values
* (to be matched before the input
* sequence) */
- HeadlessArrayOf<typename Types::HBUINT>
+ HeadlessArray16Of<typename Types::HBUINT>
inputX; /* Array of input values (start with
* second glyph) */
Array16Of<typename Types::HBUINT>
@@ -3102,6 +3148,7 @@ struct ChainRule
* design order) */
public:
DEFINE_SIZE_MIN (8);
+ DEFINE_SIZE_MAX (65536 * (3 * Types::HBUINT::static_size + LookupRecord::static_size));
};
template <typename Types>
@@ -3251,9 +3298,10 @@ struct ChainContextFormat1_4
void closure (hb_closure_context_t *c) const
{
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
+ *cur_active_glyphs);
struct ChainContextClosureLookupContext lookup_context = {
{intersects_glyph, intersected_glyph},
@@ -3423,10 +3471,10 @@ struct ChainContextFormat2_5
if (!(this+coverage).intersects (c->glyphs))
return;
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
-
+ *cur_active_glyphs);
const ClassDef &backtrack_class_def = this+backtrackClassDef;
const ClassDef &input_class_def = this+inputClassDef;
@@ -3727,10 +3775,11 @@ struct ChainContextFormat3
if (!(this+input[0]).intersects (c->glyphs))
return;
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs))
+ return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
-
+ *cur_active_glyphs);
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
@@ -3849,8 +3898,6 @@ struct ChainContextFormat3
{
TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (this);
- if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
if (!serialize_coverage_offsets (c, backtrack.iter (), this))
@@ -3877,14 +3924,14 @@ struct ChainContextFormat3
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!backtrack.sanitize (c, this)) return_trace (false);
+ if (unlikely (!backtrack.sanitize (c, this))) return_trace (false);
const auto &input = StructAfter<decltype (inputX)> (backtrack);
- if (!input.sanitize (c, this)) return_trace (false);
- if (!input.len) return_trace (false); /* To be consistent with Context. */
+ if (unlikely (!input.sanitize (c, this))) return_trace (false);
+ if (unlikely (!input.len)) return_trace (false); /* To be consistent with Context. */
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
- if (!lookahead.sanitize (c, this)) return_trace (false);
+ if (unlikely (!lookahead.sanitize (c, this))) return_trace (false);
const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
- return_trace (lookup.sanitize (c));
+ return_trace (likely (lookup.sanitize (c)));
}
protected:
@@ -3974,7 +4021,7 @@ struct ExtensionFormat1
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
out->extensionLookupType = extensionLookupType;
@@ -4503,7 +4550,10 @@ struct GSUBGPOS
{
accelerator_t (hb_face_t *face)
{
- this->table = hb_sanitize_context_t ().reference_table<T> (face);
+ hb_sanitize_context_t sc;
+ sc.lazy_some_gpos = true;
+ this->table = sc.reference_table<T> (face);
+
if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
{
hb_blob_destroy (this->table.get_blob ());
@@ -4528,6 +4578,8 @@ struct GSUBGPOS
this->table.destroy ();
}
+ hb_blob_t *get_blob () const { return table.get_blob (); }
+
hb_ot_layout_lookup_accelerator_t *get_accel (unsigned lookup_index) const
{
if (unlikely (lookup_index >= lookup_count)) return nullptr;
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc
index c66ee8cfd0..020b8a6c82 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc
@@ -1316,8 +1316,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
hb_set_t feature_indexes;
hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes);
- for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
- hb_set_next (&feature_indexes, &feature_index);)
+ for (auto feature_index : feature_indexes)
g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes);
@@ -1570,7 +1569,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
glyphs_length = glyphs->get_population ();
if (lookups)
{
- for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
+ for (auto lookup_index : *lookups)
gsub.get_lookup (lookup_index).closure (&c, lookup_index);
}
else
@@ -1953,7 +1952,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
{
const unsigned int table_index = proxy.table_index;
unsigned int i = 0;
- OT::hb_ot_apply_context_t c (table_index, font, buffer);
+ OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob ());
c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>);
for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)
@@ -2011,20 +2010,20 @@ void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, h
{
GSUBProxy proxy (font->face);
if (buffer->messaging () &&
- !buffer->message (font, "start table GSUB")) return;
+ !buffer->message (font, "start table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0]))) return;
apply (proxy, plan, font, buffer);
if (buffer->messaging ())
- (void) buffer->message (font, "end table GSUB");
+ (void) buffer->message (font, "end table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0]));
}
void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
{
GPOSProxy proxy (font->face);
if (buffer->messaging () &&
- !buffer->message (font, "start table GPOS")) return;
+ !buffer->message (font, "start table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1]))) return;
apply (proxy, plan, font, buffer);
if (buffer->messaging ())
- (void) buffer->message (font, "end table GPOS");
+ (void) buffer->message (font, "end table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1]));
}
void
@@ -2036,6 +2035,112 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
}
#ifndef HB_NO_BASE
+
+static void
+choose_base_tags (hb_script_t script,
+ hb_language_t language,
+ hb_tag_t *script_tag,
+ hb_tag_t *language_tag)
+{
+ hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+ unsigned script_count = ARRAY_LENGTH (script_tags);
+
+ hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
+ unsigned language_count = ARRAY_LENGTH (language_tags);
+
+ hb_ot_tags_from_script_and_language (script, language,
+ &script_count, script_tags,
+ &language_count, language_tags);
+
+ *script_tag = script_count ? script_tags[script_count - 1] : HB_OT_TAG_DEFAULT_SCRIPT;
+ *language_tag = language_count ? language_tags[language_count - 1] : HB_OT_TAG_DEFAULT_LANGUAGE;
+}
+
+/**
+ * hb_ot_layout_get_font_extents:
+ * @font: a font
+ * @direction: text direction.
+ * @script_tag: script tag.
+ * @language_tag: language tag.
+ * @extents: (out) (nullable): font extents if found.
+ *
+ * Fetches script/language-specific font extents. These values are
+ * looked up in the `BASE` table's `MinMax` records.
+ *
+ * If no such extents are found, the default extents for the font are
+ * fetched. As such, the return value of this function can for the
+ * most part be ignored. Note that the per-script/language extents
+ * do not have a line-gap value, and the line-gap is set to zero in
+ * that case.
+ *
+ * Return value: `true` if found script/language-specific font extents.
+ *
+ * Since: 8.0.0
+ **/
+hb_bool_t
+hb_ot_layout_get_font_extents (hb_font_t *font,
+ hb_direction_t direction,
+ hb_tag_t script_tag,
+ hb_tag_t language_tag,
+ hb_font_extents_t *extents)
+{
+ hb_position_t min, max;
+ if (font->face->table.BASE->get_min_max (font, direction, script_tag, language_tag, HB_TAG_NONE,
+ &min, &max))
+ {
+ if (extents)
+ {
+ extents->ascender = max;
+ extents->descender = min;
+ extents->line_gap = 0;
+ }
+ return true;
+ }
+
+ hb_font_get_extents_for_direction (font, direction, extents);
+ return false;
+}
+
+/**
+ * hb_ot_layout_get_font_extents2:
+ * @font: a font
+ * @direction: text direction.
+ * @script: script.
+ * @language: (nullable): language.
+ * @extents: (out) (nullable): font extents if found.
+ *
+ * Fetches script/language-specific font extents. These values are
+ * looked up in the `BASE` table's `MinMax` records.
+ *
+ * If no such extents are found, the default extents for the font are
+ * fetched. As such, the return value of this function can for the
+ * most part be ignored. Note that the per-script/language extents
+ * do not have a line-gap value, and the line-gap is set to zero in
+ * that case.
+ *
+ * This function is like hb_ot_layout_get_font_extents() but takes
+ * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t.
+ *
+ * Return value: `true` if found script/language-specific font extents.
+ *
+ * Since: 8.0.0
+ **/
+hb_bool_t
+hb_ot_layout_get_font_extents2 (hb_font_t *font,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_font_extents_t *extents)
+{
+ hb_tag_t script_tag, language_tag;
+ choose_base_tags (script, language, &script_tag, &language_tag);
+ return hb_ot_layout_get_font_extents (font,
+ direction,
+ script_tag,
+ language_tag,
+ extents);
+}
+
/**
* hb_ot_layout_get_horizontal_baseline_tag_for_script:
* @script: a script tag.
@@ -2134,6 +2239,42 @@ hb_ot_layout_get_baseline (hb_font_t *font,
}
/**
+ * hb_ot_layout_get_baseline2:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script: script.
+ * @language: (nullable): language, currently unused.
+ * @coord: (out) (nullable): baseline value if found.
+ *
+ * Fetches a baseline value from the face.
+ *
+ * This function is like hb_ot_layout_get_baseline() but takes
+ * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t.
+ *
+ * Return value: `true` if found baseline value in the font.
+ *
+ * Since: 8.0.0
+ **/
+hb_bool_t
+hb_ot_layout_get_baseline2 (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_position_t *coord /* OUT. May be NULL. */)
+{
+ hb_tag_t script_tag, language_tag;
+ choose_base_tags (script, language, &script_tag, &language_tag);
+ return hb_ot_layout_get_baseline (font,
+ baseline_tag,
+ direction,
+ script_tag,
+ language_tag,
+ coord);
+}
+
+/**
* hb_ot_layout_get_baseline_with_fallback:
* @font: a font
* @baseline_tag: a baseline tag
@@ -2355,6 +2496,41 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
}
}
+/**
+ * hb_ot_layout_get_baseline_with_fallback2:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script: script.
+ * @language: (nullable): language, currently unused.
+ * @coord: (out): baseline value if found.
+ *
+ * Fetches a baseline value from the face, and synthesizes
+ * it if the font does not have it.
+ *
+ * This function is like hb_ot_layout_get_baseline_with_fallback() but takes
+ * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t.
+ *
+ * Since: 8.0.0
+ **/
+void
+hb_ot_layout_get_baseline_with_fallback2 (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_position_t *coord /* OUT */)
+{
+ hb_tag_t script_tag, language_tag;
+ choose_base_tags (script, language, &script_tag, &language_tag);
+ hb_ot_layout_get_baseline_with_fallback (font,
+ baseline_tag,
+ direction,
+ script_tag,
+ language_tag,
+ coord);
+}
+
#endif
@@ -2451,9 +2627,10 @@ hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
hb_codepoint_t glyph)
{
const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index);
+ hb_blob_t *blob = font->face->table.GPOS->get_blob ();
hb_glyph_position_t pos = {0};
hb_position_single_dispatch_t c;
- lookup.dispatch (&c, font, direction, glyph, pos);
+ lookup.dispatch (&c, font, blob, direction, glyph, pos);
hb_position_t ret = 0;
switch (direction)
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.h b/thirdparty/harfbuzz/src/hb-ot-layout.h
index 10dcc65ac0..b0fae3707f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.h
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.h
@@ -447,6 +447,20 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
* BASE
*/
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_font_extents (hb_font_t *font,
+ hb_direction_t direction,
+ hb_tag_t script_tag,
+ hb_tag_t language_tag,
+ hb_font_extents_t *extents);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_font_extents2 (hb_font_t *font,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_font_extents_t *extents);
+
/**
* hb_ot_layout_baseline_tag_t:
* @HB_OT_LAYOUT_BASELINE_TAG_ROMAN: The baseline used by alphabetic scripts such as Latin, Cyrillic and Greek.
@@ -499,6 +513,14 @@ hb_ot_layout_get_baseline (hb_font_t *font,
hb_tag_t language_tag,
hb_position_t *coord /* OUT. May be NULL. */);
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_baseline2 (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_position_t *coord /* OUT. May be NULL. */);
+
HB_EXTERN void
hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
hb_ot_layout_baseline_tag_t baseline_tag,
@@ -507,6 +529,14 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
hb_tag_t language_tag,
hb_position_t *coord /* OUT */);
+HB_EXTERN void
+hb_ot_layout_get_baseline_with_fallback2 (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_position_t *coord /* OUT */);
+
HB_END_DECLS
#endif /* HB_OT_LAYOUT_H */
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.hh b/thirdparty/harfbuzz/src/hb-ot-layout.hh
index 9505d5f147..d71889331d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.hh
@@ -448,7 +448,7 @@ _hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
static inline bool
_hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
{
- return !!(info->lig_props() & IS_LIG_BASE);
+ return info->lig_props() & IS_LIG_BASE;
}
static inline unsigned int
@@ -496,37 +496,37 @@ _hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
static inline bool
_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
}
static inline bool
_hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
}
static inline bool
_hb_glyph_info_is_mark (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK;
}
static inline bool
_hb_glyph_info_substituted (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
}
static inline bool
_hb_glyph_info_ligated (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
}
static inline bool
_hb_glyph_info_multiplied (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
}
static inline bool
diff --git a/thirdparty/harfbuzz/src/hb-ot-map.cc b/thirdparty/harfbuzz/src/hb-ot-map.cc
index 8882dbaccb..bacd56ef3f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-map.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-map.cc
@@ -213,7 +213,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
/* Sort features and merge duplicates */
if (feature_infos.length)
{
- feature_infos.qsort ();
+ if (!is_simple)
+ feature_infos.qsort ();
auto *f = feature_infos.arrayZ;
unsigned int j = 0;
unsigned count = feature_infos.length;
@@ -314,7 +315,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
map->needs_fallback = !found;
}
//feature_infos.shrink (0); /* Done with these */
-
+ if (is_simple)
+ m.features.qsort ();
add_gsub_pause (nullptr);
add_gpos_pause (nullptr);
@@ -350,7 +352,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
}
/* Sort lookups and merge duplicates */
- if (last_num_lookups < lookups.length)
+ if (last_num_lookups + 1 < lookups.length)
{
lookups.as_array ().sub_array (last_num_lookups, lookups.length - last_num_lookups).qsort ();
diff --git a/thirdparty/harfbuzz/src/hb-ot-map.hh b/thirdparty/harfbuzz/src/hb-ot-map.hh
index efc8cae96a..8af8129ceb 100644
--- a/thirdparty/harfbuzz/src/hb-ot-map.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-map.hh
@@ -60,6 +60,13 @@ struct hb_ot_map_t
int cmp (const hb_tag_t tag_) const
{ return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; }
+
+ HB_INTERNAL static int cmp (const void *pa, const void *pb)
+ {
+ const feature_map_t *a = (const feature_map_t *) pa;
+ const feature_map_t *b = (const feature_map_t *) pb;
+ return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0;
+ }
};
struct lookup_map_t {
@@ -273,6 +280,7 @@ struct hb_ot_map_builder_t
hb_face_t *face;
hb_segment_properties_t props;
+ bool is_simple;
hb_tag_t chosen_script[2];
bool found_script[2];
diff --git a/thirdparty/harfbuzz/src/hb-ot-math-table.hh b/thirdparty/harfbuzz/src/hb-ot-math-table.hh
index dccf720f46..b11da464b2 100644
--- a/thirdparty/harfbuzz/src/hb-ot-math-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-math-table.hh
@@ -73,7 +73,6 @@ struct MathConstants
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
- if (unlikely (!out)) return_trace (nullptr);
HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
if (unlikely (!p)) return_trace (nullptr);
@@ -310,7 +309,6 @@ struct MathKern
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
- if (unlikely (!out)) return_trace (nullptr);
if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
@@ -572,6 +570,7 @@ struct MathGlyphInfo
auto it =
+ hb_iter (this+extendedShapeCoverage)
+ | hb_take (c->plan->source->get_num_glyphs ())
| hb_filter (glyphset)
| hb_map_retains_sorting (glyph_map)
;
@@ -757,8 +756,6 @@ struct MathGlyphAssembly
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
@@ -945,13 +942,13 @@ struct MathVariants
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
-
+
hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
hb_set_t indices;
collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
-
+
if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
@@ -963,10 +960,10 @@ struct MathVariants
if (!o) return_trace (false);
o->serialize_subset (c, glyphConstruction[i], this);
}
-
+
if (new_vert_coverage)
out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
-
+
if (new_hori_coverage)
out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
return_trace (true);
diff --git a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
index 97d18b9d75..72cb662473 100644
--- a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
@@ -249,7 +249,7 @@ struct OS2
if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t')) &&
!c->plan->pinned_at_default)
{
- float weight_class = c->plan->user_axes_location.get (HB_TAG ('w','g','h','t'));
+ float weight_class = c->plan->user_axes_location.get (HB_TAG ('w','g','h','t')).middle;
if (!c->serializer->check_assign (os2_prime->usWeightClass,
roundf (hb_clamp (weight_class, 1.0f, 1000.0f)),
HB_SERIALIZE_ERROR_INT_OVERFLOW))
@@ -259,7 +259,7 @@ struct OS2
if (c->plan->user_axes_location.has (HB_TAG ('w','d','t','h')) &&
!c->plan->pinned_at_default)
{
- float width = c->plan->user_axes_location.get (HB_TAG ('w','d','t','h'));
+ float width = c->plan->user_axes_location.get (HB_TAG ('w','d','t','h')).middle;
if (!c->serializer->check_assign (os2_prime->usWidthClass,
roundf (map_wdth_to_widthclass (width)),
HB_SERIALIZE_ERROR_INT_OVERFLOW))
@@ -287,8 +287,7 @@ struct OS2
/* This block doesn't show up in profiles. If it ever did,
* we can rewrite it to iterate over OS/2 ranges and use
* set iteration to check if the range matches. */
- for (hb_codepoint_t cp = HB_SET_VALUE_INVALID;
- codepoints->next (&cp);)
+ for (auto cp : *codepoints)
{
unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp);
if (bit < 128)
diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
index 951e6395d6..d44233610a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
@@ -79,6 +79,11 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
post::accelerator_t _post (c->plan->source);
hb_hashmap_t<hb_bytes_t, uint32_t, true> glyph_name_to_new_index;
+
+ old_new_index_map.alloc (num_glyphs);
+ old_gid_new_index_map.alloc (num_glyphs);
+ glyph_name_to_new_index.alloc (num_glyphs);
+
for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
{
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
@@ -86,11 +91,12 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
unsigned new_index;
const uint32_t *new_index2;
- if (old_index <= 257) new_index = old_index;
+ if (old_index <= 257)
+ new_index = old_index;
else if (old_new_index_map.has (old_index, &new_index2))
- {
new_index = *new_index2;
- } else {
+ else
+ {
hb_bytes_t s = _post.find_glyph_name (old_gid);
new_index = glyph_name_to_new_index.get (s);
if (new_index == (unsigned)-1)
diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table.hh b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
index 042fa611ad..761e49d119 100644
--- a/thirdparty/harfbuzz/src/hb-ot-post-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
@@ -96,8 +96,7 @@ struct post
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- post *post_prime = c->serializer->start_embed<post> ();
- if (unlikely (!post_prime)) return_trace (false);
+ auto *post_prime = c->serializer->start_embed<post> ();
bool glyph_names = c->plan->flags & HB_SUBSET_FLAGS_GLYPH_NAMES;
if (!serialize (c->serializer, glyph_names))
@@ -117,7 +116,7 @@ struct post
if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t')) &&
!c->plan->pinned_at_default)
{
- float italic_angle = c->plan->user_axes_location.get (HB_TAG ('s','l','n','t'));
+ float italic_angle = c->plan->user_axes_location.get (HB_TAG ('s','l','n','t')).middle;
italic_angle = hb_max (-90.f, hb_min (italic_angle, 90.f));
post_prime->italicAngle.set_float (italic_angle);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc
index 3d207e0681..d84313f190 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc
@@ -313,6 +313,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
{
hb_ot_map_builder_t *map = &planner->map;
+ map->is_simple = true;
+
map->enable_feature (HB_TAG('r','v','r','n'));
map->add_gsub_pause (nullptr);
@@ -354,7 +356,10 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
map->enable_feature (HB_TAG ('H','A','R','F')); /* Considered discretionary. */
if (planner->shaper->collect_features)
+ {
+ map->is_simple = false;
planner->shaper->collect_features (planner);
+ }
map->enable_feature (HB_TAG ('B','u','z','z')); /* Considered required. */
map->enable_feature (HB_TAG ('B','U','Z','Z')); /* Considered discretionary. */
@@ -378,6 +383,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
map->enable_feature (HB_TAG ('v','e','r','t'), F_GLOBAL_SEARCH);
}
+ if (num_user_features)
+ map->is_simple = false;
for (unsigned int i = 0; i < num_user_features; i++)
{
const hb_feature_t *feature = &user_features[i];
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh
index e7a69008b7..66a8bfbd28 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh
@@ -368,7 +368,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
- OT::hb_ot_apply_context_t c (0, font, buffer);
+ OT::hb_ot_apply_context_t c (0, font, buffer, hb_blob_get_empty ());
for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
if (fallback_plan->lookup_array[i]) {
c.set_lookup_mask (fallback_plan->mask_array[i]);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
index 353e32d32c..7dd47755af 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh
@@ -53,7 +53,7 @@ enum indic_syllable_type_t {
};
-#line 57 "hb-ot-shaper-indic-machine.hh"
+#line 54 "hb-ot-shaper-indic-machine.hh"
#define indic_syllable_machine_ex_A 9u
#define indic_syllable_machine_ex_C 1u
#define indic_syllable_machine_ex_CM 16u
@@ -76,7 +76,7 @@ enum indic_syllable_type_t {
#define indic_syllable_machine_ex_ZWNJ 5u
-#line 80 "hb-ot-shaper-indic-machine.hh"
+#line 75 "hb-ot-shaper-indic-machine.hh"
static const unsigned char _indic_syllable_machine_trans_keys[] = {
8u, 8u, 4u, 13u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
@@ -460,7 +460,7 @@ find_syllables_indic (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 464 "hb-ot-shaper-indic-machine.hh"
+#line 453 "hb-ot-shaper-indic-machine.hh"
{
cs = indic_syllable_machine_start;
ts = 0;
@@ -476,7 +476,7 @@ find_syllables_indic (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 480 "hb-ot-shaper-indic-machine.hh"
+#line 465 "hb-ot-shaper-indic-machine.hh"
{
int _slen;
int _trans;
@@ -490,7 +490,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 494 "hb-ot-shaper-indic-machine.hh"
+#line 477 "hb-ot-shaper-indic-machine.hh"
}
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -593,7 +593,7 @@ _eof_trans:
#line 114 "hb-ot-shaper-indic-machine.rl"
{act = 6;}
break;
-#line 597 "hb-ot-shaper-indic-machine.hh"
+#line 559 "hb-ot-shaper-indic-machine.hh"
}
_again:
@@ -602,7 +602,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 606 "hb-ot-shaper-indic-machine.hh"
+#line 566 "hb-ot-shaper-indic-machine.hh"
}
if ( ++p != pe )
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc
index 89226ae4a1..97f62035c6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc
@@ -40,6 +40,14 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
return false;
if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE)))
+ {
+ if (buffer->messaging ())
+ (void) buffer->message (font, "skipped inserting dotted-circles because there is no broken syllables");
+ return false;
+ }
+
+ if (buffer->messaging () &&
+ !buffer->message (font, "start inserting dotted-circles"))
return false;
hb_codepoint_t dottedcircle_glyph;
@@ -84,6 +92,10 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
(void) buffer->next_glyph ();
}
buffer->sync ();
+
+ if (buffer->messaging ())
+ (void) buffer->message (font, "end inserting dotted-circles");
+
return true;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc
index 342aba1235..c35765af95 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc
@@ -377,6 +377,9 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
#define POST_BASE_FLAGS64 (FLAG64 (USE(FAbv)) | \
FLAG64 (USE(FBlw)) | \
FLAG64 (USE(FPst)) | \
+ FLAG64 (USE(FMAbv)) | \
+ FLAG64 (USE(FMBlw)) | \
+ FLAG64 (USE(FMPst)) | \
FLAG64 (USE(MAbv)) | \
FLAG64 (USE(MBlw)) | \
FLAG64 (USE(MPst)) | \
diff --git a/thirdparty/harfbuzz/src/hb-ot-stat-table.hh b/thirdparty/harfbuzz/src/hb-ot-stat-table.hh
index de553dd72f..f7bb3791ca 100644
--- a/thirdparty/harfbuzz/src/hb-ot-stat-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-stat-table.hh
@@ -57,6 +57,16 @@ enum
// Reserved = 0xFFFC /* Reserved for future use — set to zero. */
};
+static bool axis_value_is_outside_axis_range (hb_tag_t axis_tag, float axis_value,
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location)
+{
+ if (!user_axes_location->has (axis_tag))
+ return false;
+
+ Triple axis_range = user_axes_location->get (axis_tag);
+ return (axis_value < axis_range.minimum || axis_value > axis_range.maximum);
+}
+
struct StatAxisRecord
{
int cmp (hb_tag_t key) const { return tag.cmp (key); }
@@ -96,23 +106,19 @@ struct AxisValueFormat1
}
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
hb_tag_t axis_tag = get_axis_tag (axis_records);
float axis_value = get_value ();
- if (!user_axes_location->has (axis_tag) ||
- fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
- return true;
-
- return false;
+ return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
}
bool subset (hb_subset_context_t *c,
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- const hb_hashmap_t<hb_tag_t, float>* user_axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
if (keep_axis_value (axis_records, user_axes_location))
return_trace (c->serializer->embed (this));
@@ -155,23 +161,19 @@ struct AxisValueFormat2
}
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
hb_tag_t axis_tag = get_axis_tag (axis_records);
float axis_value = get_value ();
- if (!user_axes_location->has (axis_tag) ||
- fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
- return true;
-
- return false;
+ return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
}
bool subset (hb_subset_context_t *c,
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- const hb_hashmap_t<hb_tag_t, float>* user_axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
if (keep_axis_value (axis_records, user_axes_location))
return_trace (c->serializer->embed (this));
@@ -218,23 +220,19 @@ struct AxisValueFormat3
}
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
hb_tag_t axis_tag = get_axis_tag (axis_records);
float axis_value = get_value ();
- if (!user_axes_location->has (axis_tag) ||
- fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
- return true;
-
- return false;
+ return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
}
bool subset (hb_subset_context_t *c,
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- const hb_hashmap_t<hb_tag_t, float>* user_axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
if (keep_axis_value (axis_records, user_axes_location))
return_trace (c->serializer->embed (this));
@@ -291,7 +289,7 @@ struct AxisValueFormat4
{ return axisValues.as_array (axisCount)[axis_index]; }
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
@@ -301,8 +299,7 @@ struct AxisValueFormat4
float axis_value = rec.get_value ();
hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
- if (user_axes_location->has (axis_tag) &&
- fabsf(axis_value - user_axes_location->get (axis_tag)) > 0.001f)
+ if (axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location))
return false;
}
@@ -313,7 +310,7 @@ struct AxisValueFormat4
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location = &c->plan->user_axes_location;
if (!keep_axis_value (axis_records, user_axes_location))
return_trace (false);
@@ -402,7 +399,7 @@ struct AxisValue
}
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
switch (u.format)
{
@@ -451,8 +448,6 @@ struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (this);
- if (unlikely (!out)) return_trace (false);
auto axisValueOffsets = as_array (axisValueCount);
count = 0;
@@ -517,7 +512,7 @@ struct STAT
return axis_value.get_value_name_id ();
}
- void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+ void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location,
hb_set_t *nameids_to_retain /* OUT */) const
{
if (!has_data ()) return;
diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc
index 547f9573d0..53b6b38f66 100644
--- a/thirdparty/harfbuzz/src/hb-ot-tag.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc
@@ -412,7 +412,7 @@ parse_private_use_subtag (const char *private_use_subtag,
/**
* hb_ot_tags_from_script_and_language:
* @script: an #hb_script_t to convert.
- * @language: an #hb_language_t to convert.
+ * @language: (nullable): an #hb_language_t to convert.
* @script_count: (inout) (optional): maximum number of script tags to retrieve (IN)
* and actual number of script tags retrieved (OUT)
* @script_tags: (out) (optional): array of size at least @script_count to store the
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-common.hh b/thirdparty/harfbuzz/src/hb-ot-var-common.hh
index 7d4bf2241c..44ec64bc03 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-common.hh
@@ -36,19 +36,14 @@ struct DeltaSetIndexMapFormat01
{
friend struct DeltaSetIndexMap;
+ unsigned get_size () const
+ { return min_size + mapCount * get_width (); }
+
private:
DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
- auto *out = c->start_embed (this);
- if (unlikely (!out)) return_trace (nullptr);
-
- unsigned total_size = min_size + mapCount * get_width ();
- HBUINT8 *p = c->allocate_size<HBUINT8> (total_size);
- if (unlikely (!p)) return_trace (nullptr);
-
- hb_memcpy (p, this, HBUINT8::static_size * total_size);
- return_trace (out);
+ return_trace (c->embed (this));
}
template <typename T>
@@ -65,7 +60,7 @@ struct DeltaSetIndexMapFormat01
entryFormat = ((width-1)<<4)|(inner_bit_count-1);
mapCount = output_map.length;
- HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length);
+ HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length, false);
if (unlikely (!p)) return_trace (false);
for (unsigned int i = 0; i < output_map.length; i++)
{
@@ -242,6 +237,7 @@ struct VarStoreInstancer
/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
struct TupleVariationHeader
{
+ friend struct tuple_delta_t;
unsigned get_size (unsigned axis_count) const
{ return min_size + get_all_tuples (axis_count).get_size (); }
@@ -250,14 +246,67 @@ struct TupleVariationHeader
const TupleVariationHeader &get_next (unsigned axis_count) const
{ return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
+ bool unpack_axis_tuples (unsigned axis_count,
+ const hb_array_t<const F2DOT14> shared_tuples,
+ const hb_map_t *axes_old_index_tag_map,
+ hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const
+ {
+ const F2DOT14 *peak_tuple = nullptr;
+ if (has_peak ())
+ peak_tuple = get_peak_tuple (axis_count).arrayZ;
+ else
+ {
+ unsigned int index = get_index ();
+ if (unlikely ((index + 1) * axis_count > shared_tuples.length))
+ return false;
+ peak_tuple = shared_tuples.sub_array (axis_count * index, axis_count).arrayZ;
+ }
+
+ const F2DOT14 *start_tuple = nullptr;
+ const F2DOT14 *end_tuple = nullptr;
+ bool has_interm = has_intermediate ();
+
+ if (has_interm)
+ {
+ start_tuple = get_start_tuple (axis_count).arrayZ;
+ end_tuple = get_end_tuple (axis_count).arrayZ;
+ }
+
+ for (unsigned i = 0; i < axis_count; i++)
+ {
+ float peak = peak_tuple[i].to_float ();
+ if (peak == 0.f) continue;
+
+ hb_tag_t *axis_tag;
+ if (!axes_old_index_tag_map->has (i, &axis_tag))
+ return false;
+
+ float start, end;
+ if (has_interm)
+ {
+ start = start_tuple[i].to_float ();
+ end = end_tuple[i].to_float ();
+ }
+ else
+ {
+ start = hb_min (peak, 0.f);
+ end = hb_max (peak, 0.f);
+ }
+ axis_tuples.set (*axis_tag, Triple (start, peak, end));
+ }
+
+ return true;
+ }
+
float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
const hb_array_t<const F2DOT14> shared_tuples,
- const hb_vector_t<int> *shared_tuple_active_idx = nullptr) const
+ const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
{
const F2DOT14 *peak_tuple;
unsigned start_idx = 0;
unsigned end_idx = coord_count;
+ unsigned step = 1;
if (has_peak ())
peak_tuple = get_peak_tuple (coord_count).arrayZ;
@@ -272,10 +321,16 @@ struct TupleVariationHeader
{
if (unlikely (index >= shared_tuple_active_idx->length))
return 0.f;
- int v = (*shared_tuple_active_idx).arrayZ[index];
- if (v != -1)
+ auto _ = (*shared_tuple_active_idx).arrayZ[index];
+ if (_.second != -1)
+ {
+ start_idx = _.first;
+ end_idx = _.second + 1;
+ step = _.second - _.first;
+ }
+ else if (_.first != -1)
{
- start_idx = v;
+ start_idx = _.first;
end_idx = start_idx + 1;
}
}
@@ -291,7 +346,7 @@ struct TupleVariationHeader
}
float scalar = 1.f;
- for (unsigned int i = start_idx; i < end_idx; i++)
+ for (unsigned int i = start_idx; i < end_idx; i += step)
{
int peak = peak_tuple[i].to_int ();
if (!peak) continue;
@@ -333,6 +388,7 @@ struct TupleVariationHeader
TupleIndexMask = 0x0FFFu
};
+ TuppleIndex& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
DEFINE_SIZE_STATIC (2);
};
@@ -365,6 +421,468 @@ struct TupleVariationHeader
DEFINE_SIZE_MIN (4);
};
+/* not using hb_bytes_t: avoid potential build issues with some compilers */
+struct byte_data_t
+{
+ hb_bytes_t bytes;
+
+ byte_data_t () = default;
+ byte_data_t (const char *p_, unsigned len_) : bytes (hb_bytes_t (p_, len_)) {}
+
+ void fini () { bytes.fini (); }
+
+ bool operator == (const byte_data_t& o) const
+ { return bytes.arrayZ == o.bytes.arrayZ && bytes.length == o.bytes.length; }
+
+ explicit operator bool () const { return bytes.length; }
+
+ void copy (hb_serialize_context_t *c) const
+ { c->embed (bytes.arrayZ, bytes.length); }
+};
+
+enum packed_delta_flag_t
+{
+ DELTAS_ARE_ZERO = 0x80,
+ DELTAS_ARE_WORDS = 0x40,
+ DELTA_RUN_COUNT_MASK = 0x3F
+};
+
+struct tuple_delta_t
+{
+ public:
+ hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
+
+ /* indices_length = point_count, indice[i] = 1 means point i is referenced */
+ hb_vector_t<bool> indices;
+
+ hb_vector_t<float> deltas_x;
+ /* empty for cvar tuples */
+ hb_vector_t<float> deltas_y;
+
+ /* compiled data: header and deltas
+ * compiled point data is saved in a hashmap within tuple_variations_t cause
+ * some point sets might be reused by different tuple variations */
+ hb_vector_t<char> compiled_tuple_header;
+ hb_vector_t<char> compiled_deltas;
+
+ tuple_delta_t () = default;
+ tuple_delta_t (const tuple_delta_t& o) = default;
+
+ tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t ()
+ {
+ axis_tuples = std::move (o.axis_tuples);
+ indices = std::move (o.indices);
+ deltas_x = std::move (o.deltas_x);
+ deltas_y = std::move (o.deltas_y);
+ }
+
+ tuple_delta_t& operator = (tuple_delta_t&& o)
+ {
+ hb_swap (*this, o);
+ return *this;
+ }
+
+ void remove_axis (hb_tag_t axis_tag)
+ { axis_tuples.del (axis_tag); }
+
+ bool set_tent (hb_tag_t axis_tag, Triple tent)
+ { return axis_tuples.set (axis_tag, tent); }
+
+ tuple_delta_t& operator += (const tuple_delta_t& o)
+ {
+ unsigned num = indices.length;
+ for (unsigned i = 0; i < num; i++)
+ {
+ if (indices.arrayZ[i])
+ {
+ if (o.indices.arrayZ[i])
+ {
+ deltas_x[i] += o.deltas_x[i];
+ if (deltas_y && o.deltas_y)
+ deltas_y[i] += o.deltas_y[i];
+ }
+ }
+ else
+ {
+ if (!o.indices.arrayZ[i]) continue;
+ deltas_x[i] = o.deltas_x[i];
+ if (deltas_y && o.deltas_y)
+ deltas_y[i] = o.deltas_y[i];
+ }
+ }
+ return *this;
+ }
+
+ tuple_delta_t& operator *= (float scalar)
+ {
+ if (scalar == 1.0f)
+ return *this;
+
+ unsigned num = indices.length;
+ for (unsigned i = 0; i < num; i++)
+ {
+ if (!indices.arrayZ[i]) continue;
+
+ deltas_x[i] *= scalar;
+ if (deltas_y)
+ deltas_y[i] *= scalar;
+ }
+ return *this;
+ }
+
+ hb_vector_t<tuple_delta_t> change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit) const
+ {
+ hb_vector_t<tuple_delta_t> out;
+ Triple *tent;
+ if (!axis_tuples.has (axis_tag, &tent))
+ {
+ out.push (*this);
+ return out;
+ }
+
+ if ((tent->minimum < 0.f && tent->maximum > 0.f) ||
+ !(tent->minimum <= tent->middle && tent->middle <= tent->maximum))
+ return out;
+
+ if (tent->middle == 0.f)
+ {
+ out.push (*this);
+ return out;
+ }
+
+ result_t solutions = rebase_tent (*tent, axis_limit);
+ for (auto t : solutions)
+ {
+ tuple_delta_t new_var = *this;
+ if (t.second == Triple ())
+ new_var.remove_axis (axis_tag);
+ else
+ new_var.set_tent (axis_tag, t.second);
+
+ new_var *= t.first;
+ out.push (std::move (new_var));
+ }
+
+ return out;
+ }
+
+ /* deltas should be compiled already before we compile tuple
+ * variation header cause we need to fill in the size of the
+ * serialized data for this tuple variation */
+ //TODO(qxliu):add option to use sharedTuples in gvar
+ bool compile_tuple_var_header (const hb_map_t& axes_index_map,
+ unsigned points_data_length,
+ const hb_map_t& axes_old_index_tag_map)
+ {
+ if (!compiled_deltas) return false;
+
+ unsigned cur_axis_count = axes_index_map.get_population ();
+ /* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */
+ unsigned alloc_len = 3 * cur_axis_count * (F2DOT14::static_size) + 4;
+ if (unlikely (!compiled_tuple_header.resize (alloc_len))) return false;
+
+ unsigned flag = 0;
+ /* skip the first 4 header bytes: variationDataSize+tupleIndex */
+ F2DOT14* p = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.begin () + 4);
+ F2DOT14* end = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.end ());
+ hb_array_t<F2DOT14> coords (p, end - p);
+
+ /* encode peak coords */
+ unsigned peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map);
+ if (!peak_count) return false;
+
+ /* encode interim coords, it's optional so returned num could be 0 */
+ unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag, axes_index_map, axes_old_index_tag_map);
+
+ //TODO(qxliu): add option to use shared_points in gvar
+ flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers;
+
+ unsigned serialized_data_size = points_data_length + compiled_deltas.length;
+ TupleVariationHeader *o = reinterpret_cast<TupleVariationHeader *> (compiled_tuple_header.begin ());
+ o->varDataSize = serialized_data_size;
+ o->tupleIndex = flag;
+
+ unsigned total_header_len = 4 + (peak_count + interim_count) * (F2DOT14::static_size);
+ return compiled_tuple_header.resize (total_header_len);
+ }
+
+ unsigned encode_peak_coords (hb_array_t<F2DOT14> peak_coords,
+ unsigned& flag,
+ const hb_map_t& axes_index_map,
+ const hb_map_t& axes_old_index_tag_map) const
+ {
+ unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
+ auto it = peak_coords.iter ();
+ unsigned count = 0;
+ for (unsigned i = 0; i < orig_axis_count; i++)
+ {
+ if (!axes_index_map.has (i)) /* axis pinned */
+ continue;
+ hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
+ Triple *coords;
+ if (!axis_tuples.has (axis_tag, &coords))
+ (*it).set_int (0);
+ else
+ (*it).set_float (coords->middle);
+ it++;
+ count++;
+ }
+ flag |= TupleVariationHeader::TuppleIndex::EmbeddedPeakTuple;
+ return count;
+ }
+
+ /* if no need to encode intermediate coords, then just return p */
+ unsigned encode_interm_coords (hb_array_t<F2DOT14> coords,
+ unsigned& flag,
+ const hb_map_t& axes_index_map,
+ const hb_map_t& axes_old_index_tag_map) const
+ {
+ unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
+ unsigned cur_axis_count = axes_index_map.get_population ();
+
+ auto start_coords_iter = coords.sub_array (0, cur_axis_count).iter ();
+ auto end_coords_iter = coords.sub_array (cur_axis_count).iter ();
+ bool encode_needed = false;
+ unsigned count = 0;
+ for (unsigned i = 0; i < orig_axis_count; i++)
+ {
+ if (!axes_index_map.has (i)) /* axis pinned */
+ continue;
+ hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
+ Triple *coords;
+ float min_val = 0.f, val = 0.f, max_val = 0.f;
+ if (axis_tuples.has (axis_tag, &coords))
+ {
+ min_val = coords->minimum;
+ val = coords->middle;
+ max_val = coords->maximum;
+ }
+
+ (*start_coords_iter).set_float (min_val);
+ (*end_coords_iter).set_float (max_val);
+
+ start_coords_iter++;
+ end_coords_iter++;
+ count += 2;
+ if (min_val != hb_min (val, 0.f) || max_val != hb_max (val, 0.f))
+ encode_needed = true;
+ }
+
+ if (encode_needed)
+ {
+ flag |= TupleVariationHeader::TuppleIndex::IntermediateRegion;
+ return count;
+ }
+ return 0;
+ }
+
+ bool compile_deltas ()
+ {
+ hb_vector_t<int> rounded_deltas;
+ if (unlikely (!rounded_deltas.alloc (indices.length)))
+ return false;
+
+ for (unsigned i = 0; i < indices.length; i++)
+ {
+ if (!indices[i]) continue;
+ int rounded_delta = (int) roundf (deltas_x[i]);
+ rounded_deltas.push (rounded_delta);
+ }
+
+ if (!rounded_deltas) return false;
+ /* allocate enough memories 3 * num_deltas */
+ unsigned alloc_len = 3 * rounded_deltas.length;
+ if (deltas_y)
+ alloc_len *= 2;
+
+ if (unlikely (!compiled_deltas.resize (alloc_len))) return false;
+
+ unsigned i = 0;
+ unsigned encoded_len = encode_delta_run (i, compiled_deltas.as_array (), rounded_deltas);
+
+ if (deltas_y)
+ {
+ /* reuse the rounded_deltas vector, check that deltas_y have the same num of deltas as deltas_x */
+ unsigned j = 0;
+ for (unsigned idx = 0; idx < indices.length; idx++)
+ {
+ if (!indices[idx]) continue;
+ int rounded_delta = (int) roundf (deltas_y[idx]);
+
+ if (j >= rounded_deltas.length) return false;
+
+ rounded_deltas[j++] = rounded_delta;
+ }
+
+ if (j != rounded_deltas.length) return false;
+ encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
+ }
+ return compiled_deltas.resize (encoded_len);
+ }
+
+ unsigned encode_delta_run (unsigned& i,
+ hb_array_t<char> encoded_bytes,
+ const hb_vector_t<int>& deltas) const
+ {
+ unsigned num_deltas = deltas.length;
+ unsigned encoded_len = 0;
+ while (i < num_deltas)
+ {
+ int val = deltas[i];
+ if (val == 0)
+ encoded_len += encode_delta_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), deltas);
+ else if (val >= -128 && val <= 127)
+ encoded_len += encode_delta_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), deltas);
+ else
+ encoded_len += encode_delta_run_as_words (i, encoded_bytes.sub_array (encoded_len), deltas);
+ }
+ return encoded_len;
+ }
+
+ unsigned encode_delta_run_as_zeroes (unsigned& i,
+ hb_array_t<char> encoded_bytes,
+ const hb_vector_t<int>& deltas) const
+ {
+ unsigned num_deltas = deltas.length;
+ unsigned run_length = 0;
+ auto it = encoded_bytes.iter ();
+ unsigned encoded_len = 0;
+ while (i < num_deltas && deltas[i] == 0)
+ {
+ i++;
+ run_length++;
+ }
+
+ while (run_length >= 64)
+ {
+ *it++ = (DELTAS_ARE_ZERO | 63);
+ run_length -= 64;
+ encoded_len++;
+ }
+
+ if (run_length)
+ {
+ *it++ = (DELTAS_ARE_ZERO | (run_length - 1));
+ encoded_len++;
+ }
+ return encoded_len;
+ }
+
+ unsigned encode_delta_run_as_bytes (unsigned &i,
+ hb_array_t<char> encoded_bytes,
+ const hb_vector_t<int>& deltas) const
+ {
+ unsigned start = i;
+ unsigned num_deltas = deltas.length;
+ while (i < num_deltas)
+ {
+ int val = deltas[i];
+ if (val > 127 || val < -128)
+ break;
+
+ /* from fonttools: if there're 2 or more zeros in a sequence,
+ * it is better to start a new run to save bytes. */
+ if (val == 0 && i + 1 < num_deltas && deltas[i+1] == 0)
+ break;
+
+ i++;
+ }
+ unsigned run_length = i - start;
+
+ unsigned encoded_len = 0;
+ auto it = encoded_bytes.iter ();
+
+ while (run_length >= 64)
+ {
+ *it++ = 63;
+ encoded_len++;
+
+ for (unsigned j = 0; j < 64; j++)
+ {
+ *it++ = static_cast<char> (deltas[start + j]);
+ encoded_len++;
+ }
+
+ start += 64;
+ run_length -= 64;
+ }
+
+ if (run_length)
+ {
+ *it++ = run_length - 1;
+ encoded_len++;
+
+ while (start < i)
+ {
+ *it++ = static_cast<char> (deltas[start++]);
+ encoded_len++;
+ }
+ }
+
+ return encoded_len;
+ }
+
+ unsigned encode_delta_run_as_words (unsigned &i,
+ hb_array_t<char> encoded_bytes,
+ const hb_vector_t<int>& deltas) const
+ {
+ unsigned start = i;
+ unsigned num_deltas = deltas.length;
+ while (i < num_deltas)
+ {
+ int val = deltas[i];
+
+ /* start a new run for a single zero value*/
+ if (val == 0) break;
+
+ /* from fonttools: continue word-encoded run if there's only one
+ * single value in the range [-128, 127] because it is more compact.
+ * Only start a new run when there're 2 continuous such values. */
+ if (val >= -128 && val <= 127 &&
+ i + 1 < num_deltas &&
+ deltas[i+1] >= -128 && deltas[i+1] <= 127)
+ break;
+
+ i++;
+ }
+
+ unsigned run_length = i - start;
+ auto it = encoded_bytes.iter ();
+ unsigned encoded_len = 0;
+ while (run_length >= 64)
+ {
+ *it++ = (DELTAS_ARE_WORDS | 63);
+ encoded_len++;
+
+ for (unsigned j = 0; j < 64; j++)
+ {
+ int16_t delta_val = deltas[start + j];
+ *it++ = static_cast<char> (delta_val >> 8);
+ *it++ = static_cast<char> (delta_val & 0xFF);
+
+ encoded_len += 2;
+ }
+
+ start += 64;
+ run_length -= 64;
+ }
+
+ if (run_length)
+ {
+ *it++ = (DELTAS_ARE_WORDS | (run_length - 1));
+ while (start < i)
+ {
+ int16_t delta_val = deltas[start++];
+ *it++ = static_cast<char> (delta_val >> 8);
+ *it++ = static_cast<char> (delta_val & 0xFF);
+
+ encoded_len += 2;
+ }
+ }
+ return encoded_len;
+ }
+};
+
struct TupleVariationData
{
bool sanitize (hb_sanitize_context_t *c) const
@@ -378,7 +896,7 @@ struct TupleVariationData
unsigned get_size (unsigned axis_count) const
{
unsigned total_size = min_size;
- unsigned count = tupleVarCount;
+ unsigned count = tupleVarCount.get_count ();
const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header());
for (unsigned i = 0; i < count; i++)
{
@@ -392,8 +910,354 @@ struct TupleVariationData
const TupleVariationHeader &get_tuple_var_header (void) const
{ return StructAfter<TupleVariationHeader> (data); }
+ struct tuple_iterator_t;
+ struct tuple_variations_t
+ {
+ hb_vector_t<tuple_delta_t> tuple_vars;
+
+ private:
+ /* referenced point set->compiled point data map */
+ hb_hashmap_t<const hb_vector_t<bool>*, byte_data_t> point_data_map;
+ /* referenced point set-> count map, used in finding shared points */
+ hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
+
+ public:
+ ~tuple_variations_t () { fini (); }
+ void fini ()
+ {
+ for (auto _ : point_data_map.values ())
+ _.fini ();
+
+ point_set_count_map.fini ();
+ tuple_vars.fini ();
+ }
+
+ unsigned get_var_count () const
+ { return tuple_vars.length; }
+
+ bool create_from_tuple_var_data (tuple_iterator_t iterator,
+ unsigned tuple_var_count,
+ unsigned point_count,
+ bool is_gvar,
+ const hb_map_t *axes_old_index_tag_map,
+ const hb_vector_t<unsigned> &shared_indices,
+ const hb_array_t<const F2DOT14> shared_tuples)
+ {
+ do
+ {
+ const HBUINT8 *p = iterator.get_serialized_data ();
+ unsigned int length = iterator.current_tuple->get_data_size ();
+ if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
+ { fini (); return false; }
+
+ hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
+ if (!iterator.current_tuple->unpack_axis_tuples (iterator.get_axis_count (), shared_tuples, axes_old_index_tag_map, axis_tuples)
+ || axis_tuples.is_empty ())
+ { fini (); return false; }
+
+ hb_vector_t<unsigned> private_indices;
+ bool has_private_points = iterator.current_tuple->has_private_points ();
+ const HBUINT8 *end = p + length;
+ if (has_private_points &&
+ !TupleVariationData::unpack_points (p, private_indices, end))
+ { fini (); return false; }
+
+ const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices;
+ bool apply_to_all = (indices.length == 0);
+ unsigned num_deltas = apply_to_all ? point_count : indices.length;
+
+ hb_vector_t<int> deltas_x;
+
+ if (unlikely (!deltas_x.resize (num_deltas, false) ||
+ !TupleVariationData::unpack_deltas (p, deltas_x, end)))
+ { fini (); return false; }
+
+ hb_vector_t<int> deltas_y;
+ if (is_gvar)
+ {
+ if (unlikely (!deltas_y.resize (num_deltas, false) ||
+ !TupleVariationData::unpack_deltas (p, deltas_y, end)))
+ { fini (); return false; }
+ }
+
+ tuple_delta_t var;
+ var.axis_tuples = std::move (axis_tuples);
+ if (unlikely (!var.indices.resize (point_count) ||
+ !var.deltas_x.resize (point_count, false)))
+ { fini (); return false; }
+
+ if (is_gvar && unlikely (!var.deltas_y.resize (point_count, false)))
+ { fini (); return false; }
+
+ for (unsigned i = 0; i < num_deltas; i++)
+ {
+ unsigned idx = apply_to_all ? i : indices[i];
+ if (idx >= point_count) continue;
+ var.indices[idx] = true;
+ var.deltas_x[idx] = static_cast<float> (deltas_x[i]);
+ if (is_gvar)
+ var.deltas_y[idx] = static_cast<float> (deltas_y[i]);
+ }
+ tuple_vars.push (std::move (var));
+ } while (iterator.move_to_next ());
+ return true;
+ }
+
+ void change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple> *normalized_axes_location)
+ {
+ for (auto _ : *normalized_axes_location)
+ {
+ hb_tag_t axis_tag = _.first;
+ Triple axis_limit = _.second;
+ hb_vector_t<tuple_delta_t> new_vars;
+ for (const tuple_delta_t& var : tuple_vars)
+ {
+ hb_vector_t<tuple_delta_t> out = var.change_tuple_var_axis_limit (axis_tag, axis_limit);
+ if (!out) continue;
+ unsigned new_len = new_vars.length + out.length;
+
+ if (unlikely (!new_vars.alloc (new_len, false)))
+ { fini (); return;}
+
+ for (unsigned i = 0; i < out.length; i++)
+ new_vars.push (std::move (out[i]));
+ }
+ tuple_vars.fini ();
+ tuple_vars = std::move (new_vars);
+ }
+ }
+
+ /* merge tuple variations with overlapping tents */
+ void merge_tuple_variations ()
+ {
+ hb_vector_t<tuple_delta_t> new_vars;
+ hb_hashmap_t<hb_hashmap_t<hb_tag_t, Triple>, unsigned> m;
+ unsigned i = 0;
+ for (const tuple_delta_t& var : tuple_vars)
+ {
+ /* if all axes are pinned, drop the tuple variation */
+ if (var.axis_tuples.is_empty ()) continue;
+
+ unsigned *idx;
+ if (m.has (var.axis_tuples, &idx))
+ {
+ new_vars[*idx] += var;
+ }
+ else
+ {
+ new_vars.push (var);
+ m.set (var.axis_tuples, i);
+ i++;
+ }
+ }
+ tuple_vars.fini ();
+ tuple_vars = std::move (new_vars);
+ }
+
+ byte_data_t compile_point_set (const hb_vector_t<bool> &point_indices)
+ {
+ unsigned num_points = 0;
+ for (bool i : point_indices)
+ if (i) num_points++;
+
+ unsigned indices_length = point_indices.length;
+ /* If the points set consists of all points in the glyph, it's encoded with a
+ * single zero byte */
+ if (num_points == indices_length)
+ {
+ char *p = (char *) hb_calloc (1, sizeof (char));
+ if (unlikely (!p)) return byte_data_t ();
+
+ return byte_data_t (p, 1);
+ }
+
+ /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
+ unsigned num_bytes = 2 + 3 *num_points;
+ char *p = (char *) hb_calloc (num_bytes, sizeof (char));
+ if (unlikely (!p)) return byte_data_t ();
+
+ unsigned pos = 0;
+ /* binary data starts with the total number of reference points */
+ if (num_points < 0x80)
+ p[pos++] = num_points;
+ else
+ {
+ p[pos++] = ((num_points >> 8) | 0x80);
+ p[pos++] = num_points & 0xFF;
+ }
+
+ const unsigned max_run_length = 0x7F;
+ unsigned i = 0;
+ unsigned last_value = 0;
+ unsigned num_encoded = 0;
+ while (i < indices_length && num_encoded < num_points)
+ {
+ unsigned run_length = 0;
+ unsigned header_pos = pos;
+ p[pos++] = 0;
+
+ bool use_byte_encoding = false;
+ bool new_run = true;
+ while (i < indices_length && num_encoded < num_points &&
+ run_length <= max_run_length)
+ {
+ // find out next referenced point index
+ while (i < indices_length && !point_indices[i])
+ i++;
+
+ if (i >= indices_length) break;
+
+ unsigned cur_value = i;
+ unsigned delta = cur_value - last_value;
+
+ if (new_run)
+ {
+ use_byte_encoding = (delta <= 0xFF);
+ new_run = false;
+ }
+
+ if (use_byte_encoding && delta > 0xFF)
+ break;
+
+ if (use_byte_encoding)
+ p[pos++] = delta;
+ else
+ {
+ p[pos++] = delta >> 8;
+ p[pos++] = delta & 0xFF;
+ }
+ i++;
+ last_value = cur_value;
+ run_length++;
+ num_encoded++;
+ }
+
+ if (use_byte_encoding)
+ p[header_pos] = run_length - 1;
+ else
+ p[header_pos] = (run_length - 1) | 0x80;
+ }
+ return byte_data_t (p, pos);
+ }
+
+ /* compile all point set and store byte data in a point_set->byte_data_t hashmap,
+ * also update point_set->count map, which will be used in finding shared
+ * point set*/
+ bool compile_all_point_sets ()
+ {
+ for (const auto& tuple: tuple_vars)
+ {
+ const hb_vector_t<bool>* points_set = &(tuple.indices);
+ if (point_data_map.has (points_set))
+ {
+ unsigned *count;
+ if (unlikely (!point_set_count_map.has (points_set, &count) ||
+ !point_set_count_map.set (points_set, (*count) + 1)))
+ return false;
+ continue;
+ }
+
+ byte_data_t compiled_data = compile_point_set (*points_set);
+ if (unlikely (compiled_data == byte_data_t ()))
+ return false;
+
+ if (!point_data_map.set (points_set, compiled_data) ||
+ !point_set_count_map.set (points_set, 1))
+ return false;
+ }
+ return true;
+ }
+
+ /* find shared points set which saves most bytes */
+ byte_data_t find_shared_points ()
+ {
+ unsigned max_saved_bytes = 0;
+ byte_data_t res{};
+
+ for (const auto& _ : point_data_map.iter ())
+ {
+ const hb_vector_t<bool>* points_set = _.first;
+ unsigned data_length = _.second.bytes.length;
+ unsigned *count;
+ if (unlikely (!point_set_count_map.has (points_set, &count) ||
+ *count <= 1))
+ return byte_data_t ();
+
+ unsigned saved_bytes = data_length * ((*count) -1);
+ if (saved_bytes > max_saved_bytes)
+ {
+ max_saved_bytes = saved_bytes;
+ res = _.second;
+ }
+ }
+ return res;
+ }
+
+ void instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location)
+ {
+ change_tuple_variations_axis_limits (&normalized_axes_location);
+ merge_tuple_variations ();
+ }
+
+ bool compile_bytes (const hb_map_t& axes_index_map,
+ const hb_map_t& axes_old_index_tag_map)
+ {
+ // compile points set and store data in hashmap
+ if (!compile_all_point_sets ())
+ return false;
+ // compile delta and tuple var header for each tuple variation
+ for (auto& tuple: tuple_vars)
+ {
+ const hb_vector_t<bool>* points_set = &(tuple.indices);
+ byte_data_t *points_data;
+ if (unlikely (!point_data_map.has (points_set, &points_data)))
+ return false;
+
+ if (!tuple.compile_deltas ())
+ return false;
+
+ if (!tuple.compile_tuple_var_header (axes_index_map, points_data->bytes.length, axes_old_index_tag_map))
+ return false;
+ }
+ return true;
+ }
+
+ bool serialize_var_headers (hb_serialize_context_t *c, unsigned& total_header_len) const
+ {
+ TRACE_SERIALIZE (this);
+ for (const auto& tuple: tuple_vars)
+ {
+ byte_data_t compiled_bytes {tuple.compiled_tuple_header.arrayZ, tuple.compiled_tuple_header.length};
+ compiled_bytes.copy (c);
+ if (c->in_error ()) return_trace (false);
+ total_header_len += tuple.compiled_tuple_header.length;
+ }
+ return_trace (true);
+ }
+
+ bool serialize_var_data (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ for (const auto& tuple: tuple_vars)
+ {
+ const hb_vector_t<bool>* points_set = &(tuple.indices);
+ byte_data_t *point_data;
+ if (!point_data_map.has (points_set, &point_data))
+ return_trace (false);
+
+ point_data->copy (c);
+ byte_data_t compiled_bytes {tuple.compiled_deltas.arrayZ, tuple.compiled_deltas.length};
+ compiled_bytes.copy (c);
+ if (c->in_error ()) return_trace (false);
+ }
+ return_trace (true);
+ }
+ };
+
struct tuple_iterator_t
{
+ unsigned get_axis_count () const { return axis_count; }
+
void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_, const void *table_base_)
{
var_data_bytes = var_data_bytes_;
@@ -517,13 +1381,6 @@ struct TupleVariationData
hb_vector_t<int> &deltas /* IN/OUT */,
const HBUINT8 *end)
{
- enum packed_delta_flag_t
- {
- DELTAS_ARE_ZERO = 0x80,
- DELTAS_ARE_WORDS = 0x40,
- DELTA_RUN_COUNT_MASK = 0x3F
- };
-
unsigned i = 0;
unsigned count = deltas.length;
while (i < count)
@@ -561,11 +1418,50 @@ struct TupleVariationData
bool has_data () const { return tupleVarCount; }
+ bool decompile_tuple_variations (unsigned point_count,
+ bool is_gvar,
+ tuple_iterator_t iterator,
+ const hb_map_t *axes_old_index_tag_map,
+ const hb_vector_t<unsigned> &shared_indices,
+ const hb_array_t<const F2DOT14> shared_tuples,
+ tuple_variations_t& tuple_variations /* OUT */) const
+ {
+ return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount,
+ point_count, is_gvar,
+ axes_old_index_tag_map,
+ shared_indices,
+ shared_tuples);
+ }
+
+ bool serialize (hb_serialize_context_t *c,
+ bool is_gvar,
+ tuple_variations_t& tuple_variations) const
+ {
+ TRACE_SERIALIZE (this);
+ auto *out = c->start_embed (this);
+ if (unlikely (!c->extend_min (out))) return_trace (false);
+
+ if (!c->check_assign (out->tupleVarCount, tuple_variations.get_var_count (),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
+
+ unsigned total_header_len = 0;
+
+ if (!tuple_variations.serialize_var_headers (c, total_header_len))
+ return_trace (false);
+
+ unsigned data_offset = min_size + total_header_len;
+ if (!is_gvar) data_offset += 4;
+ if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
+
+ return tuple_variations.serialize_var_data (c);
+ }
+
protected:
struct TupleVarCount : HBUINT16
{
bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
unsigned int get_count () const { return (*this) & CountMask; }
+ TupleVarCount& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
protected:
enum Flags
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-cvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-cvar-table.hh
index 7fd0f1d79d..de54339301 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-cvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-cvar-table.hh
@@ -27,6 +27,7 @@
#define HB_OT_VAR_CVAR_TABLE_HH
#include "hb-ot-var-common.hh"
+#include "hb-ot-var-fvar-table.hh"
namespace OT {
@@ -51,6 +52,27 @@ struct cvar
const TupleVariationData* get_tuple_var_data (void) const
{ return &tupleVariationData; }
+ bool decompile_tuple_variations (unsigned axis_count,
+ unsigned point_count,
+ bool is_gvar,
+ const hb_map_t *axes_old_index_tag_map,
+ TupleVariationData::tuple_variations_t& tuple_variations /* OUT */) const
+ {
+ hb_vector_t<unsigned> shared_indices;
+ TupleVariationData::tuple_iterator_t iterator;
+ unsigned var_data_length = tupleVariationData.get_size (axis_count);
+ hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast<const char*> (get_tuple_var_data ()), var_data_length);
+ if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, this,
+ shared_indices, &iterator))
+ return false;
+
+ return tupleVariationData.decompile_tuple_variations (point_count, is_gvar, iterator,
+ axes_old_index_tag_map,
+ shared_indices,
+ hb_array<const F2DOT14> (),
+ tuple_variations);
+ }
+
static bool calculate_cvt_deltas (unsigned axis_count,
hb_array_t<int> coords,
unsigned num_cvt_item,
@@ -104,6 +126,53 @@ struct cvar
return true;
}
+
+ bool serialize (hb_serialize_context_t *c,
+ TupleVariationData::tuple_variations_t& tuple_variations) const
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->embed (version))) return_trace (false);
+
+ return_trace (tupleVariationData.serialize (c, false, tuple_variations));
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ if (c->plan->all_axes_pinned)
+ return_trace (false);
+
+ /* subset() for cvar is called by partial instancing only, we always pass
+ * through cvar table in other cases */
+ if (!c->plan->normalized_coords)
+ {
+ unsigned axis_count = c->plan->source->table.fvar->get_axis_count ();
+ unsigned total_size = min_size + tupleVariationData.get_size (axis_count);
+ char *out = c->serializer->allocate_size<char> (total_size);
+ if (unlikely (!out)) return_trace (false);
+
+ hb_memcpy (out, this, total_size);
+ return_trace (true);
+ }
+
+ OT::TupleVariationData::tuple_variations_t tuple_variations;
+ unsigned axis_count = c->plan->axes_old_index_tag_map.get_population ();
+
+ const hb_tag_t cvt = HB_TAG('c','v','t',' ');
+ hb_blob_t *cvt_blob = hb_face_reference_table (c->plan->source, cvt);
+ unsigned point_count = hb_blob_get_length (cvt_blob) / FWORD::static_size;
+
+ if (!decompile_tuple_variations (axis_count, point_count, false,
+ &(c->plan->axes_old_index_tag_map),
+ tuple_variations))
+ return_trace (false);
+
+ tuple_variations.instantiate (c->plan->axes_location);
+ if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map))
+ return_trace (false);
+
+ return_trace (serialize (c->serializer, tuple_variations));
+ }
static bool add_cvt_and_apply_deltas (hb_subset_plan_t *plan,
const TupleVariationData *tuple_var_data,
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
index a384dfa531..d8e789cb44 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
@@ -39,6 +39,24 @@
namespace OT {
+static bool axis_coord_pinned_or_within_axis_range (const hb_array_t<const F16DOT16> coords,
+ unsigned axis_index,
+ Triple axis_limit)
+{
+ float axis_coord = coords[axis_index].to_float ();
+ if (axis_limit.is_point ())
+ {
+ if (axis_limit.minimum != axis_coord)
+ return false;
+ }
+ else
+ {
+ if (axis_coord < axis_limit.minimum ||
+ axis_coord > axis_limit.maximum)
+ return false;
+ }
+ return true;
+}
struct InstanceRecord
{
@@ -47,6 +65,27 @@ struct InstanceRecord
hb_array_t<const F16DOT16> get_coordinates (unsigned int axis_count) const
{ return coordinatesZ.as_array (axis_count); }
+ bool keep_instance (unsigned axis_count,
+ const hb_map_t *axes_index_tag_map,
+ const hb_hashmap_t<hb_tag_t, Triple> *axes_location) const
+ {
+ if (axes_location->is_empty ()) return true;
+ const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
+ for (unsigned i = 0 ; i < axis_count; i++)
+ {
+ uint32_t *axis_tag;
+ if (!axes_index_tag_map->has (i, &axis_tag))
+ return false;
+ if (!axes_location->has (*axis_tag))
+ continue;
+
+ Triple axis_limit = axes_location->get (*axis_tag);
+ if (!axis_coord_pinned_or_within_axis_range (coords, i, axis_limit))
+ return false;
+ }
+ return true;
+ }
+
bool subset (hb_subset_context_t *c,
unsigned axis_count,
bool has_postscript_nameid) const
@@ -56,19 +95,22 @@ struct InstanceRecord
if (unlikely (!c->serializer->embed (flags))) return_trace (false);
const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
- const hb_hashmap_t<hb_tag_t, float> *axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple> *axes_location = &c->plan->user_axes_location;
for (unsigned i = 0 ; i < axis_count; i++)
{
uint32_t *axis_tag;
// only keep instances whose coordinates == pinned axis location
if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) continue;
-
- if (axes_location->has (*axis_tag) &&
- fabsf (axes_location->get (*axis_tag) - coords[i].to_float ()) > 0.001f)
- return_trace (false);
-
- if (!c->plan->axes_index_map.has (i))
- continue;
+ if (axes_location->has (*axis_tag))
+ {
+ Triple axis_limit = axes_location->get (*axis_tag);
+ if (!axis_coord_pinned_or_within_axis_range (coords, i, axis_limit))
+ return_trace (false);
+
+ //skip pinned axis
+ if (axis_limit.is_point ())
+ continue;
+ }
if (!c->serializer->embed (coords[i]))
return_trace (false);
@@ -216,7 +258,8 @@ struct fvar
axisSize == 20 && /* Assumed in our code. */
instanceSize >= axisCount * 4 + 4 &&
get_axes ().sanitize (c) &&
- c->check_range (get_instance (0), instanceCount, instanceSize));
+ c->check_range (&StructAfter<InstanceRecord> (get_axes ()),
+ instanceCount, instanceSize));
}
unsigned int get_axis_count () const { return axisCount; }
@@ -314,21 +357,19 @@ struct fvar
return axisCount;
}
- void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+ void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location,
+ hb_map_t *axes_old_index_tag_map,
hb_set_t *nameids /* IN/OUT */) const
{
if (!has_data ()) return;
- hb_map_t pinned_axes;
auto axis_records = get_axes ();
for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
{
hb_tag_t axis_tag = axis_records[i].get_axis_tag ();
- if (user_axes_location->has (axis_tag))
- {
- pinned_axes.set (i, axis_tag);
+ if (user_axes_location->has (axis_tag) &&
+ user_axes_location->get (axis_tag).is_point ())
continue;
- }
nameids->add (axis_records[i].get_name_id ());
}
@@ -337,16 +378,7 @@ struct fvar
{
const InstanceRecord *instance = get_instance (i);
- if (hb_any (+ hb_enumerate (instance->get_coordinates (axisCount))
- | hb_filter (pinned_axes, hb_first)
- | hb_map ([&] (const hb_pair_t<unsigned, const F16DOT16&>& _)
- {
- hb_tag_t axis_tag = pinned_axes.get (_.first);
- float location = user_axes_location->get (axis_tag);
- if (fabs ((double)location - (double)_.second.to_float ()) > 0.001) return true;
- return false;
- })
- ))
+ if (!instance->keep_instance (axisCount, axes_old_index_tag_map, user_axes_location))
continue;
nameids->add (instance->subfamilyNameID);
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
index ece892e1dd..b5099ac074 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
@@ -50,13 +50,14 @@ struct contour_point_t
y = x * matrix[1] + y * matrix[3];
x = x_;
}
+ HB_ALWAYS_INLINE
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
- float x = 0.f;
- float y = 0.f;
- uint8_t flag = 0;
- bool is_end_point = false;
+ float x;
+ float y;
+ uint8_t flag;
+ bool is_end_point;
};
struct contour_point_vector_t : hb_vector_t<contour_point_t>
@@ -110,20 +111,20 @@ struct gvar
unsigned int num_glyphs = c->plan->num_output_glyphs ();
out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
+ auto it = hb_iter (c->plan->new_to_old_gid_list);
+ if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+ it++;
unsigned int subset_data_size = 0;
- for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
- gid < num_glyphs;
- gid++)
+ for (auto &_ : it)
{
- hb_codepoint_t old_gid;
- if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
+ hb_codepoint_t old_gid = _.second;
subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
}
bool long_offset = subset_data_size & ~0xFFFFu;
out->flags = long_offset ? 1 : 0;
- HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1));
+ HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
if (!subset_offsets) return_trace (false);
/* shared tuples */
@@ -138,36 +139,61 @@ struct gvar
hb_memcpy (tuples, this+sharedTuples, shared_tuple_size);
}
- char *subset_data = c->serializer->allocate_size<char> (subset_data_size);
+ char *subset_data = c->serializer->allocate_size<char> (subset_data_size, false);
if (!subset_data) return_trace (false);
out->dataZ = subset_data - (char *) out;
+
+ if (long_offset)
+ {
+ ((HBUINT32 *) subset_offsets)[0] = 0;
+ subset_offsets += 4;
+ }
+ else
+ {
+ ((HBUINT16 *) subset_offsets)[0] = 0;
+ subset_offsets += 2;
+ }
unsigned int glyph_offset = 0;
- for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
- gid < num_glyphs;
- gid++)
+
+ hb_codepoint_t last = 0;
+ it = hb_iter (c->plan->new_to_old_gid_list);
+ if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+ it++;
+ for (auto &_ : it)
{
- hb_codepoint_t old_gid;
- hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid)
- ? get_glyph_var_data_bytes (c->source_blob,
+ hb_codepoint_t gid = _.first;
+ hb_codepoint_t old_gid = _.second;
+
+ if (long_offset)
+ for (; last < gid; last++)
+ ((HBUINT32 *) subset_offsets)[last] = glyph_offset;
+ else
+ for (; last < gid; last++)
+ ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2;
+
+ hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob,
glyph_count,
- old_gid)
- : hb_bytes_t ();
+ old_gid);
+
+ hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
+ subset_data += var_data_bytes.length;
+ glyph_offset += var_data_bytes.length;
if (long_offset)
((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
else
((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
- if (var_data_bytes.length > 0)
- hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
- subset_data += var_data_bytes.length;
- glyph_offset += var_data_bytes.length;
+ last++; // Skip over gid
}
+
if (long_offset)
- ((HBUINT32 *) subset_offsets)[num_glyphs] = glyph_offset;
+ for (; last < num_glyphs; last++)
+ ((HBUINT32 *) subset_offsets)[last] = glyph_offset;
else
- ((HBUINT16 *) subset_offsets)[num_glyphs] = glyph_offset / 2;
+ for (; last < num_glyphs; last++)
+ ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2;
return_trace (true);
}
@@ -216,21 +242,24 @@ struct gvar
for (unsigned i = 0; i < count; i++)
{
hb_array_t<const F2DOT14> tuple = shared_tuples.sub_array (axis_count * i, axis_count);
- int idx = -1;
+ int idx1 = -1, idx2 = -1;
for (unsigned j = 0; j < axis_count; j++)
{
const F2DOT14 &peak = tuple.arrayZ[j];
if (peak.to_int () != 0)
{
- if (idx != -1)
+ if (idx1 == -1)
+ idx1 = j;
+ else if (idx2 == -1)
+ idx2 = j;
+ else
{
- idx = -1;
+ idx1 = idx2 = -1;
break;
}
- idx = j;
}
}
- shared_tuple_active_idx.arrayZ[i] = idx;
+ shared_tuple_active_idx.arrayZ[i] = {idx1, idx2};
}
}
~accelerator_t () { table.destroy (); }
@@ -266,10 +295,9 @@ struct gvar
public:
bool apply_deltas_to_points (hb_codepoint_t glyph,
hb_array_t<int> coords,
- const hb_array_t<contour_point_t> points) const
+ const hb_array_t<contour_point_t> points,
+ bool phantom_only = false) const
{
- if (!coords) return true;
-
if (unlikely (glyph >= glyphCount)) return true;
hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph);
@@ -297,6 +325,7 @@ struct gvar
hb_vector_t<unsigned int> private_indices;
hb_vector_t<int> x_deltas;
hb_vector_t<int> y_deltas;
+ unsigned count = points.length;
bool flush = false;
do
{
@@ -310,9 +339,10 @@ struct gvar
if (!deltas)
{
- if (unlikely (!deltas_vec.resize (points.length, false))) return false;
+ if (unlikely (!deltas_vec.resize (count, false))) return false;
deltas = deltas_vec.as_array ();
- hb_memset (deltas.arrayZ, 0, deltas.get_size ()); // Faster than vector resize
+ hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
+ (phantom_only ? 4 : count) * sizeof (deltas[0]));
}
const HBUINT8 *end = p + length;
@@ -332,7 +362,7 @@ struct gvar
if (!apply_to_all)
{
- if (!orig_points)
+ if (!orig_points && !phantom_only)
{
orig_points_vec.extend (points);
if (unlikely (orig_points_vec.in_error ())) return false;
@@ -341,13 +371,13 @@ struct gvar
if (flush)
{
- unsigned count = points.length;
- for (unsigned int i = 0; i < count; i++)
+ for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
points.arrayZ[i].translate (deltas.arrayZ[i]);
flush = false;
}
- hb_memset (deltas.arrayZ, 0, deltas.get_size ());
+ hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
+ (phantom_only ? 4 : count) * sizeof (deltas[0]));
}
if (HB_OPTIMIZE_SIZE_VAL)
@@ -362,6 +392,7 @@ struct gvar
pt_index = indices[i];
if (unlikely (pt_index >= deltas.length)) continue;
}
+ if (phantom_only && pt_index < count - 4) continue;
auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i] * scalar;
@@ -374,7 +405,7 @@ struct gvar
if (scalar != 1.0f)
{
if (apply_to_all)
- for (unsigned int i = 0; i < num_deltas; i++)
+ for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
{
unsigned int pt_index = i;
auto &delta = deltas.arrayZ[pt_index];
@@ -386,6 +417,7 @@ struct gvar
{
unsigned int pt_index = indices[i];
if (unlikely (pt_index >= deltas.length)) continue;
+ if (phantom_only && pt_index < count - 4) continue;
auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i] * scalar;
@@ -395,7 +427,7 @@ struct gvar
else
{
if (apply_to_all)
- for (unsigned int i = 0; i < num_deltas; i++)
+ for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
{
unsigned int pt_index = i;
auto &delta = deltas.arrayZ[pt_index];
@@ -407,6 +439,7 @@ struct gvar
{
unsigned int pt_index = indices[i];
if (unlikely (pt_index >= deltas.length)) continue;
+ if (phantom_only && pt_index < count - 4) continue;
auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i];
@@ -416,11 +449,10 @@ struct gvar
}
/* infer deltas for unreferenced points */
- if (!apply_to_all)
+ if (!apply_to_all && !phantom_only)
{
if (!end_points)
{
- unsigned count = points.length;
for (unsigned i = 0; i < count; ++i)
if (points.arrayZ[i].is_end_point)
end_points.push (i);
@@ -482,8 +514,7 @@ struct gvar
if (flush)
{
- unsigned count = points.length;
- for (unsigned int i = 0; i < count; i++)
+ for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
points.arrayZ[i].translate (deltas.arrayZ[i]);
}
@@ -495,7 +526,7 @@ struct gvar
private:
hb_blob_ptr_t<gvar> table;
unsigned glyphCount;
- hb_vector_t<signed> shared_tuple_active_idx;
+ hb_vector_t<hb_pair_t<int, int>> shared_tuple_active_idx;
};
protected:
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh
index 461b2b9cdb..943d376bdf 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh
@@ -56,52 +56,56 @@ struct index_map_subset_plan_t
if (&index_map == &Null (DeltaSetIndexMap)) return;
unsigned int last_val = (unsigned int)-1;
- hb_codepoint_t last_gid = (hb_codepoint_t)-1;
- hb_codepoint_t gid = (hb_codepoint_t) hb_min (index_map.get_map_count (), plan->num_output_glyphs ());
+ hb_codepoint_t last_gid = HB_CODEPOINT_INVALID;
+ hb_codepoint_t num_gid = (hb_codepoint_t) hb_min (index_map.get_map_count (), plan->num_output_glyphs ());
outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count ();
max_inners.resize (inner_sets.length);
for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0;
/* Search backwards for a map value different from the last map value */
- for (; gid > 0; gid--)
+ auto &new_to_old_gid_list = plan->new_to_old_gid_list;
+ unsigned count = new_to_old_gid_list.length;
+ for (unsigned j = count; j; j--)
{
- hb_codepoint_t old_gid;
- if (!plan->old_gid_for_new_gid (gid - 1, &old_gid))
- {
- if (last_gid == (hb_codepoint_t) -1)
- continue;
- else
- break;
- }
+ hb_codepoint_t gid = new_to_old_gid_list[j - 1].first;
+ if (gid >= num_gid) continue;
+
+ hb_codepoint_t old_gid = new_to_old_gid_list[j - 1].second;
unsigned int v = index_map.map (old_gid);
- if (last_gid == (hb_codepoint_t) -1)
+ if (last_gid == HB_CODEPOINT_INVALID)
{
+ if (gid + 1 != num_gid)
+ {
+ last_gid = gid + 1;
+ break;
+ }
last_val = v;
last_gid = gid;
continue;
}
- if (v != last_val) break;
+ if (v != last_val || gid + 1 != last_gid)
+ break;
last_gid = gid;
}
if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
- map_count = last_gid;
- for (gid = 0; gid < map_count; gid++)
+ map_count = last_gid + 1;
+ for (auto _ : plan->new_to_old_gid_list)
{
- hb_codepoint_t old_gid;
- if (plan->old_gid_for_new_gid (gid, &old_gid))
- {
- unsigned int v = index_map.map (old_gid);
- unsigned int outer = v >> 16;
- unsigned int inner = v & 0xFFFF;
- outer_map.add (outer);
- if (inner > max_inners[outer]) max_inners[outer] = inner;
- if (outer >= inner_sets.length) return;
- inner_sets[outer]->add (inner);
- }
+ hb_codepoint_t gid = _.first;
+ if (gid >= map_count) break;
+
+ hb_codepoint_t old_gid = _.second;
+ unsigned int v = index_map.map (old_gid);
+ unsigned int outer = v >> 16;
+ unsigned int inner = v & 0xFFFF;
+ outer_map.add (outer);
+ if (inner > max_inners[outer]) max_inners[outer] = inner;
+ if (outer >= inner_sets.length) return;
+ inner_sets[outer]->add (inner);
}
}
@@ -197,7 +201,8 @@ struct hvarvvar_subset_plan_t
if (retain_adv_map)
{
- for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
+ unsigned num_glyphs = plan->num_output_glyphs ();
+ for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
{
if (inner_sets[0]->has (gid))
inner_maps[0].add (gid);
diff --git a/thirdparty/harfbuzz/src/hb-ot-vorg-table.hh b/thirdparty/harfbuzz/src/hb-ot-vorg-table.hh
index 811e13919e..671b6d2c29 100644
--- a/thirdparty/harfbuzz/src/hb-ot-vorg-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-vorg-table.hh
@@ -90,7 +90,7 @@ struct VORG
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- VORG *vorg_prime = c->serializer->start_embed<VORG> ();
+ auto *vorg_prime = c->serializer->start_embed<VORG> ();
if (unlikely (!c->serializer->check_success (vorg_prime))) return_trace (false);
auto it =
diff --git a/thirdparty/harfbuzz/src/hb-pool.hh b/thirdparty/harfbuzz/src/hb-pool.hh
index d6eb778f5d..fcf10666b0 100644
--- a/thirdparty/harfbuzz/src/hb-pool.hh
+++ b/thirdparty/harfbuzz/src/hb-pool.hh
@@ -58,7 +58,7 @@ struct hb_pool_t
if (unlikely (!next))
{
if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
- chunk_t *chunk = (chunk_t *) hb_calloc (1, sizeof (chunk_t));
+ chunk_t *chunk = (chunk_t *) hb_malloc (sizeof (chunk_t));
if (unlikely (!chunk)) return nullptr;
chunks.push (chunk);
next = chunk->thread ();
diff --git a/thirdparty/harfbuzz/src/hb-sanitize.hh b/thirdparty/harfbuzz/src/hb-sanitize.hh
index 5259891b7e..2d338c51c8 100644
--- a/thirdparty/harfbuzz/src/hb-sanitize.hh
+++ b/thirdparty/harfbuzz/src/hb-sanitize.hh
@@ -122,12 +122,14 @@ struct hb_sanitize_context_t :
{
hb_sanitize_context_t () :
start (nullptr), end (nullptr),
+ length (0),
max_ops (0), max_subtables (0),
recursion_depth (0),
writable (false), edit_count (0),
blob (nullptr),
num_glyphs (65536),
- num_glyphs_set (false) {}
+ num_glyphs_set (false),
+ lazy_some_gpos (false) {}
const char *get_name () { return "SANITIZE"; }
template <typename T, typename F>
@@ -155,6 +157,19 @@ struct hb_sanitize_context_t :
dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
+ hb_sanitize_context_t (hb_blob_t *b) : hb_sanitize_context_t ()
+ {
+ init (b);
+
+ if (blob)
+ start_processing ();
+ }
+
+ ~hb_sanitize_context_t ()
+ {
+ if (blob)
+ end_processing ();
+ }
void init (hb_blob_t *b)
{
@@ -180,11 +195,15 @@ struct hb_sanitize_context_t :
const char *obj_start = (const char *) obj;
if (unlikely (obj_start < this->start || this->end <= obj_start))
+ {
this->start = this->end = nullptr;
+ this->length = 0;
+ }
else
{
this->start = obj_start;
this->end = obj_start + hb_min (size_t (this->end - obj_start), obj->get_size ());
+ this->length = this->end - this->start;
}
}
@@ -192,6 +211,7 @@ struct hb_sanitize_context_t :
{
this->start = this->blob->data;
this->end = this->start + this->blob->length;
+ this->length = this->end - this->start;
assert (this->start <= this->end); /* Must not overflow. */
}
@@ -224,6 +244,7 @@ struct hb_sanitize_context_t :
hb_blob_destroy (this->blob);
this->blob = nullptr;
this->start = this->end = nullptr;
+ this->length = 0;
}
unsigned get_edit_count () { return edit_count; }
@@ -240,15 +261,16 @@ struct hb_sanitize_context_t :
return (this->max_ops -= (int) count) > 0;
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool check_range (const void *base,
unsigned int len) const
{
const char *p = (const char *) base;
- bool ok = !len ||
- (this->start <= p &&
- p <= this->end &&
- (unsigned int) (this->end - p) >= len &&
- (this->max_ops -= len) > 0);
+ bool ok = (uintptr_t) (p - this->start) <= this->length &&
+ (unsigned int) (this->end - p) >= len &&
+ ((this->max_ops -= len) > 0);
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
"check_range [%p..%p]"
@@ -259,6 +281,43 @@ struct hb_sanitize_context_t :
return likely (ok);
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
+ bool check_range_fast (const void *base,
+ unsigned int len) const
+ {
+ const char *p = (const char *) base;
+ bool ok = ((uintptr_t) (p - this->start) <= this->length &&
+ (unsigned int) (this->end - p) >= len);
+
+ DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+ "check_range_fast [%p..%p]"
+ " (%u bytes) in [%p..%p] -> %s",
+ p, p + len, len,
+ this->start, this->end,
+ ok ? "OK" : "OUT-OF-RANGE");
+
+ return likely (ok);
+ }
+
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
+ bool check_point (const void *base) const
+ {
+ const char *p = (const char *) base;
+ bool ok = (uintptr_t) (p - this->start) <= this->length;
+
+ DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+ "check_point [%p]"
+ " in [%p..%p] -> %s",
+ p,
+ this->start, this->end,
+ ok ? "OK" : "OUT-OF-RANGE");
+
+ return likely (ok);
+ }
template <typename T>
bool check_range (const T *base,
@@ -282,6 +341,20 @@ struct hb_sanitize_context_t :
}
template <typename T>
+ HB_ALWAYS_INLINE
+ bool check_array_sized (const T *base, unsigned int len, unsigned len_size) const
+ {
+ if (len_size >= 4)
+ {
+ if (unlikely (hb_unsigned_mul_overflows (len, hb_static_size (T), &len)))
+ return false;
+ }
+ else
+ len = len * hb_static_size (T);
+ return this->check_range (base, len);
+ }
+
+ template <typename T>
bool check_array (const T *base, unsigned int len) const
{
return this->check_range (base, len, hb_static_size (T));
@@ -292,7 +365,7 @@ struct hb_sanitize_context_t :
unsigned int a,
unsigned int b) const
{
- return this->check_range (base, a, b, hb_static_size (T));
+ return this->check_range (base, hb_static_size (T), a, b);
}
bool check_start_recursion (int max_depth)
@@ -309,7 +382,12 @@ struct hb_sanitize_context_t :
template <typename Type>
bool check_struct (const Type *obj) const
- { return likely (this->check_range (obj, obj->min_size)); }
+ {
+ if (sizeof (uintptr_t) == sizeof (uint32_t))
+ return likely (this->check_range_fast (obj, obj->min_size));
+ else
+ return likely (this->check_point ((const char *) obj + obj->min_size));
+ }
bool may_edit (const void *base, unsigned int len)
{
@@ -416,6 +494,7 @@ struct hb_sanitize_context_t :
}
const char *start, *end;
+ unsigned length;
mutable int max_ops, max_subtables;
private:
int recursion_depth;
@@ -424,6 +503,8 @@ struct hb_sanitize_context_t :
hb_blob_t *blob;
unsigned int num_glyphs;
bool num_glyphs_set;
+ public:
+ bool lazy_some_gpos;
};
struct hb_sanitize_with_object_t
diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh
index 61ec0253a0..f852f07ba6 100644
--- a/thirdparty/harfbuzz/src/hb-serialize.hh
+++ b/thirdparty/harfbuzz/src/hb-serialize.hh
@@ -113,7 +113,7 @@ struct hb_serialize_context_t
{
// Virtual links aren't considered for equality since they don't affect the functionality
// of the object.
- return hb_bytes_t (head, tail - head).hash () ^
+ return hb_bytes_t (head, hb_min (128, tail - head)).hash () ^
real_links.as_bytes ().hash ();
}
@@ -172,8 +172,14 @@ struct hb_serialize_context_t
};
snapshot_t snapshot ()
- { return snapshot_t {
- head, tail, current, current->real_links.length, current->virtual_links.length, errors }; }
+ {
+ return snapshot_t {
+ head, tail, current,
+ current ? current->real_links.length : 0,
+ current ? current->virtual_links.length : 0,
+ errors
+ };
+ }
hb_serialize_context_t (void *start_, unsigned int size) :
start ((char *) start_),
@@ -261,6 +267,7 @@ struct hb_serialize_context_t
/* To be called around main operation. */
template <typename Type>
+ __attribute__((returns_nonnull))
Type *start_serialize ()
{
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
@@ -303,6 +310,7 @@ struct hb_serialize_context_t
}
template <typename Type = void>
+ __attribute__((returns_nonnull))
Type *push ()
{
if (unlikely (in_error ())) return start_embed<Type> ();
@@ -323,6 +331,8 @@ struct hb_serialize_context_t
{
object_t *obj = current;
if (unlikely (!obj)) return;
+ // Allow cleanup when we've error'd out on int overflows which don't compromise
+ // the serializer state.
if (unlikely (in_error() && !only_overflow ())) return;
current = current->next;
@@ -340,7 +350,9 @@ struct hb_serialize_context_t
{
object_t *obj = current;
if (unlikely (!obj)) return 0;
- if (unlikely (in_error())) return 0;
+ // Allow cleanup when we've error'd out on int overflows which don't compromise
+ // the serializer state.
+ if (unlikely (in_error() && !only_overflow ())) return 0;
current = current->next;
obj->tail = head;
@@ -405,8 +417,11 @@ struct hb_serialize_context_t
// Overflows that happened after the snapshot will be erased by the revert.
if (unlikely (in_error () && !only_overflow ())) return;
assert (snap.current == current);
- current->real_links.shrink (snap.num_real_links);
- current->virtual_links.shrink (snap.num_virtual_links);
+ if (current)
+ {
+ current->real_links.shrink (snap.num_real_links);
+ current->virtual_links.shrink (snap.num_virtual_links);
+ }
errors = snap.errors;
revert (snap.head, snap.tail);
}
@@ -563,13 +578,15 @@ struct hb_serialize_context_t
{
unsigned int l = length () % alignment;
if (l)
- allocate_size<void> (alignment - l);
+ (void) allocate_size<void> (alignment - l);
}
template <typename Type = void>
+ __attribute__((returns_nonnull))
Type *start_embed (const Type *obj HB_UNUSED = nullptr) const
{ return reinterpret_cast<Type *> (this->head); }
template <typename Type>
+ __attribute__((returns_nonnull))
Type *start_embed (const Type &obj) const
{ return start_embed (std::addressof (obj)); }
@@ -597,6 +614,7 @@ struct hb_serialize_context_t
}
template <typename Type>
+ HB_NODISCARD
Type *allocate_size (size_t size, bool clear = true)
{
if (unlikely (in_error ())) return nullptr;
@@ -618,6 +636,7 @@ struct hb_serialize_context_t
{ return this->allocate_size<Type> (Type::min_size); }
template <typename Type>
+ HB_NODISCARD
Type *embed (const Type *obj)
{
unsigned int size = obj->get_size ();
@@ -627,6 +646,7 @@ struct hb_serialize_context_t
return ret;
}
template <typename Type>
+ HB_NODISCARD
Type *embed (const Type &obj)
{ return embed (std::addressof (obj)); }
char *embed (const char *obj, unsigned size)
diff --git a/thirdparty/harfbuzz/src/hb-set-digest.hh b/thirdparty/harfbuzz/src/hb-set-digest.hh
index dab713729b..5681641baa 100644
--- a/thirdparty/harfbuzz/src/hb-set-digest.hh
+++ b/thirdparty/harfbuzz/src/hb-set-digest.hh
@@ -88,14 +88,19 @@ struct hb_set_digest_bits_pattern_t
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{
+ if (mask == (mask_t) -1) return false;
if ((b >> shift) - (a >> shift) >= mask_bits - 1)
+ {
mask = (mask_t) -1;
- else {
+ return false;
+ }
+ else
+ {
mask_t ma = mask_for (a);
mask_t mb = mask_for (b);
mask |= mb + (mb - ma) - (mb < ma);
+ return true;
}
- return true;
}
template <typename T>
@@ -154,8 +159,7 @@ struct hb_set_digest_combiner_t
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{
- return head.add_range (a, b) &&
- tail.add_range (a, b);
+ return (int) head.add_range (a, b) | (int) tail.add_range (a, b);
}
template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
diff --git a/thirdparty/harfbuzz/src/hb-set.h b/thirdparty/harfbuzz/src/hb-set.h
index de53231030..192abf6f63 100644
--- a/thirdparty/harfbuzz/src/hb-set.h
+++ b/thirdparty/harfbuzz/src/hb-set.h
@@ -43,7 +43,7 @@ HB_BEGIN_DECLS
*
* Since: 0.9.21
*/
-#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+#define HB_SET_VALUE_INVALID HB_CODEPOINT_INVALID
/**
* hb_set_t:
diff --git a/thirdparty/harfbuzz/src/hb-set.hh b/thirdparty/harfbuzz/src/hb-set.hh
index 604802381b..7d1c941e4d 100644
--- a/thirdparty/harfbuzz/src/hb-set.hh
+++ b/thirdparty/harfbuzz/src/hb-set.hh
@@ -115,7 +115,7 @@ struct hb_sparseset_t
/* Sink interface. */
hb_sparseset_t& operator << (hb_codepoint_t v)
{ add (v); return *this; }
- hb_sparseset_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+ hb_sparseset_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -174,7 +174,7 @@ struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t>
hb_set_t& operator << (hb_codepoint_t v)
{ sparseset::operator<< (v); return *this; }
- hb_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+ hb_set_t& operator << (const hb_codepoint_pair_t& range)
{ sparseset::operator<< (range); return *this; }
};
diff --git a/thirdparty/harfbuzz/src/hb-shape.cc b/thirdparty/harfbuzz/src/hb-shape.cc
index d9598fc704..844f7b9e80 100644
--- a/thirdparty/harfbuzz/src/hb-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-shape.cc
@@ -220,7 +220,7 @@ reset_buffer (hb_buffer_t *buffer,
assert (buffer->ensure (text.length));
buffer->have_positions = false;
buffer->len = text.length;
- memcpy (buffer->info, text.arrayZ, text.length * sizeof (buffer->info[0]));
+ hb_memcpy (buffer->info, text.arrayZ, text.length * sizeof (buffer->info[0]));
hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
}
diff --git a/thirdparty/harfbuzz/src/hb-shaper-list.hh b/thirdparty/harfbuzz/src/hb-shaper-list.hh
index 4158b7094c..f079caf4d3 100644
--- a/thirdparty/harfbuzz/src/hb-shaper-list.hh
+++ b/thirdparty/harfbuzz/src/hb-shaper-list.hh
@@ -33,6 +33,11 @@
/* v--- Add new shapers in the right place here. */
+#ifdef HAVE_WASM
+/* Only picks up fonts that have a "Wasm" table. */
+HB_SHAPER_IMPLEMENT (wasm)
+#endif
+
#ifdef HAVE_GRAPHITE2
/* Only picks up fonts that have a "Silf" table. */
HB_SHAPER_IMPLEMENT (graphite2)
diff --git a/thirdparty/harfbuzz/src/hb-static.cc b/thirdparty/harfbuzz/src/hb-static.cc
index a1a2522edf..c9bd0a61bf 100644
--- a/thirdparty/harfbuzz/src/hb-static.cc
+++ b/thirdparty/harfbuzz/src/hb-static.cc
@@ -31,6 +31,7 @@
#include "hb-aat-layout-common.hh"
#include "hb-aat-layout-feat-table.hh"
+#include "hb-cff-interp-common.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-cmap-table.hh"
#include "OT/Color/COLR/COLR.hh"
@@ -58,6 +59,8 @@ DEFINE_NULL_NAMESPACE_BYTES (AAT, Lookup) = {0xFF,0xFF};
/* hb_map_t */
const hb_codepoint_t minus_1 = -1;
+static const unsigned char static_endchar_str[] = {OpCode_endchar};
+const unsigned char *endchar_str = static_endchar_str;
/* hb_face_t */
diff --git a/thirdparty/harfbuzz/src/hb-subset-accelerator.hh b/thirdparty/harfbuzz/src/hb-subset-accelerator.hh
index bb7c62d064..9258383d28 100644
--- a/thirdparty/harfbuzz/src/hb-subset-accelerator.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-accelerator.hh
@@ -42,7 +42,9 @@ struct cff_subset_accelerator_t;
namespace OT {
struct SubtableUnicodesCache;
-};
+struct cff1_subset_accelerator_t;
+struct cff2_subset_accelerator_t;
+}
struct hb_subset_accelerator_t
{
@@ -51,8 +53,8 @@ struct hb_subset_accelerator_t
return &_hb_subset_accelerator_user_data_key;
}
- static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_,
- const hb_multimap_t gid_to_unicodes_,
+ static hb_subset_accelerator_t* create(hb_face_t *source,
+ const hb_map_t& unicode_to_gid_,
const hb_set_t& unicodes_,
bool has_seac_) {
hb_subset_accelerator_t* accel =
@@ -60,8 +62,8 @@ struct hb_subset_accelerator_t
if (unlikely (!accel)) return accel;
- new (accel) hb_subset_accelerator_t (unicode_to_gid_,
- gid_to_unicodes_,
+ new (accel) hb_subset_accelerator_t (source,
+ unicode_to_gid_,
unicodes_,
has_seac_);
@@ -79,36 +81,36 @@ struct hb_subset_accelerator_t
hb_free (accel);
}
- hb_subset_accelerator_t (const hb_map_t& unicode_to_gid_,
- const hb_multimap_t& gid_to_unicodes_,
+ hb_subset_accelerator_t (hb_face_t *source,
+ const hb_map_t& unicode_to_gid_,
const hb_set_t& unicodes_,
bool has_seac_) :
unicode_to_gid(unicode_to_gid_),
- gid_to_unicodes (gid_to_unicodes_),
unicodes(unicodes_),
cmap_cache(nullptr),
destroy_cmap_cache(nullptr),
has_seac(has_seac_),
- cff_accelerator(nullptr),
- destroy_cff_accelerator(nullptr) {}
-
- ~hb_subset_accelerator_t ()
+ source(hb_face_reference (source))
{
- if (cff_accelerator && destroy_cff_accelerator)
- destroy_cff_accelerator ((void*) cff_accelerator);
-
- if (cmap_cache && destroy_cmap_cache)
- destroy_cmap_cache ((void*) cmap_cache);
+ gid_to_unicodes.alloc (unicode_to_gid.get_population ());
+ for (const auto &_ : unicode_to_gid)
+ {
+ auto unicode = _.first;
+ auto gid = _.second;
+ gid_to_unicodes.add (gid, unicode);
+ }
}
+ HB_INTERNAL ~hb_subset_accelerator_t ();
+
// Generic
mutable hb_mutex_t sanitized_table_cache_lock;
mutable hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>> sanitized_table_cache;
- const hb_map_t unicode_to_gid;
- const hb_multimap_t gid_to_unicodes;
- const hb_set_t unicodes;
+ hb_map_t unicode_to_gid;
+ hb_multimap_t gid_to_unicodes;
+ hb_set_t unicodes;
// cmap
const OT::SubtableUnicodesCache* cmap_cache;
@@ -116,8 +118,6 @@ struct hb_subset_accelerator_t
// CFF
bool has_seac;
- const CFF::cff_subset_accelerator_t* cff_accelerator;
- hb_destroy_func_t destroy_cff_accelerator;
// TODO(garretrieger): cumulative glyf checksum map
@@ -128,6 +128,13 @@ struct hb_subset_accelerator_t
unicodes.in_error () ||
sanitized_table_cache.in_error ();
}
+
+ hb_face_t *source;
+#ifndef HB_NO_SUBSET_CFF
+ // These have to be immediately after source:
+ mutable hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel;
+ mutable hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel;
+#endif
};
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff-common.cc b/thirdparty/harfbuzz/src/hb-subset-cff-common.cc
index 6e1b6f713d..5e4ea5fe7c 100644
--- a/thirdparty/harfbuzz/src/hb-subset-cff-common.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-cff-common.cc
@@ -68,24 +68,35 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
/* use hb_set to determine the subset of font dicts */
hb_set_t set;
hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
- for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
+ hb_pair_t<unsigned, hb_codepoint_t> last_range {0, 0};
+ auto it = hb_iter (plan->new_to_old_gid_list);
+ auto _ = *it;
+ for (hb_codepoint_t gid = 0; gid < subset_num_glyphs; gid++)
{
- hb_codepoint_t glyph;
- hb_codepoint_t fd;
- if (!plan->old_gid_for_new_gid (i, &glyph))
+ hb_codepoint_t old_glyph;
+ if (gid == _.first)
+ {
+ old_glyph = _.second;
+ _ = *++it;
+ }
+ else
{
/* fonttools retains FDSelect & font dicts for missing glyphs. do the same */
- glyph = i;
+ old_glyph = gid;
}
- fd = src.get_fd (glyph);
- set.add (fd);
+ if (old_glyph >= last_range.second)
+ last_range = src.get_fd_range (old_glyph);
+ unsigned fd = last_range.first;
if (fd != prev_fd)
{
+ set.add (fd);
num_ranges++;
prev_fd = fd;
- code_pair_t pair = { fd, i };
- fdselect_ranges.push (pair);
+ fdselect_ranges.push (code_pair_t { fd, gid });
+
+ if (gid == old_glyph)
+ gid = hb_min (_.first - 1, last_range.second - 1);
}
}
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh
index ff50b0e518..f54792648d 100644
--- a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh
@@ -480,6 +480,7 @@ struct cff_subset_accelerator_t
const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) {
cff_subset_accelerator_t* accel =
(cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t));
+ if (unlikely (!accel)) return nullptr;
new (accel) cff_subset_accelerator_t (original_blob,
parsed_charstrings,
parsed_global_subrs,
@@ -510,15 +511,21 @@ struct cff_subset_accelerator_t
original_blob = hb_blob_reference (original_blob_);
}
- ~cff_subset_accelerator_t() {
+ ~cff_subset_accelerator_t()
+ {
hb_blob_destroy (original_blob);
- hb_map_destroy (glyph_to_sid_map.get_relaxed ());
+ auto *mapping = glyph_to_sid_map.get_relaxed ();
+ if (mapping)
+ {
+ mapping->~glyph_to_sid_map_t ();
+ hb_free (mapping);
+ }
}
parsed_cs_str_vec_t parsed_charstrings;
parsed_cs_str_vec_t parsed_global_subrs;
hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
- mutable hb_atomic_ptr_t<hb_map_t> glyph_to_sid_map = nullptr;
+ mutable hb_atomic_ptr_t<glyph_to_sid_map_t> glyph_to_sid_map;
private:
hb_blob_t* original_blob;
@@ -600,9 +607,8 @@ struct subr_remap_t : hb_inc_bimap_t
* no optimization based on usage counts. fonttools doesn't appear doing that either.
*/
- resize (closure->get_population ());
- hb_codepoint_t old_num = HB_SET_VALUE_INVALID;
- while (hb_set_next (closure, &old_num))
+ alloc (closure->get_population ());
+ for (auto old_num : *closure)
add (old_num);
if (get_population () < 1240)
@@ -672,8 +678,8 @@ struct subr_subsetter_t
{
unsigned fd_count = acc.fdCount;
const cff_subset_accelerator_t* cff_accelerator = nullptr;
- if (plan->accelerator && plan->accelerator->cff_accelerator) {
- cff_accelerator = plan->accelerator->cff_accelerator;
+ if (acc.cff_accelerator) {
+ cff_accelerator = acc.cff_accelerator;
fd_count = cff_accelerator->parsed_local_subrs.length;
}
@@ -709,14 +715,13 @@ struct subr_subsetter_t
}
/* phase 1 & 2 */
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ for (auto _ : plan->new_to_old_gid_list)
{
- hb_codepoint_t glyph;
- if (!plan->old_gid_for_new_gid (i, &glyph))
- continue;
+ hb_codepoint_t new_glyph = _.first;
+ hb_codepoint_t old_glyph = _.second;
- const hb_ubytes_t str = (*acc.charStrings)[glyph];
- unsigned int fd = acc.fdSelect->get_fd (glyph);
+ const hb_ubytes_t str = (*acc.charStrings)[old_glyph];
+ unsigned int fd = acc.fdSelect->get_fd (old_glyph);
if (unlikely (fd >= acc.fdCount))
return false;
@@ -725,9 +730,9 @@ struct subr_subsetter_t
// parsed string already exists in accelerator, copy it and move
// on.
if (cached_charstrings)
- cached_charstrings[i] = &cff_accelerator->parsed_charstrings[glyph];
+ cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph];
else
- parsed_charstrings[i] = cff_accelerator->parsed_charstrings[glyph];
+ parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph];
continue;
}
@@ -735,8 +740,8 @@ struct subr_subsetter_t
ENV env (str, acc, fd);
cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
- parsed_charstrings[i].alloc (str.length);
- subr_subset_param_t param (&parsed_charstrings[i],
+ parsed_charstrings[new_glyph].alloc (str.length);
+ subr_subset_param_t param (&parsed_charstrings[new_glyph],
&parsed_global_subrs_storage,
&parsed_local_subrs_storage[fd],
&closures.global_closure,
@@ -747,12 +752,12 @@ struct subr_subsetter_t
return false;
/* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
- SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
+ SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]);
/* mark hint ops and arguments for drop */
if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator)
{
- subr_subset_param_t param (&parsed_charstrings[i],
+ subr_subset_param_t param (&parsed_charstrings[new_glyph],
&parsed_global_subrs_storage,
&parsed_local_subrs_storage[fd],
&closures.global_closure,
@@ -760,11 +765,11 @@ struct subr_subsetter_t
plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
drop_hints_param_t drop;
- if (drop_hints_in_str (parsed_charstrings[i], param, drop))
+ if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop))
{
- parsed_charstrings[i].set_hint_dropped ();
+ parsed_charstrings[new_glyph].set_hint_dropped ();
if (drop.vsindex_dropped)
- parsed_charstrings[i].set_vsindex_dropped ();
+ parsed_charstrings[new_glyph].set_vsindex_dropped ();
}
}
@@ -774,7 +779,7 @@ struct subr_subsetter_t
* The compacting both saves memory and makes further operations
* faster.
*/
- parsed_charstrings[i].compact ();
+ parsed_charstrings[new_glyph].compact ();
}
/* Since parsed strings were loaded from accelerator, we still need
@@ -797,23 +802,40 @@ struct subr_subsetter_t
bool encode_charstrings (str_buff_vec_t &buffArray, bool encode_prefix = true) const
{
- if (unlikely (!buffArray.resize_exact (plan->num_output_glyphs ())))
+ unsigned num_glyphs = plan->num_output_glyphs ();
+ if (unlikely (!buffArray.resize_exact (num_glyphs)))
return false;
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ hb_codepoint_t last = 0;
+ for (auto _ : plan->new_to_old_gid_list)
{
- hb_codepoint_t glyph;
- if (!plan->old_gid_for_new_gid (i, &glyph))
- {
- /* add an endchar only charstring for a missing glyph if CFF1 */
- if (endchar_op != OpCode_Invalid) buffArray.arrayZ[i].push (endchar_op);
- continue;
- }
- unsigned int fd = acc.fdSelect->get_fd (glyph);
+ hb_codepoint_t gid = _.first;
+ hb_codepoint_t old_glyph = _.second;
+
+ if (endchar_op != OpCode_Invalid)
+ for (; last < gid; last++)
+ {
+ // Hack to point vector to static string.
+ auto &b = buffArray.arrayZ[last];
+ b.length = 1;
+ b.arrayZ = const_cast<unsigned char *>(endchar_str);
+ }
+
+ last++; // Skip over gid
+ unsigned int fd = acc.fdSelect->get_fd (old_glyph);
if (unlikely (fd >= acc.fdCount))
return false;
- if (unlikely (!encode_str (get_parsed_charstring (i), fd, buffArray.arrayZ[i], encode_prefix)))
+ if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix)))
return false;
}
+ if (endchar_op != OpCode_Invalid)
+ for (; last < num_glyphs; last++)
+ {
+ // Hack to point vector to static string.
+ auto &b = buffArray.arrayZ[last];
+ b.length = 1;
+ b.arrayZ = const_cast<unsigned char *>(endchar_str);
+ }
+
return true;
}
@@ -980,24 +1002,23 @@ struct subr_subsetter_t
const hb_vector_t<parsed_cs_str_vec_t>& local_subrs)
{
closures.reset ();
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ for (auto _ : plan->new_to_old_gid_list)
{
- hb_codepoint_t glyph;
- if (!plan->old_gid_for_new_gid (i, &glyph))
- continue;
- unsigned int fd = acc.fdSelect->get_fd (glyph);
+ hb_codepoint_t new_glyph = _.first;
+ hb_codepoint_t old_glyph = _.second;
+ unsigned int fd = acc.fdSelect->get_fd (old_glyph);
if (unlikely (fd >= acc.fdCount))
return false;
// Note: const cast is safe here because the collect_subr_refs_in_str only performs a
// closure and does not modify any of the charstrings.
- subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (i)),
+ subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)),
const_cast<parsed_cs_str_vec_t*> (&global_subrs),
const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
&closures.global_closure,
&closures.local_closures[fd],
plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
- collect_subr_refs_in_str (get_parsed_charstring (i), param);
+ collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param);
}
return true;
@@ -1105,14 +1126,11 @@ struct subr_subsetter_t
compact_parsed_subrs ();
- plan->inprogress_accelerator->cff_accelerator =
+ acc.cff_accelerator =
cff_subset_accelerator_t::create(acc.blob,
parsed_charstrings,
parsed_global_subrs_storage,
parsed_local_subrs_storage);
- plan->inprogress_accelerator->destroy_cff_accelerator =
- cff_subset_accelerator_t::destroy;
-
}
const parsed_cs_str_t& get_parsed_charstring (unsigned i) const
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff1.cc b/thirdparty/harfbuzz/src/hb-subset-cff1.cc
index 1d7ed6444a..e80d18d097 100644
--- a/thirdparty/harfbuzz/src/hb-subset-cff1.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-cff1.cc
@@ -32,36 +32,59 @@
#include "hb-ot-cff1-table.hh"
#include "hb-set.h"
#include "hb-bimap.hh"
-#include "hb-subset-cff1.hh"
#include "hb-subset-plan.hh"
#include "hb-subset-cff-common.hh"
#include "hb-cff1-interp-cs.hh"
using namespace CFF;
-struct remap_sid_t : hb_inc_bimap_t
+struct remap_sid_t
{
+ unsigned get_population () const { return vector.length; }
+
+ void alloc (unsigned size)
+ {
+ map.alloc (size);
+ vector.alloc (size, true);
+ }
+
+ bool in_error () const
+ { return map.in_error () || vector.in_error (); }
+
unsigned int add (unsigned int sid)
{
- if ((sid != CFF_UNDEF_SID) && !is_std_std (sid))
- return offset_sid (hb_inc_bimap_t::add (unoffset_sid (sid)));
- else
+ if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
return sid;
+
+ sid = unoffset_sid (sid);
+ unsigned v = next;
+ if (map.set (sid, v, false))
+ {
+ vector.push (sid);
+ next++;
+ }
+ else
+ v = map.get (sid); // already exists
+ return offset_sid (v);
}
unsigned int operator[] (unsigned int sid) const
{
- if (is_std_std (sid) || (sid == CFF_UNDEF_SID))
+ if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
return sid;
- else
- return offset_sid (get (unoffset_sid (sid)));
+
+ return offset_sid (map.get (unoffset_sid (sid)));
}
static const unsigned int num_std_strings = 391;
- static bool is_std_std (unsigned int sid) { return sid < num_std_strings; }
+ static bool is_std_str (unsigned int sid) { return sid < num_std_strings; }
static unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; }
static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
+ unsigned next = 0;
+
+ hb_map_t map;
+ hb_vector_t<unsigned> vector;
};
struct cff1_sub_table_info_t : cff_sub_table_info_t
@@ -271,16 +294,17 @@ struct range_list_t : hb_vector_t<code_pair_t>
/* replace the first glyph ID in the "glyph" field each range with a nLeft value */
bool complete (unsigned int last_glyph)
{
- bool two_byte = false;
+ hb_codepoint_t all_glyphs = 0;
unsigned count = this->length;
for (unsigned int i = count; i; i--)
{
code_pair_t &pair = arrayZ[i - 1];
unsigned int nLeft = last_glyph - pair.glyph - 1;
- two_byte |= nLeft >= 0x100;
+ all_glyphs |= nLeft;
last_glyph = pair.glyph;
pair.glyph = nLeft;
}
+ bool two_byte = all_glyphs >= 0x100;
return two_byte;
}
};
@@ -391,8 +415,10 @@ struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs
}
};
-struct cff_subset_plan {
- cff_subset_plan ()
+namespace OT {
+struct cff1_subset_plan
+{
+ cff1_subset_plan ()
{
for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
topDictModSIDs[i] = CFF_UNDEF_SID;
@@ -402,7 +428,7 @@ struct cff_subset_plan {
{
const Encoding *encoding = acc.encoding;
unsigned int size0, size1;
- hb_codepoint_t code, last_code = CFF_UNDEF_CODE;
+ unsigned code, last_code = CFF_UNDEF_CODE - 1;
hb_vector_t<hb_codepoint_t> supp_codes;
if (unlikely (!subset_enc_code_ranges.resize (0)))
@@ -413,39 +439,42 @@ struct cff_subset_plan {
supp_codes.init ();
+ code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
subset_enc_num_codes = plan->num_output_glyphs () - 1;
unsigned int glyph;
- for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
+ auto it = hb_iter (plan->new_to_old_gid_list);
+ if (it->first == 0) it++;
+ auto _ = *it;
+ for (glyph = 1; glyph < num_glyphs; glyph++)
{
- hb_codepoint_t old_glyph;
- if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+ hb_codepoint_t old_glyph;
+ if (glyph == _.first)
+ {
+ old_glyph = _.second;
+ _ = *++it;
+ }
+ else
{
- /* Retain the code for the old missing glyph ID */
+ /* Retain the SID for the old missing glyph ID */
old_glyph = glyph;
}
- code = acc.glyph_to_code (old_glyph);
+ code = acc.glyph_to_code (old_glyph, &glyph_to_sid_cache);
if (code == CFF_UNDEF_CODE)
{
subset_enc_num_codes = glyph - 1;
break;
}
- if ((last_code == CFF_UNDEF_CODE) || (code != last_code + 1))
- {
- code_pair_t pair = { code, glyph };
- subset_enc_code_ranges.push (pair);
- }
+ if (code != last_code + 1)
+ subset_enc_code_ranges.push (code_pair_t {code, glyph});
last_code = code;
if (encoding != &Null (Encoding))
{
- hb_codepoint_t sid = acc.glyph_to_sid (old_glyph);
+ hb_codepoint_t sid = acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
encoding->get_supplement_codes (sid, supp_codes);
for (unsigned int i = 0; i < supp_codes.length; i++)
- {
- code_pair_t pair = { supp_codes[i], sid };
- subset_enc_supp_codes.push (pair);
- }
+ subset_enc_supp_codes.push (code_pair_t {supp_codes[i], sid});
}
}
supp_codes.fini ();
@@ -462,65 +491,95 @@ struct cff_subset_plan {
subset_enc_format = 1;
}
- void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
+ bool plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
{
unsigned int size0, size_ranges;
- hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE;
+ unsigned last_sid = CFF_UNDEF_CODE - 1;
if (unlikely (!subset_charset_ranges.resize (0)))
{
plan->check_success (false);
- return;
+ return false;
}
- hb_map_t *glyph_to_sid_map = (plan->accelerator && plan->accelerator->cff_accelerator) ?
- plan->accelerator->cff_accelerator->glyph_to_sid_map :
- nullptr;
+ code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
+
+ unsigned num_glyphs = plan->num_output_glyphs ();
+
+ if (unlikely (!subset_charset_ranges.alloc (hb_min (num_glyphs,
+ acc.num_charset_entries))))
+ {
+ plan->check_success (false);
+ return false;
+ }
+
+ glyph_to_sid_map_t *glyph_to_sid_map = acc.cff_accelerator ?
+ acc.cff_accelerator->glyph_to_sid_map.get_acquire () :
+ nullptr;
bool created_map = false;
- if (!glyph_to_sid_map &&
- ((plan->accelerator && plan->accelerator->cff_accelerator) ||
- plan->num_output_glyphs () > plan->source->get_num_glyphs () / 8.))
+ if (!glyph_to_sid_map && acc.cff_accelerator)
{
created_map = true;
glyph_to_sid_map = acc.create_glyph_to_sid_map ();
}
- unsigned int glyph;
- for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
+ auto it = hb_iter (plan->new_to_old_gid_list);
+ if (it->first == 0) it++;
+ auto _ = *it;
+ bool not_is_cid = !acc.is_CID ();
+ bool skip = !not_is_cid && glyph_to_sid_map;
+ if (not_is_cid)
+ sidmap.alloc (num_glyphs);
+ for (hb_codepoint_t glyph = 1; glyph < num_glyphs; glyph++)
{
- hb_codepoint_t old_glyph;
- if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+ hb_codepoint_t old_glyph;
+ if (glyph == _.first)
+ {
+ old_glyph = _.second;
+ _ = *++it;
+ }
+ else
{
/* Retain the SID for the old missing glyph ID */
old_glyph = glyph;
}
- sid = glyph_to_sid_map ? glyph_to_sid_map->get (old_glyph) : acc.glyph_to_sid (old_glyph);
+ unsigned sid = glyph_to_sid_map ?
+ glyph_to_sid_map->arrayZ[old_glyph].code :
+ acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
- if (!acc.is_CID ())
+ if (not_is_cid)
sid = sidmap.add (sid);
- if ((last_sid == CFF_UNDEF_CODE) || (sid != last_sid + 1))
+ if (sid != last_sid + 1)
{
- code_pair_t pair = { sid, glyph };
- subset_charset_ranges.push (pair);
+ subset_charset_ranges.push (code_pair_t {sid, glyph});
+
+ if (glyph == old_glyph && skip)
+ {
+ glyph = hb_min (_.first - 1, glyph_to_sid_map->arrayZ[old_glyph].glyph);
+ sid += glyph - old_glyph;
+ }
}
last_sid = sid;
}
if (created_map)
{
- if (!(plan->accelerator && plan->accelerator->cff_accelerator) ||
- !plan->accelerator->cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map))
- hb_map_destroy (glyph_to_sid_map);
+ if ((!plan->accelerator && acc.cff_accelerator) ||
+ !acc.cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map))
+ {
+ glyph_to_sid_map->~glyph_to_sid_map_t ();
+ hb_free (glyph_to_sid_map);
+ }
}
- bool two_byte = subset_charset_ranges.complete (glyph);
+ bool two_byte = subset_charset_ranges.complete (num_glyphs);
- size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1);
+ size0 = Charset0::get_size (plan->num_output_glyphs ());
if (!two_byte)
- size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
+ size_ranges = Charset1::get_size_for_ranges (subset_charset_ranges.length);
else
- size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.length;
+ size_ranges = Charset2::get_size_for_ranges (subset_charset_ranges.length);
if (size0 < size_ranges)
subset_charset_format = 0;
@@ -528,19 +587,18 @@ struct cff_subset_plan {
subset_charset_format = 1;
else
subset_charset_format = 2;
+
+ return true;
}
bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
{
- sidmap.reset ();
-
for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
{
unsigned int sid = acc.topDict.nameSIDs[i];
if (sid != CFF_UNDEF_SID)
{
- (void)sidmap.add (sid);
- topDictModSIDs[i] = sidmap[sid];
+ topDictModSIDs[i] = sidmap.add (sid);
}
}
@@ -564,19 +622,18 @@ struct cff_subset_plan {
drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
- /* check whether the subset renumbers any glyph IDs */
- gid_renum = false;
- for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++)
- {
- if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph))
- continue;
- if (new_glyph != old_glyph) {
- gid_renum = true;
- break;
+ subset_charset = !acc.is_predef_charset ();
+ if (!subset_charset)
+ /* check whether the subset renumbers any glyph IDs */
+ for (const auto &_ : plan->new_to_old_gid_list)
+ {
+ if (_.first != _.second)
+ {
+ subset_charset = true;
+ break;
+ }
}
- }
- subset_charset = gid_renum || !acc.is_predef_charset ();
subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
/* top dict INDEX */
@@ -618,7 +675,8 @@ struct cff_subset_plan {
if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */
return false;
- if (subset_charset) plan_subset_charset (acc, plan);
+ if (subset_charset && !plan_subset_charset (acc, plan))
+ return false;
topdict_mod.reassignSIDs (sidmap);
}
@@ -682,8 +740,9 @@ struct cff_subset_plan {
;
}
- return ((subset_charstrings.length == plan->num_output_glyphs ())
- && (fontdicts_mod.length == subset_fdcount));
+ return !plan->in_error () &&
+ (subset_charstrings.length == plan->num_output_glyphs ()) &&
+ (fontdicts_mod.length == subset_fdcount);
}
cff1_top_dict_values_mod_t topdict_mod;
@@ -722,24 +781,22 @@ struct cff_subset_plan {
bool desubroutinize = false;
};
+} // namespace OT
-static bool _serialize_cff1 (hb_serialize_context_t *c,
- cff_subset_plan &plan,
- const OT::cff1::accelerator_subset_t &acc,
- unsigned int num_glyphs)
+bool
+OT::cff1::accelerator_subset_t::serialize (hb_serialize_context_t *c,
+ struct OT::cff1_subset_plan &plan) const
{
/* private dicts & local subrs */
- for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
+ for (int i = (int) privateDicts.length; --i >= 0 ;)
{
if (plan.fdmap.has (i))
{
objidx_t subrs_link = 0;
if (plan.subset_localsubrs[i].length > 0)
{
- CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
- if (unlikely (!dest)) return false;
- c->push ();
- if (likely (dest && dest->serialize (c, plan.subset_localsubrs[i])))
+ auto *dest = c->push <CFF1Subrs> ();
+ if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
subrs_link = c->pop_pack ();
else
{
@@ -748,12 +805,10 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
}
}
- PrivateDict *pd = c->start_embed<PrivateDict> ();
- if (unlikely (!pd)) return false;
- c->push ();
+ auto *pd = c->push<PrivateDict> ();
cff1_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
- if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link)))
+ if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link)))
{
unsigned fd = plan.fdmap[i];
plan.fontdicts_mod[fd].privateDictInfo.size = c->length ();
@@ -767,21 +822,20 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
}
}
- if (!acc.is_CID ())
+ if (!is_CID ())
plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo;
/* CharStrings */
{
c->push<CFF1CharStrings> ();
- unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings);
+ unsigned data_size = 0;
+ unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings, &data_size);
if (unlikely (!c->start_zerocopy (total_size)))
return false;
- CFF1CharStrings *cs = c->start_embed<CFF1CharStrings> ();
- if (unlikely (!cs)) return false;
-
- if (likely (cs->serialize (c, plan.subset_charstrings)))
+ auto *cs = c->start_embed<CFF1CharStrings> ();
+ if (likely (cs->serialize (c, plan.subset_charstrings, &data_size)))
plan.info.char_strings_link = c->pop_pack (false);
else
{
@@ -791,11 +845,9 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
}
/* FDArray (FD Index) */
- if (acc.fdArray != &Null (CFF1FDArray))
+ if (fdArray != &Null (CFF1FDArray))
{
- CFF1FDArray *fda = c->start_embed<CFF1FDArray> ();
- if (unlikely (!fda)) return false;
- c->push ();
+ auto *fda = c->push<CFF1FDArray> ();
cff1_font_dict_op_serializer_t fontSzr;
auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod));
if (likely (fda->serialize (c, it, fontSzr)))
@@ -808,10 +860,10 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
}
/* FDSelect */
- if (acc.fdSelect != &Null (CFF1FDSelect))
+ if (fdSelect != &Null (CFF1FDSelect))
{
c->push ();
- if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount,
+ if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *fdSelect, fdCount,
plan.subset_fdselect_format, plan.info.fd_select.size,
plan.subset_fdselect_ranges)))
plan.info.fd_select.link = c->pop_pack ();
@@ -825,9 +877,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* Charset */
if (plan.subset_charset)
{
- Charset *dest = c->start_embed<Charset> ();
- if (unlikely (!dest)) return false;
- c->push ();
+ auto *dest = c->push<Charset> ();
if (likely (dest->serialize (c,
plan.subset_charset_format,
plan.num_glyphs,
@@ -843,9 +893,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* Encoding */
if (plan.subset_encoding)
{
- Encoding *dest = c->start_embed<Encoding> ();
- if (unlikely (!dest)) return false;
- c->push ();
+ auto *dest = c->push<Encoding> ();
if (likely (dest->serialize (c,
plan.subset_enc_format,
plan.subset_enc_num_codes,
@@ -861,9 +909,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* global subrs */
{
- c->push ();
- CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
- if (unlikely (!dest)) return false;
+ auto *dest = c->push <CFF1Subrs> ();
if (likely (dest->serialize (c, plan.subset_globalsubrs)))
c->pop_pack (false);
else
@@ -875,10 +921,9 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* String INDEX */
{
- CFF1StringIndex *dest = c->start_embed<CFF1StringIndex> ();
- if (unlikely (!dest)) return false;
- c->push ();
- if (likely (dest->serialize (c, *acc.stringIndex, plan.sidmap)))
+ auto *dest = c->push<CFF1StringIndex> ();
+ if (likely (!plan.sidmap.in_error () &&
+ dest->serialize (c, *stringIndex, plan.sidmap.vector)))
c->pop_pack ();
else
{
@@ -898,14 +943,12 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
cff->offSize = 4; /* unused? */
/* name INDEX */
- if (unlikely (!(*acc.nameIndex).copy (c))) return false;
+ if (unlikely (!c->embed (*nameIndex))) return false;
/* top dict INDEX */
{
/* serialize singleton TopDict */
- TopDict *top = c->start_embed<TopDict> ();
- if (!top) return false;
- c->push ();
+ auto *top = c->push<TopDict> ();
cff1_top_dict_op_serializer_t topSzr;
unsigned top_size = 0;
top_dict_modifiers_t modifier (plan.info, plan.topDictModSIDs);
@@ -920,36 +963,23 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
return false;
}
/* serialize INDEX header for above */
- CFF1Index *dest = c->start_embed<CFF1Index> ();
- if (!dest) return false;
- return dest->serialize_header (c, hb_iter (hb_array_t<unsigned> (&top_size, 1)));
+ auto *dest = c->start_embed<CFF1Index> ();
+ return dest->serialize_header (c, hb_iter (&top_size, 1), top_size);
}
}
-static bool
-_hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc,
- hb_subset_context_t *c)
+bool
+OT::cff1::accelerator_subset_t::subset (hb_subset_context_t *c) const
{
- cff_subset_plan cff_plan;
+ cff1_subset_plan cff_plan;
- if (unlikely (!cff_plan.create (acc, c->plan)))
+ if (unlikely (!cff_plan.create (*this, c->plan)))
{
DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
return false;
}
- return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ());
-}
-
-bool
-hb_subset_cff1 (hb_subset_context_t *c)
-{
- OT::cff1::accelerator_subset_t acc;
- acc.init (c->plan->source);
- bool result = likely (acc.is_valid ()) && _hb_subset_cff1 (acc, c);
- acc.fini ();
-
- return result;
+ return serialize (c->serializer, cff_plan);
}
diff --git a/thirdparty/harfbuzz/src/hb-subset-cff2.cc b/thirdparty/harfbuzz/src/hb-subset-cff2.cc
index 8ab4620194..3c52fb9c2c 100644
--- a/thirdparty/harfbuzz/src/hb-subset-cff2.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-cff2.cc
@@ -31,7 +31,6 @@
#include "hb-open-type.hh"
#include "hb-ot-cff2-table.hh"
#include "hb-set.h"
-#include "hb-subset-cff2.hh"
#include "hb-subset-plan.hh"
#include "hb-subset-cff-common.hh"
#include "hb-cff2-interp-cs.hh"
@@ -422,11 +421,17 @@ struct cff2_private_dict_op_serializer_t : op_serializer_t
};
+namespace OT {
struct cff2_subset_plan
{
bool create (const OT::cff2::accelerator_subset_t &acc,
hb_subset_plan_t *plan)
{
+ /* make sure notdef is first */
+ hb_codepoint_t old_glyph;
+ if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
+
+ num_glyphs = plan->num_output_glyphs ();
orig_fdcount = acc.fdArray->count;
drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
@@ -489,6 +494,7 @@ struct cff2_subset_plan
cff2_sub_table_info_t info;
+ unsigned int num_glyphs;
unsigned int orig_fdcount = 0;
unsigned int subset_fdcount = 1;
unsigned int subset_fdselect_size = 0;
@@ -505,18 +511,18 @@ struct cff2_subset_plan
bool drop_hints = false;
bool desubroutinize = false;
};
+} // namespace OT
-static bool _serialize_cff2 (hb_serialize_context_t *c,
- cff2_subset_plan &plan,
- const OT::cff2::accelerator_subset_t &acc,
- unsigned int num_glyphs,
- hb_array_t<int> normalized_coords)
+bool
+OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c,
+ struct cff2_subset_plan &plan,
+ hb_array_t<int> normalized_coords) const
{
/* private dicts & local subrs */
hb_vector_t<table_info_t> private_dict_infos;
if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) return false;
- for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
+ for (int i = (int)privateDicts.length; --i >= 0 ;)
{
if (plan.fdmap.has (i))
{
@@ -524,9 +530,7 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
if (plan.subset_localsubrs[i].length > 0)
{
- CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
- if (unlikely (!dest)) return false;
- c->push ();
+ auto *dest = c->push <CFF2Subrs> ();
if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
subrs_link = c->pop_pack (false);
else
@@ -535,12 +539,10 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
return false;
}
}
- PrivateDict *pd = c->start_embed<PrivateDict> ();
- if (unlikely (!pd)) return false;
- c->push ();
+ auto *pd = c->push<PrivateDict> ();
cff2_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints, plan.pinned,
- acc.varStore, normalized_coords);
- if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link)))
+ varStore, normalized_coords);
+ if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link)))
{
unsigned fd = plan.fdmap[i];
private_dict_infos[fd].size = c->length ();
@@ -558,14 +560,13 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
{
c->push ();
- unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings);
+ unsigned data_size = 0;
+ unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings, &data_size);
if (unlikely (!c->start_zerocopy (total_size)))
return false;
- CFF2CharStrings *cs = c->start_embed<CFF2CharStrings> ();
- if (unlikely (!cs)) return false;
-
- if (likely (cs->serialize (c, plan.subset_charstrings)))
+ auto *cs = c->start_embed<CFF2CharStrings> ();
+ if (likely (cs->serialize (c, plan.subset_charstrings, &data_size)))
plan.info.char_strings_link = c->pop_pack (false);
else
{
@@ -575,10 +576,10 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
}
/* FDSelect */
- if (acc.fdSelect != &Null (CFF2FDSelect))
+ if (fdSelect != &Null (CFF2FDSelect))
{
c->push ();
- if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect,
+ if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *(const FDSelect *)fdSelect,
plan.orig_fdcount,
plan.subset_fdselect_format, plan.subset_fdselect_size,
plan.subset_fdselect_ranges)))
@@ -592,27 +593,32 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
/* FDArray (FD Index) */
{
- c->push ();
- CFF2FDArray *fda = c->start_embed<CFF2FDArray> ();
- if (unlikely (!fda)) return false;
+ auto *fda = c->push<CFF2FDArray> ();
cff_font_dict_op_serializer_t fontSzr;
auto it =
- + hb_zip (+ hb_iter (acc.fontDicts)
+ + hb_zip (+ hb_iter (fontDicts)
| hb_filter ([&] (const cff2_font_dict_values_t &_)
- { return plan.fdmap.has (&_ - &acc.fontDicts[0]); }),
+ { return plan.fdmap.has (&_ - &fontDicts[0]); }),
hb_iter (private_dict_infos))
;
- if (unlikely (!fda->serialize (c, it, fontSzr))) return false;
+ if (unlikely (!fda->serialize (c, it, fontSzr)))
+ {
+ c->pop_discard ();
+ return false;
+ }
plan.info.fd_array_link = c->pop_pack (false);
}
/* variation store */
- if (acc.varStore != &Null (CFF2VariationStore) &&
+ if (varStore != &Null (CFF2VariationStore) &&
!plan.pinned)
{
- c->push ();
- CFF2VariationStore *dest = c->start_embed<CFF2VariationStore> ();
- if (unlikely (!dest || !dest->serialize (c, acc.varStore))) return false;
+ auto *dest = c->push<CFF2VariationStore> ();
+ if (unlikely (!dest->serialize (c, varStore)))
+ {
+ c->pop_discard ();
+ return false;
+ }
plan.info.var_store_link = c->pop_pack (false);
}
@@ -628,34 +634,25 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
{
TopDict &dict = cff2 + cff2->topDict;
cff2_top_dict_op_serializer_t topSzr;
- if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.info))) return false;
+ if (unlikely (!dict.serialize (c, topDict, topSzr, plan.info))) return false;
cff2->topDictSize = c->head - (const char *)&dict;
}
/* global subrs */
{
- CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
- if (unlikely (!dest)) return false;
+ auto *dest = c->start_embed <CFF2Subrs> ();
return dest->serialize (c, plan.subset_globalsubrs);
}
}
-static bool
-_hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc,
- hb_subset_context_t *c)
+bool
+OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const
{
cff2_subset_plan cff2_plan;
- if (unlikely (!cff2_plan.create (acc, c->plan))) return false;
- return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs (),
- c->plan->normalized_coords.as_array ());
-}
-
-bool
-hb_subset_cff2 (hb_subset_context_t *c)
-{
- OT::cff2::accelerator_subset_t acc (c->plan->source);
- return acc.is_valid () && _hb_subset_cff2 (acc, c);
+ if (unlikely (!cff2_plan.create (*this, c->plan))) return false;
+ return serialize (c->serializer, cff2_plan,
+ c->plan->normalized_coords.as_array ());
}
#endif
diff --git a/thirdparty/harfbuzz/src/hb-subset-input.cc b/thirdparty/harfbuzz/src/hb-subset-input.cc
index 465af50814..e6b23df704 100644
--- a/thirdparty/harfbuzz/src/hb-subset-input.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-input.cc
@@ -438,7 +438,8 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
return false;
- return input->axes_location.set (axis_tag, axis_info.default_value);
+ float default_val = axis_info.default_value;
+ return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val));
}
/**
@@ -468,8 +469,52 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
return false;
float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value);
- return input->axes_location.set (axis_tag, val);
+ return input->axes_location.set (axis_tag, Triple (val, val, val));
}
+
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_subset_input_set_axis_range: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @face: a #hb_face_t object.
+ * @axis_tag: Tag of the axis
+ * @axis_min_value: Minimum value of the axis variation range to set
+ * @axis_max_value: Maximum value of the axis variation range to set
+ *
+ * Restricting the range of variation on an axis in the given subset input object.
+ * New min/max values will be clamped if they're not within the fvar axis range.
+ * If the fvar axis default value is not within the new range, the new default
+ * value will be changed to the new min or max value, whichever is closer to the fvar
+ * axis default.
+ *
+ * Note: input min value can not be bigger than input max value
+ * Note: currently this API does not support changing axis limits yet.It'd be only
+ * used internally for setting axis limits in the internal data structures
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * XSince: EXPERIMENTAL
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_set_axis_range (hb_subset_input_t *input,
+ hb_face_t *face,
+ hb_tag_t axis_tag,
+ float axis_min_value,
+ float axis_max_value)
+{
+ if (axis_min_value > axis_max_value)
+ return false;
+
+ hb_ot_var_axis_info_t axis_info;
+ if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
+ return false;
+
+ float new_min_val = hb_clamp(axis_min_value, axis_info.min_value, axis_info.max_value);
+ float new_max_val = hb_clamp(axis_max_value, axis_info.min_value, axis_info.max_value);
+ float new_default_val = hb_clamp(axis_info.default_value, new_min_val, new_max_val);
+ return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val));
+}
+#endif
#endif
/**
diff --git a/thirdparty/harfbuzz/src/hb-subset-input.hh b/thirdparty/harfbuzz/src/hb-subset-input.hh
index 1970f795b9..6ae311e613 100644
--- a/thirdparty/harfbuzz/src/hb-subset-input.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-input.hh
@@ -35,6 +35,7 @@
#include "hb-set.hh"
#include "hb-cplusplus.hh"
#include "hb-font.hh"
+#include "hb-subset-instancer-solver.hh"
struct hb_ot_name_record_ids_t
{
@@ -118,7 +119,7 @@ struct hb_subset_input_t
// If set loca format will always be the long version.
bool force_long_loca = false;
- hb_hashmap_t<hb_tag_t, float> axes_location;
+ hb_hashmap_t<hb_tag_t, Triple> axes_location;
hb_map_t glyph_map;
#ifdef HB_EXPERIMENTAL_API
hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> name_table_overrides;
diff --git a/thirdparty/harfbuzz/src/hb-subset-instancer-solver.cc b/thirdparty/harfbuzz/src/hb-subset-instancer-solver.cc
index 7a2735c529..c698d944ce 100644
--- a/thirdparty/harfbuzz/src/hb-subset-instancer-solver.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-instancer-solver.cc
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#include "hb.hh"
+#include "hb-subset-instancer-solver.hh"
/* This file is a straight port of the following:
*
@@ -35,26 +35,6 @@
constexpr static float EPSILON = 1.f / (1 << 14);
constexpr static float MAX_F2DOT14 = float (0x7FFF) / (1 << 14);
-struct Triple {
-
- Triple () :
- minimum (0.f), middle (0.f), maximum (0.f) {}
-
- Triple (float minimum_, float middle_, float maximum_) :
- minimum (minimum_), middle (middle_), maximum (maximum_) {}
-
- bool operator == (const Triple &o) const
- {
- return minimum == o.minimum &&
- middle == o.middle &&
- maximum == o.maximum;
- }
-
- float minimum;
- float middle;
- float maximum;
-};
-
static inline Triple _reverse_negate(const Triple &v)
{ return {-v.maximum, -v.middle, -v.minimum}; }
@@ -82,10 +62,6 @@ static inline float supportScalar (float coord, const Triple &tent)
return (end - coord) / (end - peak);
}
-
-using result_item_t = hb_pair_t<float, Triple>;
-using result_t = hb_vector_t<result_item_t>;
-
static inline result_t
_solve (Triple tent, Triple axisLimit, bool negative = false)
{
@@ -195,9 +171,9 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
if (gain > outGain)
{
// Crossing point on the axis.
- float crossing = peak + ((1 - gain) * (upper - peak) / (1 - outGain));
+ float crossing = peak + (1 - gain) * (upper - peak);
- Triple loc{peak, peak, crossing};
+ Triple loc{axisDef, peak, crossing};
float scalar = 1.f;
// The part before the crossing point.
@@ -213,7 +189,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
if (upper >= axisMax)
{
Triple loc {crossing, axisMax, axisMax};
- float scalar = supportScalar (axisMax, tent);
+ float scalar = outGain;
out.push (hb_pair (scalar - gain, loc));
}
@@ -247,89 +223,83 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// Eternity justify.
Triple loc2 {upper, axisMax, axisMax};
- float scalar2 = 1.f; // supportScalar({"tag": axisMax}, {"tag": tent})
+ float scalar2 = 0.f;
out.push (hb_pair (scalar1 - gain, loc1));
out.push (hb_pair (scalar2 - gain, loc2));
}
}
- /* Case 3: Outermost limit still fits within F2Dot14 bounds;
- * we keep deltas as is and only scale the axes bounds. Deltas beyond -1.0
- * or +1.0 will never be applied as implementations must clamp to that range.
- *
- * A second tent is needed for cases when gain is positive, though we add it
- * unconditionally and it will be dropped because scalar ends up 0.
- *
- * TODO: See if we can just move upper closer to adjust the slope, instead of
- * second tent.
- *
- * | peak |
- * 1.........|............o...|..................
- * | /x\ |
- * | /xxx\ |
- * | /xxxxx\|
- * | /xxxxxxx+
- * | /xxxxxxxx|\
- * 0---|-----|------oxxxxxxxxx|xo---------------1
- * axisMin | lower | upper
- * | |
- * axisDef axisMax
- */
- else if (axisDef + (axisMax - axisDef) * 2 >= upper)
+ else
{
- if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper)
- {
- // we clamp +2.0 to the max F2Dot14 (~1.99994) for convenience
- upper = axisDef + (axisMax - axisDef) * MAX_F2DOT14;
- assert (peak < upper);
- }
-
// Special-case if peak is at axisMax.
if (axisMax == peak)
upper = peak;
- Triple loc1 {hb_max (axisDef, lower), peak, upper};
- float scalar1 = 1.f;
+ /* Case 3:
+ * we keep deltas as is and only scale the axis upper to achieve
+ * the desired new tent if feasible.
+ *
+ * peak
+ * 1.....................o....................
+ * / \_|
+ * ..................../....+_.........outGain
+ * / | \
+ * gain..............+......|..+_.............
+ * /| | | \
+ * 0---|-----------o | | | o----------1
+ * axisMin lower| | | upper
+ * | | newUpper
+ * axisDef axisMax
+ */
+ float newUpper = peak + (1 - gain) * (upper - peak);
+ // I feel like the first condition is always true because
+ // outGain >= gain.
+ if (axisMax <= newUpper && newUpper <= axisDef + (axisMax - axisDef) * 2)
+ {
+ upper = newUpper;
+ if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper)
+ {
+ // we clamp +2.0 to the max F2Dot14 (~1.99994) for convenience
+ upper = axisDef + (axisMax - axisDef) * MAX_F2DOT14;
+ assert (peak < upper);
+ }
- Triple loc2 {peak, upper, upper};
- float scalar2 = 0.f;
+ Triple loc {hb_max (axisDef, lower), peak, upper};
+ float scalar = 1.f;
- // Don't add a dirac delta!
- if (axisDef < upper)
- out.push (hb_pair (scalar1 - gain, loc1));
- if (peak < upper)
- out.push (hb_pair (scalar2 - gain, loc2));
- }
+ out.push (hb_pair (scalar - gain, loc));
+ }
- /* Case 4: New limit doesn't fit; we need to chop into two tents,
- * because the shape of a triangle with part of one side cut off
- * cannot be represented as a triangle itself.
- *
- * | peak |
- * 1.........|......o.|...................
- * | /x\|
- * | |xxy|\_
- * | /xxxy| \_
- * | |xxxxy| \_
- * | /xxxxy| \_
- * 0---|-----|-oxxxxxx| o----------1
- * axisMin | lower | upper
- * | |
- * axisDef axisMax
- */
- else
- {
- Triple loc1 {hb_max (axisDef, lower), peak, axisMax};
- float scalar1 = 1.f;
+ /* Case 4: New limit doesn't fit; we need to chop into two tents,
+ * because the shape of a triangle with part of one side cut off
+ * cannot be represented as a triangle itself.
+ *
+ * | peak |
+ * 1.........|......o.|....................
+ * ..........|...../x\|.............outGain
+ * | |xxy|\_
+ * | /xxxy| \_
+ * | |xxxxy| \_
+ * | /xxxxy| \_
+ * 0---|-----|-oxxxxxx| o----------1
+ * axisMin | lower | upper
+ * | |
+ * axisDef axisMax
+ */
+ else
+ {
+ Triple loc1 {hb_max (axisDef, lower), peak, axisMax};
+ float scalar1 = 1.f;
- Triple loc2 {peak, axisMax, axisMax};
- float scalar2 = supportScalar (axisMax, tent);
+ Triple loc2 {peak, axisMax, axisMax};
+ float scalar2 = outGain;
- out.push (hb_pair (scalar1 - gain, loc1));
- // Don't add a dirac delta!
- if (peak < axisMax)
- out.push (hb_pair (scalar2 - gain, loc2));
+ out.push (hb_pair (scalar1 - gain, loc1));
+ // Don't add a dirac delta!
+ if (peak < axisMax)
+ out.push (hb_pair (scalar2 - gain, loc2));
+ }
}
/* Now, the negative side
@@ -422,19 +392,6 @@ static inline float normalizeValue (float v, const Triple &triple, bool extrapol
}
}
-/* Given a tuple (lower,peak,upper) "tent" and new axis limits
- * (axisMin,axisDefault,axisMax), solves how to represent the tent
- * under the new axis configuration. All values are in normalized
- * -1,0,+1 coordinate system. Tent values can be outside this range.
- *
- * Return value: a list of tuples. Each tuple is of the form
- * (scalar,tent), where scalar is a multipler to multiply any
- * delta-sets by, and tent is a new tent for that output delta-set.
- * If tent value is Triple{}, that is a special deltaset that should
- * be always-enabled (called "gain").
- */
-HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit);
-
result_t
rebase_tent (Triple tent, Triple axisLimit)
{
@@ -460,5 +417,5 @@ rebase_tent (Triple tent, Triple axisLimit)
Triple{n (t.minimum), n (t.middle), n (t.maximum)}));
}
- return sols;
+ return out;
}
diff --git a/thirdparty/harfbuzz/src/hb-subset-instancer-solver.hh b/thirdparty/harfbuzz/src/hb-subset-instancer-solver.hh
new file mode 100644
index 0000000000..b1f8594937
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-subset-instancer-solver.hh
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_SUBSET_INSTANCER_SOLVER_HH
+#define HB_SUBSET_INSTANCER_SOLVER_HH
+
+#include "hb.hh"
+
+struct Triple {
+
+ Triple () :
+ minimum (0.f), middle (0.f), maximum (0.f) {}
+
+ Triple (float minimum_, float middle_, float maximum_) :
+ minimum (minimum_), middle (middle_), maximum (maximum_) {}
+
+ bool operator == (const Triple &o) const
+ {
+ return minimum == o.minimum &&
+ middle == o.middle &&
+ maximum == o.maximum;
+ }
+
+ bool operator != (const Triple o) const
+ { return !(*this == o); }
+
+ bool is_point () const
+ { return minimum == middle && middle == maximum; }
+
+ bool contains (float point) const
+ { return minimum <= point && point <= maximum; }
+
+ /* from hb_array_t hash ()*/
+ uint32_t hash () const
+ {
+ uint32_t current = /*cbf29ce4*/0x84222325;
+ current = current ^ hb_hash (minimum);
+ current = current * 16777619;
+
+ current = current ^ hb_hash (middle);
+ current = current * 16777619;
+
+ current = current ^ hb_hash (maximum);
+ current = current * 16777619;
+ return current;
+ }
+
+ float minimum;
+ float middle;
+ float maximum;
+};
+
+using result_item_t = hb_pair_t<float, Triple>;
+using result_t = hb_vector_t<result_item_t>;
+
+/* Given a tuple (lower,peak,upper) "tent" and new axis limits
+ * (axisMin,axisDefault,axisMax), solves how to represent the tent
+ * under the new axis configuration. All values are in normalized
+ * -1,0,+1 coordinate system. Tent values can be outside this range.
+ *
+ * Return value: a list of tuples. Each tuple is of the form
+ * (scalar,tent), where scalar is a multipler to multiply any
+ * delta-sets by, and tent is a new tent for that output delta-set.
+ * If tent value is Triple{}, that is a special deltaset that should
+ * be always-enabled (called "gain").
+ */
+HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit);
+
+#endif /* HB_SUBSET_INSTANCER_SOLVER_HH */
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan-member-list.hh b/thirdparty/harfbuzz/src/hb-subset-plan-member-list.hh
index acf508c32d..be29e67ecb 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan-member-list.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-plan-member-list.hh
@@ -33,7 +33,9 @@
// For each cp that we'd like to retain maps to the corresponding gid.
HB_SUBSET_PLAN_MEMBER (hb_set_t, unicodes)
-HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t E(<hb_pair_t<hb_codepoint_t, hb_codepoint_t>>), unicode_to_new_gid_list)
+HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t<hb_codepoint_pair_t>, unicode_to_new_gid_list)
+
+HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t<hb_codepoint_pair_t>, new_to_old_gid_list)
// name_ids we would like to retain
HB_SUBSET_PLAN_MEMBER (hb_set_t, name_ids)
@@ -97,12 +99,12 @@ HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, gdef_varstore_inner_maps)
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, hb::unique_ptr<hb_blob_t>>), sanitized_table_cache)
-//normalized axes location map
-HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, int>), axes_location)
+//normalized axes range map
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), axes_location)
HB_SUBSET_PLAN_MEMBER (hb_vector_t<int>, normalized_coords)
-//user specified axes location map
-HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, float>), user_axes_location)
+//user specified axes range map
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), user_axes_location)
//retained old axis index -> new axis index mapping in fvar axis array
HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map)
@@ -115,9 +117,9 @@ HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsi
//vmtx metrics map: new gid->(advance, lsb)
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsigned, int>)>), vmtx_map)
//boundsWidth map: new gid->boundsWidth, boundWidth=xMax - xMin
-HB_SUBSET_PLAN_MEMBER (mutable hb_map_t, bounds_width_map)
+HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_width_vec)
//boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin
-HB_SUBSET_PLAN_MEMBER (mutable hb_map_t, bounds_height_map)
+HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_height_vec)
#ifdef HB_EXPERIMENTAL_API
// name table overrides map: hb_ot_name_record_ids_t-> name string new value or
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc
index 791f92d02d..9a00de3e60 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc
@@ -48,10 +48,24 @@
using OT::Layout::GSUB;
using OT::Layout::GPOS;
+
+hb_subset_accelerator_t::~hb_subset_accelerator_t ()
+{
+ if (cmap_cache && destroy_cmap_cache)
+ destroy_cmap_cache ((void*) cmap_cache);
+
+#ifndef HB_NO_SUBSET_CFF
+ cff1_accel.fini ();
+ cff2_accel.fini ();
+#endif
+ hb_face_destroy (source);
+}
+
+
typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
#ifndef HB_NO_SUBSET_CFF
static inline bool
-_add_cff_seac_components (const OT::cff1::accelerator_t &cff,
+_add_cff_seac_components (const OT::cff1::accelerator_subset_t &cff,
hb_codepoint_t gid,
hb_set_t *gids_to_retain)
{
@@ -135,7 +149,8 @@ static void _collect_layout_indices (hb_subset_plan_t *plan,
hb_set_t *lookup_indices, /* OUT */
hb_set_t *feature_indices, /* OUT */
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
- hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map /* OUT */)
+ hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, /* OUT */
+ bool& insert_catch_all_feature_variation_record)
{
unsigned num_features = table.get_feature_count ();
hb_vector_t<hb_tag_t> features;
@@ -171,8 +186,11 @@ static void _collect_layout_indices (hb_subset_plan_t *plan,
&plan->axes_location,
feature_record_cond_idx_map,
feature_substitutes_map,
+ insert_catch_all_feature_variation_record,
feature_indices,
- true,
+ false,
+ false,
+ false,
0,
&conditionset_map
};
@@ -283,7 +301,8 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
hb_map_t *features,
script_langsys_map *langsys_map,
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
- hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map)
+ hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
+ bool& insert_catch_all_feature_variation_record)
{
hb_blob_ptr_t<T> table = plan->source_table<T> ();
hb_tag_t table_tag = table->tableTag;
@@ -293,7 +312,8 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
&lookup_indices,
&feature_indices,
feature_record_cond_idx_map,
- feature_substitutes_map);
+ feature_substitutes_map,
+ insert_catch_all_feature_variation_record);
if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
hb_ot_layout_lookups_substitute_closure (plan->source,
@@ -329,7 +349,7 @@ _generate_varstore_inner_maps (const hb_set_t& varidx_set,
{
if (varidx_set.is_empty () || subtable_count == 0) return;
- inner_maps.resize (subtable_count);
+ if (unlikely (!inner_maps.resize (subtable_count))) return;
for (unsigned idx : varidx_set)
{
uint16_t major = idx >> 16;
@@ -356,7 +376,7 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan)
{
hb_variation_t var;
var.tag = _.first;
- var.value = _.second;
+ var.value = _.second.middle;
vars.push (var);
}
@@ -541,6 +561,8 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
unicodes->get_population () < cmap_unicodes->get_population () &&
glyphs->get_population () < cmap_unicodes->get_population ())
{
+ plan->codepoint_to_glyph->alloc (unicodes->get_population () + glyphs->get_population ());
+
auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes;
for (hb_codepoint_t gid : *glyphs)
{
@@ -569,6 +591,7 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
}
else
{
+ plan->codepoint_to_glyph->alloc (cmap_unicodes->get_population ());
for (hb_codepoint_t cp : *cmap_unicodes)
{
hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
@@ -581,9 +604,10 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
}
/* Add gids which where requested, but not mapped in cmap */
+ unsigned num_glyphs = plan->source->get_num_glyphs ();
for (hb_codepoint_t gid : *glyphs)
{
- if (gid >= plan->source->get_num_glyphs ())
+ if (gid >= num_glyphs)
break;
plan->_glyphset_gsub.add (gid);
}
@@ -616,7 +640,9 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
if (unlikely (--operation_count < 0)) return operation_count;
- for (auto &item : glyf.glyph_for_gid (gid).get_composite_iterator ())
+ auto glyph = glyf.glyph_for_gid (gid);
+
+ for (auto &item : glyph.get_composite_iterator ())
operation_count =
_glyf_add_gid_and_children (glyf,
item.get_gid (),
@@ -625,7 +651,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
depth);
#ifndef HB_NO_VAR_COMPOSITES
- for (auto &item : glyf.glyph_for_gid (gid).get_var_composite_iterator ())
+ for (auto &item : glyph.get_var_composite_iterator ())
{
operation_count =
_glyf_add_gid_and_children (glyf,
@@ -648,7 +674,7 @@ _nameid_closure (hb_subset_plan_t* plan,
#endif
#ifndef HB_NO_VAR
if (!plan->all_axes_pinned)
- plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
+ plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->axes_old_index_tag_map, &plan->name_ids);
#endif
#ifndef HB_NO_COLOR
if (!drop_tables->has (HB_OT_TAG_CPAL))
@@ -677,7 +703,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
{
OT::glyf_accelerator_t glyf (plan->source);
#ifndef HB_NO_SUBSET_CFF
- OT::cff1::accelerator_t cff (plan->source);
+ // Note: we cannot use inprogress_accelerator here, since it has not been
+ // created yet. So in case of preprocessed-face (and otherwise), we do an
+ // extra sanitize pass here, which is not ideal.
+ OT::cff1::accelerator_subset_t stack_cff (plan->accelerator ? nullptr : plan->source);
+ const OT::cff1::accelerator_subset_t *cff (plan->accelerator ? plan->accelerator->cff1_accel.get () : &stack_cff);
#endif
plan->_glyphset_gsub.add (0); // Not-def
@@ -694,7 +724,8 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
&plan->gsub_features,
&plan->gsub_langsys,
&plan->gsub_feature_record_cond_idx_map,
- &plan->gsub_feature_substitutes_map);
+ &plan->gsub_feature_substitutes_map,
+ plan->gsub_insert_catch_all_feature_variation_rec);
if (!drop_tables->has (HB_OT_TAG_GPOS))
_closure_glyphs_lookups_features<GPOS> (
@@ -704,7 +735,8 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
&plan->gpos_features,
&plan->gpos_langsys,
&plan->gpos_feature_record_cond_idx_map,
- &plan->gpos_feature_substitutes_map);
+ &plan->gpos_feature_substitutes_map,
+ plan->gpos_insert_catch_all_feature_variation_rec);
#endif
_remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ());
@@ -737,9 +769,9 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
if (!plan->accelerator || plan->accelerator->has_seac)
{
bool has_seac = false;
- if (cff.is_valid ())
+ if (cff->is_valid ())
for (hb_codepoint_t gid : cur_glyphset)
- if (_add_cff_seac_components (cff, gid, &plan->_glyphset))
+ if (_add_cff_seac_components (*cff, gid, &plan->_glyphset))
has_seac = true;
plan->has_seac = has_seac;
}
@@ -747,7 +779,6 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
_remove_invalid_gids (&plan->_glyphset, plan->source->get_num_glyphs ());
-
#ifndef HB_NO_VAR
if (!drop_tables->has (HB_OT_TAG_GDEF))
_collect_layout_variation_indices (plan);
@@ -759,10 +790,10 @@ _create_glyph_map_gsub (const hb_set_t* glyph_set_gsub,
const hb_map_t* glyph_map,
hb_map_t* out)
{
+ out->alloc (glyph_set_gsub->get_population ());
+ hb_iter (glyph_set_gsub)
| hb_map ([&] (hb_codepoint_t gid) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid,
- glyph_map->get (gid));
+ return hb_codepoint_pair_t (gid, glyph_map->get (gid));
})
| hb_sink (out)
;
@@ -775,11 +806,13 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face,
const hb_map_t *requested_glyph_map,
hb_map_t *glyph_map, /* OUT */
hb_map_t *reverse_glyph_map, /* OUT */
+ hb_sorted_vector_t<hb_codepoint_pair_t> *new_to_old_gid_list /* OUT */,
unsigned int *num_glyphs /* OUT */)
{
unsigned pop = all_gids_to_retain->get_population ();
- reverse_glyph_map->resize (pop);
- glyph_map->resize (pop);
+ reverse_glyph_map->alloc (pop);
+ glyph_map->alloc (pop);
+ new_to_old_gid_list->alloc (pop);
if (*requested_glyph_map)
{
@@ -803,45 +836,44 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face,
for (auto old_gid : all_gids_to_retain->iter ())
{
if (old_gid == 0) {
- reverse_glyph_map->set(0, 0);
+ new_to_old_gid_list->push (hb_pair<hb_codepoint_t, hb_codepoint_t> (0u, 0u));
continue;
}
hb_codepoint_t* new_gid;
if (!requested_glyph_map->has (old_gid, &new_gid))
{
- remaining.add(old_gid);
+ remaining.add(old_gid);
continue;
}
if (*new_gid > max_glyph)
max_glyph = *new_gid;
- reverse_glyph_map->set (*new_gid, old_gid);
+ new_to_old_gid_list->push (hb_pair (*new_gid, old_gid));
}
+ new_to_old_gid_list->qsort ();
// Anything that wasn't mapped by the requested mapping should
// be placed after the requested mapping.
for (auto old_gid : remaining)
- {
- reverse_glyph_map->set(++max_glyph, old_gid);
- }
+ new_to_old_gid_list->push (hb_pair (++max_glyph, old_gid));
*num_glyphs = max_glyph + 1;
}
else if (!retain_gids)
{
+ hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0)
- | hb_sink (reverse_glyph_map)
+ | hb_sink (new_to_old_gid_list)
;
- *num_glyphs = reverse_glyph_map->get_population ();
+ *num_glyphs = new_to_old_gid_list->length;
}
else
{
+ hb_iter (all_gids_to_retain)
| hb_map ([] (hb_codepoint_t _) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, _);
+ return hb_codepoint_pair_t (_, _);
})
- | hb_sink (reverse_glyph_map)
+ | hb_sink (new_to_old_gid_list)
;
hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID;
@@ -850,8 +882,11 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face,
*num_glyphs = max_glyph + 1;
}
- + reverse_glyph_map->iter ()
- | hb_map (&hb_pair_t<hb_codepoint_t, hb_codepoint_t>::reverse)
+ + hb_iter (new_to_old_gid_list)
+ | hb_sink (reverse_glyph_map)
+ ;
+ + hb_iter (new_to_old_gid_list)
+ | hb_map (&hb_codepoint_pair_t::reverse)
| hb_sink (glyph_map)
;
@@ -884,24 +919,35 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
hb_tag_t axis_tag = axis.get_axis_tag ();
plan->axes_old_index_tag_map.set (old_axis_idx, axis_tag);
- if (!plan->user_axes_location.has (axis_tag))
+ if (!plan->user_axes_location.has (axis_tag) ||
+ !plan->user_axes_location.get (axis_tag).is_point ())
{
axis_not_pinned = true;
plan->axes_index_map.set (old_axis_idx, new_axis_idx);
new_axis_idx++;
}
- else
+
+ if (plan->user_axes_location.has (axis_tag))
{
- int normalized_v = axis.normalize_axis_value (plan->user_axes_location.get (axis_tag));
+ Triple axis_range = plan->user_axes_location.get (axis_tag);
+ int normalized_min = axis.normalize_axis_value (axis_range.minimum);
+ int normalized_default = axis.normalize_axis_value (axis_range.middle);
+ int normalized_max = axis.normalize_axis_value (axis_range.maximum);
+
if (has_avar && old_axis_idx < avar_axis_count)
{
- normalized_v = seg_maps->map (normalized_v);
+ normalized_min = seg_maps->map (normalized_min);
+ normalized_default = seg_maps->map (normalized_default);
+ normalized_max = seg_maps->map (normalized_max);
}
- plan->axes_location.set (axis_tag, normalized_v);
- if (normalized_v != 0)
+ plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min),
+ static_cast<float> (normalized_default),
+ static_cast<float> (normalized_max)));
+
+ if (normalized_default != 0)
plan->pinned_at_default = false;
- plan->normalized_coords[old_axis_idx] = normalized_v;
+ plan->normalized_coords[old_axis_idx] = normalized_default;
}
old_axis_idx++;
@@ -968,7 +1014,7 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
continue;
}
plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
- plan->bounds_width_map.set (new_gid, extents.width);
+ plan->bounds_width_vec[new_gid] = extents.width;
}
if (_vmtx.has_data ())
@@ -985,7 +1031,7 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
continue;
}
plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
- plan->bounds_height_map.set (new_gid, extents.height);
+ plan->bounds_height_vec[new_gid] = extents.height;
}
}
hb_font_destroy (font);
@@ -1018,6 +1064,8 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
glyph_map = hb_map_create ();
reverse_glyph_map = hb_map_create ();
+ gsub_insert_catch_all_feature_variation_rec = false;
+ gpos_insert_catch_all_feature_variation_rec = false;
gdef_varstore_inner_maps.init ();
user_axes_location = input->axes_location;
@@ -1065,6 +1113,7 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
&input->glyph_map,
glyph_map,
reverse_glyph_map,
+ &new_to_old_gid_list,
&_num_output_glyphs))) {
return;
}
@@ -1082,6 +1131,13 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second);
}
+ bounds_width_vec.resize (_num_output_glyphs, false);
+ for (auto &v : bounds_width_vec)
+ v = 0xFFFFFFFF;
+ bounds_height_vec.resize (_num_output_glyphs, false);
+ for (auto &v : bounds_height_vec)
+ v = 0xFFFFFFFF;
+
if (unlikely (in_error ()))
return;
@@ -1091,19 +1147,9 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
if (attach_accelerator_data)
{
- hb_multimap_t gid_to_unicodes;
-
- hb_map_t &unicode_to_gid = *codepoint_to_glyph;
-
- for (auto unicode : unicodes)
- {
- auto gid = unicode_to_gid[unicode];
- gid_to_unicodes.add (gid, unicode);
- }
-
inprogress_accelerator =
- hb_subset_accelerator_t::create (*codepoint_to_glyph,
- gid_to_unicodes,
+ hb_subset_accelerator_t::create (source,
+ *codepoint_to_glyph,
unicodes,
has_seac);
@@ -1115,6 +1161,29 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
#undef HB_SUBSET_PLAN_MEMBER
}
+hb_subset_plan_t::~hb_subset_plan_t()
+{
+ hb_face_destroy (dest);
+
+ hb_map_destroy (codepoint_to_glyph);
+ hb_map_destroy (glyph_map);
+ hb_map_destroy (reverse_glyph_map);
+#ifndef HB_NO_SUBSET_CFF
+ cff1_accel.fini ();
+ cff2_accel.fini ();
+#endif
+ hb_face_destroy (source);
+
+#ifdef HB_EXPERIMENTAL_API
+ for (auto _ : name_table_overrides.iter_ref ())
+ _.second.fini ();
+#endif
+
+ if (inprogress_accelerator)
+ hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator);
+}
+
+
/**
* hb_subset_plan_create_or_fail:
* @face: font face to create the plan for.
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh
index 19470ff83e..d156de05d7 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh
@@ -67,28 +67,17 @@ struct head_maxp_info_t
typedef struct head_maxp_info_t head_maxp_info_t;
+namespace OT {
+ struct cff1_subset_accelerator_t;
+ struct cff2_subset_accelerator_t;
+}
+
struct hb_subset_plan_t
{
HB_INTERNAL hb_subset_plan_t (hb_face_t *,
const hb_subset_input_t *input);
- ~hb_subset_plan_t()
- {
- hb_face_destroy (source);
- hb_face_destroy (dest);
-
- hb_map_destroy (codepoint_to_glyph);
- hb_map_destroy (glyph_map);
- hb_map_destroy (reverse_glyph_map);
-
-#ifdef HB_EXPERIMENTAL_API
- for (auto _ : name_table_overrides)
- _.second.fini ();
-#endif
-
- if (inprogress_accelerator)
- hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator);
- }
+ HB_INTERNAL ~hb_subset_plan_t();
hb_object_header_t header;
@@ -106,6 +95,12 @@ struct hb_subset_plan_t
// Plan is only good for a specific source/dest so keep them with it
hb_face_t *source;
+#ifndef HB_NO_SUBSET_CFF
+ // These have to be immediately after source:
+ hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel;
+ hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel;
+#endif
+
hb_face_t *dest;
unsigned int _num_output_glyphs;
@@ -114,6 +109,10 @@ struct hb_subset_plan_t
bool pinned_at_default;
bool has_seac;
+ // whether to insert a catch-all FeatureVariationRecord
+ bool gsub_insert_catch_all_feature_variation_rec;
+ bool gpos_insert_catch_all_feature_variation_rec;
+
#define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name;
#include "hb-subset-plan-member-list.hh"
#undef HB_SUBSET_PLAN_MEMBER
@@ -127,25 +126,31 @@ struct hb_subset_plan_t
public:
template<typename T>
- hb_blob_ptr_t<T> source_table()
+ struct source_table_loader
{
- hb_lock_t lock (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr);
+ hb_blob_ptr_t<T> operator () (hb_subset_plan_t *plan)
+ {
+ hb_lock_t lock (plan->accelerator ? &plan->accelerator->sanitized_table_cache_lock : nullptr);
- auto *cache = accelerator ? &accelerator->sanitized_table_cache : &sanitized_table_cache;
- if (cache
- && !cache->in_error ()
- && cache->has (+T::tableTag)) {
- return hb_blob_reference (cache->get (+T::tableTag).get ());
- }
+ auto *cache = plan->accelerator ? &plan->accelerator->sanitized_table_cache : &plan->sanitized_table_cache;
+ if (cache
+ && !cache->in_error ()
+ && cache->has (+T::tableTag)) {
+ return hb_blob_reference (cache->get (+T::tableTag).get ());
+ }
- hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (source)};
- hb_blob_t* ret = hb_blob_reference (table_blob.get ());
+ hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (plan->source)};
+ hb_blob_t* ret = hb_blob_reference (table_blob.get ());
- if (likely (cache))
- cache->set (+T::tableTag, std::move (table_blob));
+ if (likely (cache))
+ cache->set (+T::tableTag, std::move (table_blob));
- return ret;
- }
+ return ret;
+ }
+ };
+
+ template<typename T>
+ auto source_table() HB_AUTO_RETURN (source_table_loader<T> {} (this))
bool in_error () const { return !successful; }
@@ -184,15 +189,6 @@ struct hb_subset_plan_t
return _num_output_glyphs;
}
- /*
- * Given an output gid , returns true if that glyph id is an empty
- * glyph (ie. it's a gid that we are dropping all data for).
- */
- inline bool is_empty_glyph (hb_codepoint_t gid) const
- {
- return !_glyphset.has (gid);
- }
-
inline bool new_gid_for_codepoint (hb_codepoint_t codepoint,
hb_codepoint_t *new_gid) const
{
@@ -242,4 +238,5 @@ struct hb_subset_plan_t
}
};
+
#endif /* HB_SUBSET_PLAN_HH */
diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc
index 9c066e6d78..8e8a5eb0bd 100644
--- a/thirdparty/harfbuzz/src/hb-subset.cc
+++ b/thirdparty/harfbuzz/src/hb-subset.cc
@@ -62,6 +62,27 @@
using OT::Layout::GSUB;
using OT::Layout::GPOS;
+
+#ifndef HB_NO_SUBSET_CFF
+template<>
+struct hb_subset_plan_t::source_table_loader<const OT::cff1>
+{
+ auto operator () (hb_subset_plan_t *plan)
+ HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel :
+ plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel :
+ plan->cff1_accel)
+};
+template<>
+struct hb_subset_plan_t::source_table_loader<const OT::cff2>
+{
+ auto operator () (hb_subset_plan_t *plan)
+ HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel :
+ plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel :
+ plan->cff2_accel)
+};
+#endif
+
+
/**
* SECTION:hb-subset
* @title: hb-subset
@@ -192,15 +213,36 @@ _get_table_tags (const hb_subset_plan_t* plan,
static unsigned
_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
unsigned table_len,
- bool same_size)
+ hb_tag_t table_tag)
{
unsigned src_glyphs = plan->source->get_num_glyphs ();
unsigned dst_glyphs = plan->glyphset ()->get_population ();
+ unsigned bulk = 8192;
+ /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's
+ * because those are expensive to subset, so giving them more room is fine. */
+ bool same_size = table_tag == HB_OT_TAG_GSUB ||
+ table_tag == HB_OT_TAG_GPOS ||
+ table_tag == HB_OT_TAG_name;
+
+ if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS)
+ {
+ if (table_tag == HB_OT_TAG_CFF1)
+ {
+ /* Add some extra room for the CFF charset. */
+ bulk += src_glyphs * 16;
+ }
+ else if (table_tag == HB_OT_TAG_CFF2)
+ {
+ /* Just extra CharString offsets. */
+ bulk += src_glyphs * 4;
+ }
+ }
+
if (unlikely (!src_glyphs) || same_size)
- return 512 + table_len;
+ return bulk + table_len;
- return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
+ return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
}
/*
@@ -262,45 +304,46 @@ _try_subset (const TableType *table,
return _try_subset (table, buf, c);
}
+template <typename T>
+static auto _do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ())
+
+template <typename T>
+static void _do_destroy (T &t, hb_priority<0>) {}
+
template<typename TableType>
static bool
_subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf)
{
- hb_blob_ptr_t<TableType> source_blob = plan->source_table<TableType> ();
- const TableType *table = source_blob.get ();
+ auto &&source_blob = plan->source_table<TableType> ();
+ auto *table = source_blob.get ();
hb_tag_t tag = TableType::tableTag;
- if (!source_blob.get_blob()->data)
+ hb_blob_t *blob = source_blob.get_blob();
+ if (unlikely (!blob || !blob->data))
{
DEBUG_MSG (SUBSET, nullptr,
"OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
- source_blob.destroy ();
+ _do_destroy (source_blob, hb_prioritize);
return false;
}
- /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's
- * because those are expensive to subset, so giving them more room is fine. */
- bool same_size_table = TableType::tableTag == HB_OT_TAG_GSUB ||
- TableType::tableTag == HB_OT_TAG_GPOS ||
- TableType::tableTag == HB_OT_TAG_name;
-
- unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob.get_length (), same_size_table);
+ unsigned buf_size = _plan_estimate_subset_table_size (plan, blob->length, TableType::tableTag);
DEBUG_MSG (SUBSET, nullptr,
"OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
if (unlikely (!buf.alloc (buf_size)))
{
DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
- source_blob.destroy ();
+ _do_destroy (source_blob, hb_prioritize);
return false;
}
bool needed = false;
hb_serialize_context_t serializer (buf.arrayZ, buf.allocated);
{
- hb_subset_context_t c (source_blob.get_blob (), plan, &serializer, tag);
+ hb_subset_context_t c (blob, plan, &serializer, tag);
needed = _try_subset (table, &buf, &c);
}
- source_blob.destroy ();
+ _do_destroy (source_blob, hb_prioritize);
if (serializer.in_error () && !serializer.only_offset_overflow ())
{
@@ -587,46 +630,49 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
offset += num_tables;
}
- hb_vector_t<char> buf;
- buf.alloc (4096 - 16);
-
-
bool success = true;
- while (!pending_subset_tags.is_empty ())
{
- if (subsetted_tags.in_error ()
- || pending_subset_tags.in_error ()) {
- success = false;
- goto end;
- }
+ // Grouping to deallocate buf before calling hb_face_reference (plan->dest).
- bool made_changes = false;
- for (hb_tag_t tag : pending_subset_tags)
+ hb_vector_t<char> buf;
+ buf.alloc (8192 - 16);
+
+ while (!pending_subset_tags.is_empty ())
{
- if (!_dependencies_satisfied (plan, tag,
- subsetted_tags,
- pending_subset_tags))
- {
- // delayed subsetting for some tables since they might have dependency on other tables
- // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated
- // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values
- continue;
+ if (subsetted_tags.in_error ()
+ || pending_subset_tags.in_error ()) {
+ success = false;
+ goto end;
}
- pending_subset_tags.del (tag);
- subsetted_tags.add (tag);
- made_changes = true;
-
- success = _subset_table (plan, buf, tag);
- if (unlikely (!success)) goto end;
- }
+ bool made_changes = false;
+ for (hb_tag_t tag : pending_subset_tags)
+ {
+ if (!_dependencies_satisfied (plan, tag,
+ subsetted_tags,
+ pending_subset_tags))
+ {
+ // delayed subsetting for some tables since they might have dependency on other tables
+ // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated
+ // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values
+ continue;
+ }
+
+ pending_subset_tags.del (tag);
+ subsetted_tags.add (tag);
+ made_changes = true;
+
+ success = _subset_table (plan, buf, tag);
+ if (unlikely (!success)) goto end;
+ }
- if (!made_changes)
- {
- DEBUG_MSG (SUBSET, nullptr, "Table dependencies unable to be satisfied. Subset failed.");
- success = false;
- goto end;
+ if (!made_changes)
+ {
+ DEBUG_MSG (SUBSET, nullptr, "Table dependencies unable to be satisfied. Subset failed.");
+ success = false;
+ goto end;
+ }
}
}
diff --git a/thirdparty/harfbuzz/src/hb-subset.h b/thirdparty/harfbuzz/src/hb-subset.h
index 6368ff93f0..93f1f7f10c 100644
--- a/thirdparty/harfbuzz/src/hb-subset.h
+++ b/thirdparty/harfbuzz/src/hb-subset.h
@@ -177,6 +177,13 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
#ifdef HB_EXPERIMENTAL_API
HB_EXTERN hb_bool_t
+hb_subset_input_set_axis_range (hb_subset_input_t *input,
+ hb_face_t *face,
+ hb_tag_t axis_tag,
+ float axis_min_value,
+ float axis_max_value);
+
+HB_EXTERN hb_bool_t
hb_subset_input_override_name_table (hb_subset_input_t *input,
hb_ot_name_id_t name_id,
unsigned platform_id,
diff --git a/thirdparty/harfbuzz/src/hb-vector.hh b/thirdparty/harfbuzz/src/hb-vector.hh
index d61ce48c01..23a96d7081 100644
--- a/thirdparty/harfbuzz/src/hb-vector.hh
+++ b/thirdparty/harfbuzz/src/hb-vector.hh
@@ -54,7 +54,7 @@ struct hb_vector_t
hb_vector_t (const Iterable &o) : hb_vector_t ()
{
auto iter = hb_iter (o);
- if (iter.is_random_access_iterator)
+ if (iter.is_random_access_iterator || iter.has_fast_len)
alloc (hb_len (iter), true);
hb_copy (iter, *this);
}
@@ -62,7 +62,19 @@ struct hb_vector_t
{
alloc (o.length, true);
if (unlikely (in_error ())) return;
- copy_vector (o);
+ copy_array (o.as_array ());
+ }
+ hb_vector_t (array_t o) : hb_vector_t ()
+ {
+ alloc (o.length, true);
+ if (unlikely (in_error ())) return;
+ copy_array (o);
+ }
+ hb_vector_t (c_array_t o) : hb_vector_t ()
+ {
+ alloc (o.length, true);
+ if (unlikely (in_error ())) return;
+ copy_array (o);
}
hb_vector_t (hb_vector_t &&o)
{
@@ -74,7 +86,7 @@ struct hb_vector_t
~hb_vector_t () { fini (); }
public:
- int allocated = 0; /* == -1 means allocation failed. */
+ int allocated = 0; /* < 0 means allocation failed. */
unsigned int length = 0;
public:
Type *arrayZ = nullptr;
@@ -90,19 +102,21 @@ struct hb_vector_t
void fini ()
{
- shrink_vector (0);
- hb_free (arrayZ);
+ /* We allow a hack to make the vector point to a foriegn array
+ * by the user. In that case length/arrayZ are non-zero but
+ * allocated is zero. Don't free anything. */
+ if (allocated)
+ {
+ shrink_vector (0);
+ hb_free (arrayZ);
+ }
init ();
}
void reset ()
{
if (unlikely (in_error ()))
- /* Big Hack! We don't know the true allocated size before
- * an allocation failure happened. But we know it was at
- * least as big as length. Restore it to that and continue
- * as if error did not happen. */
- allocated = length;
+ reset_error ();
resize (0);
}
@@ -119,7 +133,7 @@ struct hb_vector_t
alloc (o.length, true);
if (unlikely (in_error ())) return *this;
- copy_vector (o);
+ copy_array (o.as_array ());
return *this;
}
@@ -191,7 +205,7 @@ struct hb_vector_t
Type *push ()
{
if (unlikely (!resize (length + 1)))
- return &Crap (Type);
+ return std::addressof (Crap (Type));
return std::addressof (arrayZ[length - 1]);
}
template <typename T,
@@ -201,7 +215,7 @@ struct hb_vector_t
Type *push (T&& v)
{
Type *p = push ();
- if (p == &Crap (Type))
+ if (p == std::addressof (Crap (Type)))
// If push failed to allocate then don't copy v, since this may cause
// the created copy to leak memory since we won't have stored a
// reference to it.
@@ -214,24 +228,33 @@ struct hb_vector_t
hb_enable_if (std::is_copy_constructible<T2>::value)>
Type *push (T&& v)
{
- if (unlikely (!alloc (length + 1)))
+ if (unlikely ((int) length >= allocated && !alloc (length + 1)))
// If push failed to allocate then don't copy v, since this may cause
// the created copy to leak memory since we won't have stored a
// reference to it.
- return &Crap (Type);
+ return std::addressof (Crap (Type));
/* Emplace. */
- length++;
- Type *p = std::addressof (arrayZ[length - 1]);
+ Type *p = std::addressof (arrayZ[length++]);
return new (p) Type (std::forward<T> (v));
}
bool in_error () const { return allocated < 0; }
+ void set_error ()
+ {
+ assert (allocated >= 0);
+ allocated = -allocated - 1;
+ }
+ void reset_error ()
+ {
+ assert (allocated < 0);
+ allocated = -(allocated + 1);
+ }
template <typename T = Type,
hb_enable_if (hb_is_trivially_copy_assignable(T))>
Type *
- realloc_vector (unsigned new_allocated)
+ realloc_vector (unsigned new_allocated, hb_priority<0>)
{
if (!new_allocated)
{
@@ -243,7 +266,7 @@ struct hb_vector_t
template <typename T = Type,
hb_enable_if (!hb_is_trivially_copy_assignable(T))>
Type *
- realloc_vector (unsigned new_allocated)
+ realloc_vector (unsigned new_allocated, hb_priority<0>)
{
if (!new_allocated)
{
@@ -263,31 +286,52 @@ struct hb_vector_t
}
return new_array;
}
+ /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */
+ template <typename T = Type,
+ hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) ||
+ hb_is_same (T, hb_array_t <typename T::item_t>))>
+ Type *
+ realloc_vector (unsigned new_allocated, hb_priority<1>)
+ {
+ if (!new_allocated)
+ {
+ hb_free (arrayZ);
+ return nullptr;
+ }
+ return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
+ }
template <typename T = Type,
hb_enable_if (hb_is_trivially_constructible(T))>
void
- grow_vector (unsigned size)
+ grow_vector (unsigned size, hb_priority<0>)
{
- memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
+ hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
length = size;
}
template <typename T = Type,
hb_enable_if (!hb_is_trivially_constructible(T))>
void
- grow_vector (unsigned size)
+ grow_vector (unsigned size, hb_priority<0>)
{
- while (length < size)
- {
- length++;
- new (std::addressof (arrayZ[length - 1])) Type ();
- }
+ for (; length < size; length++)
+ new (std::addressof (arrayZ[length])) Type ();
+ }
+ /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */
+ template <typename T = Type,
+ hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) ||
+ hb_is_same (T, hb_array_t <typename T::item_t>))>
+ void
+ grow_vector (unsigned size, hb_priority<1>)
+ {
+ hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
+ length = size;
}
template <typename T = Type,
hb_enable_if (hb_is_trivially_copyable (T))>
void
- copy_vector (const hb_vector_t &other)
+ copy_array (hb_array_t<const Type> other)
{
length = other.length;
if (!HB_OPTIMIZE_SIZE_VAL && sizeof (T) >= sizeof (long long))
@@ -301,7 +345,7 @@ struct hb_vector_t
hb_enable_if (!hb_is_trivially_copyable (T) &&
std::is_copy_constructible<T>::value)>
void
- copy_vector (const hb_vector_t &other)
+ copy_array (hb_array_t<const Type> other)
{
length = 0;
while (length < other.length)
@@ -316,7 +360,7 @@ struct hb_vector_t
std::is_default_constructible<T>::value &&
std::is_copy_assignable<T>::value)>
void
- copy_vector (const hb_vector_t &other)
+ copy_array (hb_array_t<const Type> other)
{
length = 0;
while (length < other.length)
@@ -330,11 +374,15 @@ struct hb_vector_t
void
shrink_vector (unsigned size)
{
- while ((unsigned) length > size)
+ assert (size <= length);
+ if (!std::is_trivially_destructible<Type>::value)
{
- arrayZ[(unsigned) length - 1].~Type ();
- length--;
+ unsigned count = length - size;
+ Type *p = arrayZ + length - 1;
+ while (count--)
+ p--->~Type ();
}
+ length = size;
}
void
@@ -381,18 +429,18 @@ struct hb_vector_t
if (unlikely (overflows))
{
- allocated = -1;
+ set_error ();
return false;
}
- Type *new_array = realloc_vector (new_allocated);
+ Type *new_array = realloc_vector (new_allocated, hb_prioritize);
if (unlikely (new_allocated && !new_array))
{
if (new_allocated <= (unsigned) allocated)
return true; // shrinking failed; it's okay; happens in our fuzzer
- allocated = -1;
+ set_error ();
return false;
}
@@ -411,7 +459,7 @@ struct hb_vector_t
if (size > length)
{
if (initialize)
- grow_vector (size);
+ grow_vector (size, hb_prioritize);
}
else if (size < length)
{
diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h
index 08d1f55a35..9b27acf598 100644
--- a/thirdparty/harfbuzz/src/hb-version.h
+++ b/thirdparty/harfbuzz/src/hb-version.h
@@ -41,13 +41,13 @@ HB_BEGIN_DECLS
*
* The major component of the library version available at compile-time.
*/
-#define HB_VERSION_MAJOR 7
+#define HB_VERSION_MAJOR 8
/**
* HB_VERSION_MINOR:
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 3
+#define HB_VERSION_MINOR 0
/**
* HB_VERSION_MICRO:
*
@@ -60,7 +60,7 @@ HB_BEGIN_DECLS
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "7.3.0"
+#define HB_VERSION_STRING "8.0.0"
/**
* HB_VERSION_ATLEAST:
diff --git a/thirdparty/harfbuzz/src/hb.hh b/thirdparty/harfbuzz/src/hb.hh
index 205f8cf196..49119b8f82 100644
--- a/thirdparty/harfbuzz/src/hb.hh
+++ b/thirdparty/harfbuzz/src/hb.hh
@@ -315,6 +315,14 @@ extern "C" void hb_free_impl(void *ptr);
#define __restrict
#endif
+#ifndef HB_ALWAYS_INLINE
+#if defined(_MSC_VER)
+#define HB_ALWAYS_INLINE __forceinline
+#else
+#define HB_ALWAYS_INLINE __attribute__((always_inline)) inline
+#endif
+#endif
+
/*
* Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
* HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
diff --git a/thirdparty/icu4c/common/unicode/ures.h b/thirdparty/icu4c/common/unicode/ures.h
index cc25b6e49c..babc01d426 100644
--- a/thirdparty/icu4c/common/unicode/ures.h
+++ b/thirdparty/icu4c/common/unicode/ures.h
@@ -25,6 +25,7 @@
#ifndef URES_H
#define URES_H
+#include "unicode/char16ptr.h"
#include "unicode/utypes.h"
#include "unicode/uloc.h"
@@ -812,7 +813,7 @@ inline UnicodeString
ures_getUnicodeString(const UResourceBundle *resB, UErrorCode* status) {
UnicodeString result;
int32_t len = 0;
- const char16_t *r = ures_getString(resB, &len, status);
+ const char16_t *r = ConstChar16Ptr(ures_getString(resB, &len, status));
if(U_SUCCESS(*status)) {
result.setTo(true, r, len);
} else {
@@ -837,7 +838,7 @@ inline UnicodeString
ures_getNextUnicodeString(UResourceBundle *resB, const char ** key, UErrorCode* status) {
UnicodeString result;
int32_t len = 0;
- const char16_t* r = ures_getNextString(resB, &len, key, status);
+ const char16_t* r = ConstChar16Ptr(ures_getNextString(resB, &len, key, status));
if(U_SUCCESS(*status)) {
result.setTo(true, r, len);
} else {
@@ -859,7 +860,7 @@ inline UnicodeString
ures_getUnicodeStringByIndex(const UResourceBundle *resB, int32_t indexS, UErrorCode* status) {
UnicodeString result;
int32_t len = 0;
- const char16_t* r = ures_getStringByIndex(resB, indexS, &len, status);
+ const char16_t* r = ConstChar16Ptr(ures_getStringByIndex(resB, indexS, &len, status));
if(U_SUCCESS(*status)) {
result.setTo(true, r, len);
} else {
@@ -882,7 +883,7 @@ inline UnicodeString
ures_getUnicodeStringByKey(const UResourceBundle *resB, const char* key, UErrorCode* status) {
UnicodeString result;
int32_t len = 0;
- const char16_t* r = ures_getStringByKey(resB, key, &len, status);
+ const char16_t* r = ConstChar16Ptr(ures_getStringByKey(resB, key, &len, status));
if(U_SUCCESS(*status)) {
result.setTo(true, r, len);
} else {
diff --git a/thirdparty/icu4c/common/unicode/uvernum.h b/thirdparty/icu4c/common/unicode/uvernum.h
index f0fc671b4b..fc784b2492 100644
--- a/thirdparty/icu4c/common/unicode/uvernum.h
+++ b/thirdparty/icu4c/common/unicode/uvernum.h
@@ -59,7 +59,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_MINOR_NUM 1
+#define U_ICU_VERSION_MINOR_NUM 2
/** The current ICU patchlevel version as an integer.
* This value will change in the subsequent releases of ICU
@@ -132,7 +132,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION "73.1"
+#define U_ICU_VERSION "73.2"
/**
* The current ICU library major version number as a string, for library name suffixes.
@@ -151,7 +151,7 @@
/** Data version in ICU4C.
* @internal ICU 4.4 Internal Use Only
**/
-#define U_ICU_DATA_VERSION "73.1"
+#define U_ICU_DATA_VERSION "73.2"
#endif /* U_HIDE_INTERNAL_API */
/*===========================================================================
diff --git a/thirdparty/icu4c/icudt73l.dat b/thirdparty/icu4c/icudt73l.dat
index b8e2cf7567..fc007e5f96 100644
--- a/thirdparty/icu4c/icudt73l.dat
+++ b/thirdparty/icu4c/icudt73l.dat
Binary files differ
diff --git a/thirdparty/minizip/patches/empty-zip-fix.patch b/thirdparty/minizip/patches/empty-zip-fix.patch
new file mode 100644
index 0000000000..7885d4c3a3
--- /dev/null
+++ b/thirdparty/minizip/patches/empty-zip-fix.patch
@@ -0,0 +1,193 @@
+diff --git a/thirdparty/minizip/unzip.c b/thirdparty/minizip/unzip.c
+index e83aff2773..af73f06137 100644
+--- a/thirdparty/minizip/unzip.c
++++ b/thirdparty/minizip/unzip.c
+@@ -408,6 +408,12 @@ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1,
+ #define BUFREADCOMMENT (0x400)
+ #endif
+
++/* GODOT start */
++#ifndef CENTRALDIRINVALID
++#define CENTRALDIRINVALID (0xffffffffffffffff)
++#endif
++/* GODOT end */
++
+ /*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+@@ -419,10 +425,14 @@ local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_f
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+- ZPOS64_T uPosFound=0;
++ /* GODOT start */
++ ZPOS64_T uPosFound=CENTRALDIRINVALID;
++ /* GODOT end */
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+@@ -432,7 +442,9 @@ local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_f
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+@@ -462,7 +474,9 @@ local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_f
+ break;
+ }
+
+- if (uPosFound!=0)
++ /* GODOT start */
++ if (uPosFound!=CENTRALDIRINVALID)
++ /* GODOT end */
+ break;
+ }
+ TRYFREE(buf);
+@@ -485,12 +499,16 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+- ZPOS64_T uPosFound=0;
++ /* GODOT start */
++ ZPOS64_T uPosFound=CENTRALDIRINVALID;
++ /* GODOT end */
+ uLong uL;
+ ZPOS64_T relativeOffset;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+@@ -500,7 +518,9 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+@@ -530,47 +550,71 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
+ break;
+ }
+
+- if (uPosFound!=0)
++ /* GODOT start */
++ if (uPosFound!=CENTRALDIRINVALID)
++ /* GODOT end */
+ break;
+ }
+ TRYFREE(buf);
+- if (uPosFound == 0)
+- return 0;
++ /* GODOT start */
++ if (uPosFound == CENTRALDIRINVALID)
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ /* Zip64 end of central directory locator */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ /* the signature, already checked */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ /* number of the disk with the start of the zip64 end of central directory */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+ if (uL != 0)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ /* relative offset of the zip64 end of central directory record */
+ if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ /* total number of disks */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+ if (uL != 1)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ /* Goto end of central directory record */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ /* the signature */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ if (uL != 0x06064b50)
+- return 0;
++ /* GODOT start */
++ return CENTRALDIRINVALID;
++ /* GODOT end */
+
+ return relativeOffset;
+ }
+@@ -625,7 +669,9 @@ local unzFile unzOpenInternal (const void *path,
+ return NULL;
+
+ central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
+- if (central_pos)
++ /* GODOT start */
++ if (central_pos != CENTRALDIRINVALID)
++ /* GODOT end */
+ {
+ uLong uS;
+ ZPOS64_T uL64;
+@@ -687,7 +733,9 @@ local unzFile unzOpenInternal (const void *path,
+ else
+ {
+ central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
+- if (central_pos==0)
++ /* GODOT start */
++ if (central_pos==CENTRALDIRINVALID)
++ /* GODOT end */
+ err=UNZ_ERRNO;
+
+ us.isZip64 = 0;
diff --git a/thirdparty/minizip/unzip.c b/thirdparty/minizip/unzip.c
index e83aff2773..f72bf3974f 100644
--- a/thirdparty/minizip/unzip.c
+++ b/thirdparty/minizip/unzip.c
@@ -408,6 +408,12 @@ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1,
#define BUFREADCOMMENT (0x400)
#endif
+/* GODOT start */
+#ifndef CENTRALDIRINVALID
+#define CENTRALDIRINVALID (0xffffffffffffffff)
+#endif
+/* GODOT end */
+
/*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
@@ -419,10 +425,14 @@ local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_f
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
- ZPOS64_T uPosFound=0;
+ /* GODOT start */
+ ZPOS64_T uPosFound=CENTRALDIRINVALID;
+ /* GODOT end */
if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
@@ -432,7 +442,9 @@ local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_f
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
if (buf==NULL)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
uBackRead = 4;
while (uBackRead<uMaxBack)
@@ -462,7 +474,9 @@ local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_f
break;
}
- if (uPosFound!=0)
+ /* GODOT start */
+ if (uPosFound!=CENTRALDIRINVALID)
+ /* GODOT end */
break;
}
TRYFREE(buf);
@@ -485,12 +499,16 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
- ZPOS64_T uPosFound=0;
+ /* GODOT start */
+ ZPOS64_T uPosFound=CENTRALDIRINVALID;
+ /* GODOT end */
uLong uL;
ZPOS64_T relativeOffset;
if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
@@ -500,7 +518,9 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
if (buf==NULL)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
uBackRead = 4;
while (uBackRead<uMaxBack)
@@ -530,47 +550,71 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
break;
}
- if (uPosFound!=0)
+ /* GODOT start */
+ if (uPosFound!=CENTRALDIRINVALID)
+ /* GODOT end */
break;
}
TRYFREE(buf);
- if (uPosFound == 0)
- return 0;
+ /* GODOT start */
+ if (uPosFound == CENTRALDIRINVALID)
+ return CENTRALDIRINVALID;
+ /* GODOT end */
/* Zip64 end of central directory locator */
if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
/* the signature, already checked */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
/* number of the disk with the start of the zip64 end of central directory */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
if (uL != 0)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
/* relative offset of the zip64 end of central directory record */
if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
/* total number of disks */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
if (uL != 1)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
/* Goto end of central directory record */
if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
/* the signature */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
if (uL != 0x06064b50)
- return 0;
+ /* GODOT start */
+ return CENTRALDIRINVALID;
+ /* GODOT end */
return relativeOffset;
}
@@ -625,7 +669,9 @@ local unzFile unzOpenInternal (const void *path,
return NULL;
central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
- if (central_pos)
+ /* GODOT start */
+ if (central_pos != CENTRALDIRINVALID)
+ /* GODOT end */
{
uLong uS;
ZPOS64_T uL64;
@@ -687,7 +733,9 @@ local unzFile unzOpenInternal (const void *path,
else
{
central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
- if (central_pos==0)
+ /* GODOT start */
+ if (central_pos==CENTRALDIRINVALID)
+ /* GODOT end */
err=UNZ_ERRNO;
us.isZip64 = 0;
diff --git a/thirdparty/openxr/COPYING.adoc b/thirdparty/openxr/COPYING.adoc
index 3a31362acb..473e7fdc5d 100644
--- a/thirdparty/openxr/COPYING.adoc
+++ b/thirdparty/openxr/COPYING.adoc
@@ -1,6 +1,6 @@
= COPYING.adoc for the Khronos Group OpenXR projects
-// Copyright (c) 2020-2022, The Khronos Group Inc.
+// Copyright (c) 2020-2023, The Khronos Group Inc.
//
// SPDX-License-Identifier: CC-BY-4.0
diff --git a/thirdparty/openxr/include/openxr/openxr.h b/thirdparty/openxr/include/openxr/openxr.h
index 3663f9f14d..5d953fb9ba 100644
--- a/thirdparty/openxr/include/openxr/openxr.h
+++ b/thirdparty/openxr/include/openxr/openxr.h
@@ -2,7 +2,7 @@
#define OPENXR_H_ 1
/*
-** Copyright 2017-2022 The Khronos Group Inc.
+** Copyright 2017-2023 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -25,7 +25,7 @@ extern "C" {
((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL))
// OpenXR current version number.
-#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 26)
+#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 28)
#define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL)
#define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL)
@@ -74,6 +74,12 @@ extern "C" {
#define XR_MAX_EVENT_DATA_SIZE sizeof(XrEventDataBuffer)
+#define XR_EXTENSION_ENUM_BASE 1000000000
+
+
+#define XR_EXTENSION_ENUM_STRIDE 1000
+
+
#if !defined(XR_MAY_ALIAS)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4))
#define XR_MAY_ALIAS __attribute__((__may_alias__))
@@ -214,6 +220,15 @@ typedef enum XrResult {
XR_ERROR_MARKER_ID_INVALID_VARJO = -1000124001,
XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT = -1000142001,
XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT = -1000142002,
+ XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB = -1000169000,
+ XR_ERROR_SPACE_LOCALIZATION_FAILED_FB = -1000169001,
+ XR_ERROR_SPACE_NETWORK_TIMEOUT_FB = -1000169002,
+ XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB = -1000169003,
+ XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB = -1000169004,
+ XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META = -1000266000,
+ XR_ERROR_HINT_ALREADY_SET_QCOM = -1000306000,
+ XR_ERROR_SPACE_NOT_LOCATABLE_EXT = -1000429000,
+ XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT = -1000429001,
XR_RESULT_MAX_ENUM = 0x7FFFFFFF
} XrResult;
@@ -341,6 +356,11 @@ typedef enum XrStructureType {
XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT = 1000066001,
XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB = 1000070000,
XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB = 1000072000,
+ XR_TYPE_BODY_TRACKER_CREATE_INFO_FB = 1000076001,
+ XR_TYPE_BODY_JOINTS_LOCATE_INFO_FB = 1000076002,
+ XR_TYPE_SYSTEM_BODY_TRACKING_PROPERTIES_FB = 1000076004,
+ XR_TYPE_BODY_JOINT_LOCATIONS_FB = 1000076005,
+ XR_TYPE_BODY_SKELETON_FB = 1000076006,
XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT = 1000078000,
XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE = 1000079000,
XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT = 1000080000,
@@ -421,6 +441,9 @@ typedef enum XrStructureType {
XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO = 1000124000,
XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO = 1000124001,
XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO = 1000124002,
+ XR_TYPE_FRAME_END_INFO_ML = 1000135000,
+ XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML = 1000136000,
+ XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML = 1000137000,
XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT = 1000142000,
XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT = 1000142001,
XR_TYPE_SPACE_QUERY_INFO_FB = 1000156001,
@@ -438,19 +461,64 @@ typedef enum XrStructureType {
XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB = 1000161000,
XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB = 1000162000,
XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB = 1000163000,
+ XR_TYPE_SPACE_SHARE_INFO_FB = 1000169001,
+ XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB = 1000169002,
XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB = 1000171000,
XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB = 1000171001,
+ XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB = 1000173001,
XR_TYPE_SEMANTIC_LABELS_FB = 1000175000,
XR_TYPE_ROOM_LAYOUT_FB = 1000175001,
XR_TYPE_BOUNDARY_2D_FB = 1000175002,
+ XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB = 1000175010,
XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE = 1000196000,
+ XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB = 1000198001,
+ XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB = 1000198050,
XR_TYPE_SPACE_CONTAINER_FB = 1000199000,
+ XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META = 1000200000,
+ XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META = 1000200001,
+ XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META = 1000200002,
+ XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_FB = 1000201004,
+ XR_TYPE_FACE_TRACKER_CREATE_INFO_FB = 1000201005,
+ XR_TYPE_FACE_EXPRESSION_INFO_FB = 1000201002,
+ XR_TYPE_FACE_EXPRESSION_WEIGHTS_FB = 1000201006,
+ XR_TYPE_EYE_TRACKER_CREATE_INFO_FB = 1000202001,
+ XR_TYPE_EYE_GAZES_INFO_FB = 1000202002,
+ XR_TYPE_EYE_GAZES_FB = 1000202003,
+ XR_TYPE_SYSTEM_EYE_TRACKING_PROPERTIES_FB = 1000202004,
XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB = 1000203002,
XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB = 1000204000,
+ XR_TYPE_HAPTIC_PCM_VIBRATION_FB = 1000209001,
+ XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB = 1000209002,
+ XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_FB = 1000212000,
+ XR_TYPE_LOCAL_DIMMING_FRAME_END_INFO_META = 1000216000,
+ XR_TYPE_SYSTEM_VIRTUAL_KEYBOARD_PROPERTIES_META = 1000219001,
+ XR_TYPE_VIRTUAL_KEYBOARD_CREATE_INFO_META = 1000219002,
+ XR_TYPE_VIRTUAL_KEYBOARD_SPACE_CREATE_INFO_META = 1000219003,
+ XR_TYPE_VIRTUAL_KEYBOARD_LOCATION_INFO_META = 1000219004,
+ XR_TYPE_VIRTUAL_KEYBOARD_MODEL_VISIBILITY_SET_INFO_META = 1000219005,
+ XR_TYPE_VIRTUAL_KEYBOARD_ANIMATION_STATE_META = 1000219006,
+ XR_TYPE_VIRTUAL_KEYBOARD_MODEL_ANIMATION_STATES_META = 1000219007,
+ XR_TYPE_VIRTUAL_KEYBOARD_TEXTURE_DATA_META = 1000219009,
+ XR_TYPE_VIRTUAL_KEYBOARD_INPUT_INFO_META = 1000219010,
+ XR_TYPE_VIRTUAL_KEYBOARD_TEXT_CONTEXT_CHANGE_INFO_META = 1000219011,
+ XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_COMMIT_TEXT_META = 1000219014,
+ XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_BACKSPACE_META = 1000219015,
+ XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_ENTER_META = 1000219016,
+ XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_SHOWN_META = 1000219017,
+ XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_HIDDEN_META = 1000219018,
+ XR_TYPE_EXTERNAL_CAMERA_OCULUS = 1000226000,
XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META = 1000227000,
XR_TYPE_PERFORMANCE_METRICS_STATE_META = 1000232001,
XR_TYPE_PERFORMANCE_METRICS_COUNTER_META = 1000232002,
+ XR_TYPE_SPACE_LIST_SAVE_INFO_FB = 1000238000,
+ XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB = 1000238001,
+ XR_TYPE_SPACE_USER_CREATE_INFO_FB = 1000241001,
XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META = 1000245000,
+ XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META = 1000266000,
+ XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META = 1000266001,
+ XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META = 1000266002,
+ XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META = 1000266100,
+ XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META = 1000266101,
XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC = 1000317001,
XR_TYPE_PASSTHROUGH_COLOR_HTC = 1000317002,
XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC = 1000317003,
@@ -459,9 +527,21 @@ typedef enum XrStructureType {
XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC = 1000318001,
XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC = 1000318002,
XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT = 1000373000,
+ XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX = 1000375000,
+ XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX = 1000375001,
+ XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT = 1000428000,
+ XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT = 1000428001,
+ XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT = 1000429001,
+ XR_TYPE_PLANE_DETECTOR_BEGIN_INFO_EXT = 1000429002,
+ XR_TYPE_PLANE_DETECTOR_GET_INFO_EXT = 1000429003,
+ XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT = 1000429004,
+ XR_TYPE_PLANE_DETECTOR_LOCATION_EXT = 1000429005,
+ XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT = 1000429006,
+ XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT = 1000429007,
XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR,
XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR,
XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR,
+ XR_TYPE_DEVICE_PCM_SAMPLE_RATE_GET_INFO_FB = XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB,
XR_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
} XrStructureType;
@@ -492,6 +572,7 @@ typedef enum XrReferenceSpaceType {
XR_REFERENCE_SPACE_TYPE_STAGE = 3,
XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT = 1000038000,
XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO = 1000121000,
+ XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT = 1000426000,
XR_REFERENCE_SPACE_TYPE_MAX_ENUM = 0x7FFFFFFF
} XrReferenceSpaceType;
@@ -536,6 +617,7 @@ typedef enum XrObjectType {
XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT = 1000039000,
XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT = 1000049000,
XR_OBJECT_TYPE_HAND_TRACKER_EXT = 1000051000,
+ XR_OBJECT_TYPE_BODY_TRACKER_FB = 1000076000,
XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT = 1000097000,
XR_OBJECT_TYPE_SCENE_MSFT = 1000097001,
XR_OBJECT_TYPE_FACIAL_TRACKER_HTC = 1000104000,
@@ -545,7 +627,13 @@ typedef enum XrObjectType {
XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB = 1000118002,
XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB = 1000118004,
XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT = 1000142000,
+ XR_OBJECT_TYPE_FACE_TRACKER_FB = 1000201000,
+ XR_OBJECT_TYPE_EYE_TRACKER_FB = 1000202000,
+ XR_OBJECT_TYPE_VIRTUAL_KEYBOARD_META = 1000219000,
+ XR_OBJECT_TYPE_SPACE_USER_FB = 1000241000,
+ XR_OBJECT_TYPE_PASSTHROUGH_COLOR_LUT_META = 1000266000,
XR_OBJECT_TYPE_PASSTHROUGH_HTC = 1000317000,
+ XR_OBJECT_TYPE_PLANE_DETECTOR_EXT = 1000429000,
XR_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
} XrObjectType;
typedef XrFlags64 XrInstanceCreateFlags;
@@ -2542,6 +2630,167 @@ typedef struct XrCompositionLayerSecureContentFB {
+#define XR_FB_body_tracking 1
+XR_DEFINE_HANDLE(XrBodyTrackerFB)
+#define XR_FB_body_tracking_SPEC_VERSION 1
+#define XR_FB_BODY_TRACKING_EXTENSION_NAME "XR_FB_body_tracking"
+
+typedef enum XrBodyJointFB {
+ XR_BODY_JOINT_ROOT_FB = 0,
+ XR_BODY_JOINT_HIPS_FB = 1,
+ XR_BODY_JOINT_SPINE_LOWER_FB = 2,
+ XR_BODY_JOINT_SPINE_MIDDLE_FB = 3,
+ XR_BODY_JOINT_SPINE_UPPER_FB = 4,
+ XR_BODY_JOINT_CHEST_FB = 5,
+ XR_BODY_JOINT_NECK_FB = 6,
+ XR_BODY_JOINT_HEAD_FB = 7,
+ XR_BODY_JOINT_LEFT_SHOULDER_FB = 8,
+ XR_BODY_JOINT_LEFT_SCAPULA_FB = 9,
+ XR_BODY_JOINT_LEFT_ARM_UPPER_FB = 10,
+ XR_BODY_JOINT_LEFT_ARM_LOWER_FB = 11,
+ XR_BODY_JOINT_LEFT_HAND_WRIST_TWIST_FB = 12,
+ XR_BODY_JOINT_RIGHT_SHOULDER_FB = 13,
+ XR_BODY_JOINT_RIGHT_SCAPULA_FB = 14,
+ XR_BODY_JOINT_RIGHT_ARM_UPPER_FB = 15,
+ XR_BODY_JOINT_RIGHT_ARM_LOWER_FB = 16,
+ XR_BODY_JOINT_RIGHT_HAND_WRIST_TWIST_FB = 17,
+ XR_BODY_JOINT_LEFT_HAND_PALM_FB = 18,
+ XR_BODY_JOINT_LEFT_HAND_WRIST_FB = 19,
+ XR_BODY_JOINT_LEFT_HAND_THUMB_METACARPAL_FB = 20,
+ XR_BODY_JOINT_LEFT_HAND_THUMB_PROXIMAL_FB = 21,
+ XR_BODY_JOINT_LEFT_HAND_THUMB_DISTAL_FB = 22,
+ XR_BODY_JOINT_LEFT_HAND_THUMB_TIP_FB = 23,
+ XR_BODY_JOINT_LEFT_HAND_INDEX_METACARPAL_FB = 24,
+ XR_BODY_JOINT_LEFT_HAND_INDEX_PROXIMAL_FB = 25,
+ XR_BODY_JOINT_LEFT_HAND_INDEX_INTERMEDIATE_FB = 26,
+ XR_BODY_JOINT_LEFT_HAND_INDEX_DISTAL_FB = 27,
+ XR_BODY_JOINT_LEFT_HAND_INDEX_TIP_FB = 28,
+ XR_BODY_JOINT_LEFT_HAND_MIDDLE_METACARPAL_FB = 29,
+ XR_BODY_JOINT_LEFT_HAND_MIDDLE_PROXIMAL_FB = 30,
+ XR_BODY_JOINT_LEFT_HAND_MIDDLE_INTERMEDIATE_FB = 31,
+ XR_BODY_JOINT_LEFT_HAND_MIDDLE_DISTAL_FB = 32,
+ XR_BODY_JOINT_LEFT_HAND_MIDDLE_TIP_FB = 33,
+ XR_BODY_JOINT_LEFT_HAND_RING_METACARPAL_FB = 34,
+ XR_BODY_JOINT_LEFT_HAND_RING_PROXIMAL_FB = 35,
+ XR_BODY_JOINT_LEFT_HAND_RING_INTERMEDIATE_FB = 36,
+ XR_BODY_JOINT_LEFT_HAND_RING_DISTAL_FB = 37,
+ XR_BODY_JOINT_LEFT_HAND_RING_TIP_FB = 38,
+ XR_BODY_JOINT_LEFT_HAND_LITTLE_METACARPAL_FB = 39,
+ XR_BODY_JOINT_LEFT_HAND_LITTLE_PROXIMAL_FB = 40,
+ XR_BODY_JOINT_LEFT_HAND_LITTLE_INTERMEDIATE_FB = 41,
+ XR_BODY_JOINT_LEFT_HAND_LITTLE_DISTAL_FB = 42,
+ XR_BODY_JOINT_LEFT_HAND_LITTLE_TIP_FB = 43,
+ XR_BODY_JOINT_RIGHT_HAND_PALM_FB = 44,
+ XR_BODY_JOINT_RIGHT_HAND_WRIST_FB = 45,
+ XR_BODY_JOINT_RIGHT_HAND_THUMB_METACARPAL_FB = 46,
+ XR_BODY_JOINT_RIGHT_HAND_THUMB_PROXIMAL_FB = 47,
+ XR_BODY_JOINT_RIGHT_HAND_THUMB_DISTAL_FB = 48,
+ XR_BODY_JOINT_RIGHT_HAND_THUMB_TIP_FB = 49,
+ XR_BODY_JOINT_RIGHT_HAND_INDEX_METACARPAL_FB = 50,
+ XR_BODY_JOINT_RIGHT_HAND_INDEX_PROXIMAL_FB = 51,
+ XR_BODY_JOINT_RIGHT_HAND_INDEX_INTERMEDIATE_FB = 52,
+ XR_BODY_JOINT_RIGHT_HAND_INDEX_DISTAL_FB = 53,
+ XR_BODY_JOINT_RIGHT_HAND_INDEX_TIP_FB = 54,
+ XR_BODY_JOINT_RIGHT_HAND_MIDDLE_METACARPAL_FB = 55,
+ XR_BODY_JOINT_RIGHT_HAND_MIDDLE_PROXIMAL_FB = 56,
+ XR_BODY_JOINT_RIGHT_HAND_MIDDLE_INTERMEDIATE_FB = 57,
+ XR_BODY_JOINT_RIGHT_HAND_MIDDLE_DISTAL_FB = 58,
+ XR_BODY_JOINT_RIGHT_HAND_MIDDLE_TIP_FB = 59,
+ XR_BODY_JOINT_RIGHT_HAND_RING_METACARPAL_FB = 60,
+ XR_BODY_JOINT_RIGHT_HAND_RING_PROXIMAL_FB = 61,
+ XR_BODY_JOINT_RIGHT_HAND_RING_INTERMEDIATE_FB = 62,
+ XR_BODY_JOINT_RIGHT_HAND_RING_DISTAL_FB = 63,
+ XR_BODY_JOINT_RIGHT_HAND_RING_TIP_FB = 64,
+ XR_BODY_JOINT_RIGHT_HAND_LITTLE_METACARPAL_FB = 65,
+ XR_BODY_JOINT_RIGHT_HAND_LITTLE_PROXIMAL_FB = 66,
+ XR_BODY_JOINT_RIGHT_HAND_LITTLE_INTERMEDIATE_FB = 67,
+ XR_BODY_JOINT_RIGHT_HAND_LITTLE_DISTAL_FB = 68,
+ XR_BODY_JOINT_RIGHT_HAND_LITTLE_TIP_FB = 69,
+ XR_BODY_JOINT_COUNT_FB = 70,
+ XR_BODY_JOINT_NONE_FB = -1,
+ XR_BODY_JOINT_MAX_ENUM_FB = 0x7FFFFFFF
+} XrBodyJointFB;
+
+typedef enum XrBodyJointSetFB {
+ XR_BODY_JOINT_SET_DEFAULT_FB = 0,
+ XR_BODY_JOINT_SET_MAX_ENUM_FB = 0x7FFFFFFF
+} XrBodyJointSetFB;
+typedef struct XrBodyJointLocationFB {
+ XrSpaceLocationFlags locationFlags;
+ XrPosef pose;
+} XrBodyJointLocationFB;
+
+// XrSystemBodyTrackingPropertiesFB extends XrSystemProperties
+typedef struct XrSystemBodyTrackingPropertiesFB {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 supportsBodyTracking;
+} XrSystemBodyTrackingPropertiesFB;
+
+typedef struct XrBodyTrackerCreateInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrBodyJointSetFB bodyJointSet;
+} XrBodyTrackerCreateInfoFB;
+
+typedef struct XrBodySkeletonJointFB {
+ int32_t joint;
+ int32_t parentJoint;
+ XrPosef pose;
+} XrBodySkeletonJointFB;
+
+typedef struct XrBodySkeletonFB {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ uint32_t jointCount;
+ XrBodySkeletonJointFB* joints;
+} XrBodySkeletonFB;
+
+typedef struct XrBodyJointsLocateInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrSpace baseSpace;
+ XrTime time;
+} XrBodyJointsLocateInfoFB;
+
+typedef struct XrBodyJointLocationsFB {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 isActive;
+ float confidence;
+ uint32_t jointCount;
+ XrBodyJointLocationFB* jointLocations;
+ uint32_t skeletonChangedCount;
+ XrTime time;
+} XrBodyJointLocationsFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateBodyTrackerFB)(XrSession session, const XrBodyTrackerCreateInfoFB* createInfo, XrBodyTrackerFB* bodyTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyBodyTrackerFB)(XrBodyTrackerFB bodyTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrLocateBodyJointsFB)(XrBodyTrackerFB bodyTracker, const XrBodyJointsLocateInfoFB* locateInfo, XrBodyJointLocationsFB* locations);
+typedef XrResult (XRAPI_PTR *PFN_xrGetBodySkeletonFB)(XrBodyTrackerFB bodyTracker, XrBodySkeletonFB* skeleton);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateBodyTrackerFB(
+ XrSession session,
+ const XrBodyTrackerCreateInfoFB* createInfo,
+ XrBodyTrackerFB* bodyTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyBodyTrackerFB(
+ XrBodyTrackerFB bodyTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrLocateBodyJointsFB(
+ XrBodyTrackerFB bodyTracker,
+ const XrBodyJointsLocateInfoFB* locateInfo,
+ XrBodyJointLocationsFB* locations);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetBodySkeletonFB(
+ XrBodyTrackerFB bodyTracker,
+ XrBodySkeletonFB* skeleton);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_EXT_dpad_binding 1
#define XR_EXT_dpad_binding_SPEC_VERSION 1
#define XR_EXT_DPAD_BINDING_EXTENSION_NAME "XR_EXT_dpad_binding"
@@ -3325,12 +3574,13 @@ typedef struct XrHandTrackingCapsulesStateFB {
#define XR_FB_spatial_entity 1
XR_DEFINE_ATOM(XrAsyncRequestIdFB)
#define XR_UUID_SIZE_EXT 16
-#define XR_FB_spatial_entity_SPEC_VERSION 1
+#define XR_FB_spatial_entity_SPEC_VERSION 2
#define XR_FB_SPATIAL_ENTITY_EXTENSION_NAME "XR_FB_spatial_entity"
typedef enum XrSpaceComponentTypeFB {
XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB = 0,
XR_SPACE_COMPONENT_TYPE_STORABLE_FB = 1,
+ XR_SPACE_COMPONENT_TYPE_SHARABLE_FB = 2,
XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB = 3,
XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB = 4,
XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB = 5,
@@ -3834,7 +4084,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGeometryInstanceSetTransformFB(
#define XR_NULL_RENDER_MODEL_KEY_FB 0
XR_DEFINE_ATOM(XrRenderModelKeyFB)
-#define XR_FB_render_model_SPEC_VERSION 3
+#define XR_FB_render_model_SPEC_VERSION 4
#define XR_FB_RENDER_MODEL_EXTENSION_NAME "XR_FB_render_model"
#define XR_MAX_RENDER_MODEL_NAME_SIZE_FB 64
typedef XrFlags64 XrRenderModelFlagsFB;
@@ -3913,7 +4163,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrLoadRenderModelFB(
#define XR_VARJO_foveated_rendering 1
-#define XR_VARJO_foveated_rendering_SPEC_VERSION 2
+#define XR_VARJO_foveated_rendering_SPEC_VERSION 3
#define XR_VARJO_FOVEATED_RENDERING_EXTENSION_NAME "XR_VARJO_foveated_rendering"
// XrViewLocateFoveatedRenderingVARJO extends XrViewLocateInfo
typedef struct XrViewLocateFoveatedRenderingVARJO {
@@ -4045,6 +4295,43 @@ XRAPI_ATTR XrResult XRAPI_CALL xrSetViewOffsetVARJO(
#define XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_ML_ml2_controller_interaction"
+#define XR_ML_frame_end_info 1
+#define XR_ML_frame_end_info_SPEC_VERSION 1
+#define XR_ML_FRAME_END_INFO_EXTENSION_NAME "XR_ML_frame_end_info"
+typedef XrFlags64 XrFrameEndInfoFlagsML;
+
+// Flag bits for XrFrameEndInfoFlagsML
+static const XrFrameEndInfoFlagsML XR_FRAME_END_INFO_PROTECTED_BIT_ML = 0x00000001;
+static const XrFrameEndInfoFlagsML XR_FRAME_END_INFO_VIGNETTE_BIT_ML = 0x00000002;
+
+// XrFrameEndInfoML extends XrFrameEndInfo
+typedef struct XrFrameEndInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ float focusDistance;
+ XrFrameEndInfoFlagsML flags;
+} XrFrameEndInfoML;
+
+
+
+#define XR_ML_global_dimmer 1
+#define XR_ML_global_dimmer_SPEC_VERSION 1
+#define XR_ML_GLOBAL_DIMMER_EXTENSION_NAME "XR_ML_global_dimmer"
+typedef XrFlags64 XrGlobalDimmerFrameEndInfoFlagsML;
+
+// Flag bits for XrGlobalDimmerFrameEndInfoFlagsML
+static const XrGlobalDimmerFrameEndInfoFlagsML XR_GLOBAL_DIMMER_FRAME_END_INFO_ENABLED_BIT_ML = 0x00000001;
+
+// XrGlobalDimmerFrameEndInfoML extends XrFrameEndInfo
+typedef struct XrGlobalDimmerFrameEndInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ float dimmerValue;
+ XrGlobalDimmerFrameEndInfoFlagsML flags;
+} XrGlobalDimmerFrameEndInfoML;
+
+
+
#define XR_MSFT_spatial_anchor_persistence 1
XR_DEFINE_HANDLE(XrSpatialAnchorStoreConnectionMSFT)
#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT 256
@@ -4161,6 +4448,7 @@ typedef enum XrSpaceQueryActionFB {
typedef enum XrSpaceStorageLocationFB {
XR_SPACE_STORAGE_LOCATION_INVALID_FB = 0,
XR_SPACE_STORAGE_LOCATION_LOCAL_FB = 1,
+ XR_SPACE_STORAGE_LOCATION_CLOUD_FB = 2,
XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB = 0x7FFFFFFF
} XrSpaceStorageLocationFB;
typedef struct XR_MAY_ALIAS XrSpaceQueryInfoBaseHeaderFB {
@@ -4309,6 +4597,43 @@ XRAPI_ATTR XrResult XRAPI_CALL xrEraseSpaceFB(
#endif /* !XR_NO_PROTOTYPES */
+#define XR_FB_touch_controller_pro 1
+#define XR_FB_touch_controller_pro_SPEC_VERSION 1
+#define XR_FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME "XR_FB_touch_controller_pro"
+
+
+#define XR_FB_spatial_entity_sharing 1
+XR_DEFINE_HANDLE(XrSpaceUserFB)
+#define XR_FB_spatial_entity_sharing_SPEC_VERSION 1
+#define XR_FB_SPATIAL_ENTITY_SHARING_EXTENSION_NAME "XR_FB_spatial_entity_sharing"
+typedef struct XrSpaceShareInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ uint32_t spaceCount;
+ XrSpace* spaces;
+ uint32_t userCount;
+ XrSpaceUserFB* users;
+} XrSpaceShareInfoFB;
+
+typedef struct XrEventDataSpaceShareCompleteFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrAsyncRequestIdFB requestId;
+ XrResult result;
+} XrEventDataSpaceShareCompleteFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrShareSpacesFB)(XrSession session, const XrSpaceShareInfoFB* info, XrAsyncRequestIdFB* requestId);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrShareSpacesFB(
+ XrSession session,
+ const XrSpaceShareInfoFB* info,
+ XrAsyncRequestIdFB* requestId);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_FB_space_warp 1
#define XR_FB_space_warp_SPEC_VERSION 2
#define XR_FB_SPACE_WARP_EXTENSION_NAME "XR_FB_space_warp"
@@ -4341,9 +4666,31 @@ typedef struct XrSystemSpaceWarpPropertiesFB {
+#define XR_FB_haptic_amplitude_envelope 1
+
+#define XR_MAX_HAPTIC_AMPLITUDE_ENVELOPE_SAMPLES_FB 4000u
+
+#define XR_FB_haptic_amplitude_envelope_SPEC_VERSION 1
+#define XR_FB_HAPTIC_AMPLITUDE_ENVELOPE_EXTENSION_NAME "XR_FB_haptic_amplitude_envelope"
+typedef struct XrHapticAmplitudeEnvelopeVibrationFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrDuration duration;
+ uint32_t amplitudeCount;
+ const float* amplitudes;
+} XrHapticAmplitudeEnvelopeVibrationFB;
+
+
+
#define XR_FB_scene 1
-#define XR_FB_scene_SPEC_VERSION 1
+#define XR_FB_scene_SPEC_VERSION 3
#define XR_FB_SCENE_EXTENSION_NAME "XR_FB_scene"
+typedef XrFlags64 XrSemanticLabelsSupportFlagsFB;
+
+// Flag bits for XrSemanticLabelsSupportFlagsFB
+static const XrSemanticLabelsSupportFlagsFB XR_SEMANTIC_LABELS_SUPPORT_MULTIPLE_SEMANTIC_LABELS_BIT_FB = 0x00000001;
+static const XrSemanticLabelsSupportFlagsFB XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_DESK_TO_TABLE_MIGRATION_BIT_FB = 0x00000002;
+
typedef struct XrExtent3DfFB {
float width;
float height;
@@ -4387,6 +4734,13 @@ typedef struct XrBoundary2DFB {
XrVector2f* vertices;
} XrBoundary2DFB;
+typedef struct XrSemanticLabelsSupportInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrSemanticLabelsSupportFlagsFB flags;
+ const char* recognizedLabels;
+} XrSemanticLabelsSupportInfoFB;
+
typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox2DFB)(XrSession session, XrSpace space, XrRect2Df* boundingBox2DOutput);
typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox3DFB)(XrSession session, XrSpace space, XrRect3DfFB* boundingBox3DOutput);
typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceSemanticLabelsFB)(XrSession session, XrSpace space, XrSemanticLabelsFB* semanticLabelsOutput);
@@ -4453,6 +4807,35 @@ XRAPI_ATTR XrResult XRAPI_CALL xrSetDigitalLensControlALMALENCE(
#endif /* !XR_NO_PROTOTYPES */
+#define XR_FB_scene_capture 1
+#define XR_FB_scene_capture_SPEC_VERSION 1
+#define XR_FB_SCENE_CAPTURE_EXTENSION_NAME "XR_FB_scene_capture"
+typedef struct XrEventDataSceneCaptureCompleteFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrAsyncRequestIdFB requestId;
+ XrResult result;
+} XrEventDataSceneCaptureCompleteFB;
+
+typedef struct XrSceneCaptureRequestInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ uint32_t requestByteCount;
+ const char* request;
+} XrSceneCaptureRequestInfoFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrRequestSceneCaptureFB)(XrSession session, const XrSceneCaptureRequestInfoFB* info, XrAsyncRequestIdFB* requestId);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrRequestSceneCaptureFB(
+ XrSession session,
+ const XrSceneCaptureRequestInfoFB* info,
+ XrAsyncRequestIdFB* requestId);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_FB_spatial_entity_container 1
#define XR_FB_spatial_entity_container_SPEC_VERSION 2
#define XR_FB_SPATIAL_ENTITY_CONTAINER_EXTENSION_NAME "XR_FB_spatial_entity_container"
@@ -4476,6 +4859,260 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceContainerFB(
#endif /* !XR_NO_PROTOTYPES */
+#define XR_META_foveation_eye_tracked 1
+#define XR_FOVEATION_CENTER_SIZE_META 2
+#define XR_META_foveation_eye_tracked_SPEC_VERSION 1
+#define XR_META_FOVEATION_EYE_TRACKED_EXTENSION_NAME "XR_META_foveation_eye_tracked"
+typedef XrFlags64 XrFoveationEyeTrackedProfileCreateFlagsMETA;
+
+// Flag bits for XrFoveationEyeTrackedProfileCreateFlagsMETA
+
+typedef XrFlags64 XrFoveationEyeTrackedStateFlagsMETA;
+
+// Flag bits for XrFoveationEyeTrackedStateFlagsMETA
+static const XrFoveationEyeTrackedStateFlagsMETA XR_FOVEATION_EYE_TRACKED_STATE_VALID_BIT_META = 0x00000001;
+
+// XrFoveationEyeTrackedProfileCreateInfoMETA extends XrFoveationLevelProfileCreateInfoFB
+typedef struct XrFoveationEyeTrackedProfileCreateInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrFoveationEyeTrackedProfileCreateFlagsMETA flags;
+} XrFoveationEyeTrackedProfileCreateInfoMETA;
+
+typedef struct XrFoveationEyeTrackedStateMETA {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrVector2f foveationCenter[XR_FOVEATION_CENTER_SIZE_META];
+ XrFoveationEyeTrackedStateFlagsMETA flags;
+} XrFoveationEyeTrackedStateMETA;
+
+// XrSystemFoveationEyeTrackedPropertiesMETA extends XrSystemProperties
+typedef struct XrSystemFoveationEyeTrackedPropertiesMETA {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 supportsFoveationEyeTracked;
+} XrSystemFoveationEyeTrackedPropertiesMETA;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetFoveationEyeTrackedStateMETA)(XrSession session, XrFoveationEyeTrackedStateMETA* foveationState);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrGetFoveationEyeTrackedStateMETA(
+ XrSession session,
+ XrFoveationEyeTrackedStateMETA* foveationState);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_face_tracking 1
+
+#define XR_FACE_EXPRESSSION_SET_DEFAULT_FB XR_FACE_EXPRESSION_SET_DEFAULT_FB
+
+XR_DEFINE_HANDLE(XrFaceTrackerFB)
+#define XR_FB_face_tracking_SPEC_VERSION 1
+#define XR_FB_FACE_TRACKING_EXTENSION_NAME "XR_FB_face_tracking"
+
+typedef enum XrFaceExpressionFB {
+ XR_FACE_EXPRESSION_BROW_LOWERER_L_FB = 0,
+ XR_FACE_EXPRESSION_BROW_LOWERER_R_FB = 1,
+ XR_FACE_EXPRESSION_CHEEK_PUFF_L_FB = 2,
+ XR_FACE_EXPRESSION_CHEEK_PUFF_R_FB = 3,
+ XR_FACE_EXPRESSION_CHEEK_RAISER_L_FB = 4,
+ XR_FACE_EXPRESSION_CHEEK_RAISER_R_FB = 5,
+ XR_FACE_EXPRESSION_CHEEK_SUCK_L_FB = 6,
+ XR_FACE_EXPRESSION_CHEEK_SUCK_R_FB = 7,
+ XR_FACE_EXPRESSION_CHIN_RAISER_B_FB = 8,
+ XR_FACE_EXPRESSION_CHIN_RAISER_T_FB = 9,
+ XR_FACE_EXPRESSION_DIMPLER_L_FB = 10,
+ XR_FACE_EXPRESSION_DIMPLER_R_FB = 11,
+ XR_FACE_EXPRESSION_EYES_CLOSED_L_FB = 12,
+ XR_FACE_EXPRESSION_EYES_CLOSED_R_FB = 13,
+ XR_FACE_EXPRESSION_EYES_LOOK_DOWN_L_FB = 14,
+ XR_FACE_EXPRESSION_EYES_LOOK_DOWN_R_FB = 15,
+ XR_FACE_EXPRESSION_EYES_LOOK_LEFT_L_FB = 16,
+ XR_FACE_EXPRESSION_EYES_LOOK_LEFT_R_FB = 17,
+ XR_FACE_EXPRESSION_EYES_LOOK_RIGHT_L_FB = 18,
+ XR_FACE_EXPRESSION_EYES_LOOK_RIGHT_R_FB = 19,
+ XR_FACE_EXPRESSION_EYES_LOOK_UP_L_FB = 20,
+ XR_FACE_EXPRESSION_EYES_LOOK_UP_R_FB = 21,
+ XR_FACE_EXPRESSION_INNER_BROW_RAISER_L_FB = 22,
+ XR_FACE_EXPRESSION_INNER_BROW_RAISER_R_FB = 23,
+ XR_FACE_EXPRESSION_JAW_DROP_FB = 24,
+ XR_FACE_EXPRESSION_JAW_SIDEWAYS_LEFT_FB = 25,
+ XR_FACE_EXPRESSION_JAW_SIDEWAYS_RIGHT_FB = 26,
+ XR_FACE_EXPRESSION_JAW_THRUST_FB = 27,
+ XR_FACE_EXPRESSION_LID_TIGHTENER_L_FB = 28,
+ XR_FACE_EXPRESSION_LID_TIGHTENER_R_FB = 29,
+ XR_FACE_EXPRESSION_LIP_CORNER_DEPRESSOR_L_FB = 30,
+ XR_FACE_EXPRESSION_LIP_CORNER_DEPRESSOR_R_FB = 31,
+ XR_FACE_EXPRESSION_LIP_CORNER_PULLER_L_FB = 32,
+ XR_FACE_EXPRESSION_LIP_CORNER_PULLER_R_FB = 33,
+ XR_FACE_EXPRESSION_LIP_FUNNELER_LB_FB = 34,
+ XR_FACE_EXPRESSION_LIP_FUNNELER_LT_FB = 35,
+ XR_FACE_EXPRESSION_LIP_FUNNELER_RB_FB = 36,
+ XR_FACE_EXPRESSION_LIP_FUNNELER_RT_FB = 37,
+ XR_FACE_EXPRESSION_LIP_PRESSOR_L_FB = 38,
+ XR_FACE_EXPRESSION_LIP_PRESSOR_R_FB = 39,
+ XR_FACE_EXPRESSION_LIP_PUCKER_L_FB = 40,
+ XR_FACE_EXPRESSION_LIP_PUCKER_R_FB = 41,
+ XR_FACE_EXPRESSION_LIP_STRETCHER_L_FB = 42,
+ XR_FACE_EXPRESSION_LIP_STRETCHER_R_FB = 43,
+ XR_FACE_EXPRESSION_LIP_SUCK_LB_FB = 44,
+ XR_FACE_EXPRESSION_LIP_SUCK_LT_FB = 45,
+ XR_FACE_EXPRESSION_LIP_SUCK_RB_FB = 46,
+ XR_FACE_EXPRESSION_LIP_SUCK_RT_FB = 47,
+ XR_FACE_EXPRESSION_LIP_TIGHTENER_L_FB = 48,
+ XR_FACE_EXPRESSION_LIP_TIGHTENER_R_FB = 49,
+ XR_FACE_EXPRESSION_LIPS_TOWARD_FB = 50,
+ XR_FACE_EXPRESSION_LOWER_LIP_DEPRESSOR_L_FB = 51,
+ XR_FACE_EXPRESSION_LOWER_LIP_DEPRESSOR_R_FB = 52,
+ XR_FACE_EXPRESSION_MOUTH_LEFT_FB = 53,
+ XR_FACE_EXPRESSION_MOUTH_RIGHT_FB = 54,
+ XR_FACE_EXPRESSION_NOSE_WRINKLER_L_FB = 55,
+ XR_FACE_EXPRESSION_NOSE_WRINKLER_R_FB = 56,
+ XR_FACE_EXPRESSION_OUTER_BROW_RAISER_L_FB = 57,
+ XR_FACE_EXPRESSION_OUTER_BROW_RAISER_R_FB = 58,
+ XR_FACE_EXPRESSION_UPPER_LID_RAISER_L_FB = 59,
+ XR_FACE_EXPRESSION_UPPER_LID_RAISER_R_FB = 60,
+ XR_FACE_EXPRESSION_UPPER_LIP_RAISER_L_FB = 61,
+ XR_FACE_EXPRESSION_UPPER_LIP_RAISER_R_FB = 62,
+ XR_FACE_EXPRESSION_COUNT_FB = 63,
+ XR_FACE_EXPRESSION_MAX_ENUM_FB = 0x7FFFFFFF
+} XrFaceExpressionFB;
+
+typedef enum XrFaceExpressionSetFB {
+ XR_FACE_EXPRESSION_SET_DEFAULT_FB = 0,
+ XR_FACE_EXPRESSION_SET_MAX_ENUM_FB = 0x7FFFFFFF
+} XrFaceExpressionSetFB;
+
+typedef enum XrFaceConfidenceFB {
+ XR_FACE_CONFIDENCE_LOWER_FACE_FB = 0,
+ XR_FACE_CONFIDENCE_UPPER_FACE_FB = 1,
+ XR_FACE_CONFIDENCE_COUNT_FB = 2,
+ XR_FACE_CONFIDENCE_MAX_ENUM_FB = 0x7FFFFFFF
+} XrFaceConfidenceFB;
+// XrSystemFaceTrackingPropertiesFB extends XrSystemProperties
+typedef struct XrSystemFaceTrackingPropertiesFB {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 supportsFaceTracking;
+} XrSystemFaceTrackingPropertiesFB;
+
+typedef struct XrFaceTrackerCreateInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrFaceExpressionSetFB faceExpressionSet;
+} XrFaceTrackerCreateInfoFB;
+
+typedef struct XrFaceExpressionInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrTime time;
+} XrFaceExpressionInfoFB;
+
+typedef struct XrFaceExpressionStatusFB {
+ XrBool32 isValid;
+ XrBool32 isEyeFollowingBlendshapesValid;
+} XrFaceExpressionStatusFB;
+
+typedef struct XrFaceExpressionWeightsFB {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ uint32_t weightCount;
+ float* weights;
+ uint32_t confidenceCount;
+ float* confidences;
+ XrFaceExpressionStatusFB status;
+ XrTime time;
+} XrFaceExpressionWeightsFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateFaceTrackerFB)(XrSession session, const XrFaceTrackerCreateInfoFB* createInfo, XrFaceTrackerFB* faceTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyFaceTrackerFB)(XrFaceTrackerFB faceTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrGetFaceExpressionWeightsFB)(XrFaceTrackerFB faceTracker, const XrFaceExpressionInfoFB* expressionInfo, XrFaceExpressionWeightsFB* expressionWeights);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateFaceTrackerFB(
+ XrSession session,
+ const XrFaceTrackerCreateInfoFB* createInfo,
+ XrFaceTrackerFB* faceTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFaceTrackerFB(
+ XrFaceTrackerFB faceTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetFaceExpressionWeightsFB(
+ XrFaceTrackerFB faceTracker,
+ const XrFaceExpressionInfoFB* expressionInfo,
+ XrFaceExpressionWeightsFB* expressionWeights);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_eye_tracking_social 1
+XR_DEFINE_HANDLE(XrEyeTrackerFB)
+#define XR_FB_eye_tracking_social_SPEC_VERSION 1
+#define XR_FB_EYE_TRACKING_SOCIAL_EXTENSION_NAME "XR_FB_eye_tracking_social"
+
+typedef enum XrEyePositionFB {
+ XR_EYE_POSITION_LEFT_FB = 0,
+ XR_EYE_POSITION_RIGHT_FB = 1,
+ XR_EYE_POSITION_COUNT_FB = 2,
+ XR_EYE_POSITION_MAX_ENUM_FB = 0x7FFFFFFF
+} XrEyePositionFB;
+typedef struct XrEyeGazeFB {
+ XrBool32 isValid;
+ XrPosef gazePose;
+ float gazeConfidence;
+} XrEyeGazeFB;
+
+typedef struct XrEyeTrackerCreateInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+} XrEyeTrackerCreateInfoFB;
+
+typedef struct XrEyeGazesInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrSpace baseSpace;
+ XrTime time;
+} XrEyeGazesInfoFB;
+
+// XrSystemEyeTrackingPropertiesFB extends XrSystemProperties
+typedef struct XrSystemEyeTrackingPropertiesFB {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 supportsEyeTracking;
+} XrSystemEyeTrackingPropertiesFB;
+
+typedef struct XrEyeGazesFB {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrEyeGazeFB gaze[XR_EYE_POSITION_COUNT_FB];
+ XrTime time;
+} XrEyeGazesFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateEyeTrackerFB)(XrSession session, const XrEyeTrackerCreateInfoFB* createInfo, XrEyeTrackerFB* eyeTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyEyeTrackerFB)(XrEyeTrackerFB eyeTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrGetEyeGazesFB)(XrEyeTrackerFB eyeTracker, const XrEyeGazesInfoFB* gazeInfo, XrEyeGazesFB* eyeGazes);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateEyeTrackerFB(
+ XrSession session,
+ const XrEyeTrackerCreateInfoFB* createInfo,
+ XrEyeTrackerFB* eyeTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyEyeTrackerFB(
+ XrEyeTrackerFB eyeTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetEyeGazesFB(
+ XrEyeTrackerFB eyeTracker,
+ const XrEyeGazesInfoFB* gazeInfo,
+ XrEyeGazesFB* eyeGazes);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_FB_passthrough_keyboard_hands 1
#define XR_FB_passthrough_keyboard_hands_SPEC_VERSION 2
#define XR_FB_PASSTHROUGH_KEYBOARD_HANDS_EXTENSION_NAME "XR_FB_passthrough_keyboard_hands"
@@ -4517,6 +5154,349 @@ typedef struct XrCompositionLayerSettingsFB {
+#define XR_FB_touch_controller_proximity 1
+#define XR_FB_touch_controller_proximity_SPEC_VERSION 1
+#define XR_FB_TOUCH_CONTROLLER_PROXIMITY_EXTENSION_NAME "XR_FB_touch_controller_proximity"
+
+
+#define XR_FB_haptic_pcm 1
+
+#define XR_MAX_HAPTIC_PCM_BUFFER_SIZE_FB 4000
+
+#define XR_FB_haptic_pcm_SPEC_VERSION 1
+#define XR_FB_HAPTIC_PCM_EXTENSION_NAME "XR_FB_haptic_pcm"
+typedef struct XrHapticPcmVibrationFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ uint32_t bufferSize;
+ const float* buffer;
+ float sampleRate;
+ XrBool32 append;
+ uint32_t* samplesConsumed;
+} XrHapticPcmVibrationFB;
+
+typedef struct XrDevicePcmSampleRateStateFB {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ float sampleRate;
+} XrDevicePcmSampleRateStateFB;
+
+typedef XrDevicePcmSampleRateStateFB XrDevicePcmSampleRateGetInfoFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetDeviceSampleRateFB)(XrSession session, const XrHapticActionInfo* hapticActionInfo, XrDevicePcmSampleRateGetInfoFB* deviceSampleRate);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrGetDeviceSampleRateFB(
+ XrSession session,
+ const XrHapticActionInfo* hapticActionInfo,
+ XrDevicePcmSampleRateGetInfoFB* deviceSampleRate);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_composition_layer_depth_test 1
+#define XR_FB_composition_layer_depth_test_SPEC_VERSION 1
+#define XR_FB_COMPOSITION_LAYER_DEPTH_TEST_EXTENSION_NAME "XR_FB_composition_layer_depth_test"
+
+typedef enum XrCompareOpFB {
+ XR_COMPARE_OP_NEVER_FB = 0,
+ XR_COMPARE_OP_LESS_FB = 1,
+ XR_COMPARE_OP_EQUAL_FB = 2,
+ XR_COMPARE_OP_LESS_OR_EQUAL_FB = 3,
+ XR_COMPARE_OP_GREATER_FB = 4,
+ XR_COMPARE_OP_NOT_EQUAL_FB = 5,
+ XR_COMPARE_OP_GREATER_OR_EQUAL_FB = 6,
+ XR_COMPARE_OP_ALWAYS_FB = 7,
+ XR_COMPARE_OP_MAX_ENUM_FB = 0x7FFFFFFF
+} XrCompareOpFB;
+// XrCompositionLayerDepthTestFB extends XrCompositionLayerBaseHeader
+typedef struct XrCompositionLayerDepthTestFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrBool32 depthMask;
+ XrCompareOpFB compareOp;
+} XrCompositionLayerDepthTestFB;
+
+
+
+#define XR_META_local_dimming 1
+#define XR_META_local_dimming_SPEC_VERSION 1
+#define XR_META_LOCAL_DIMMING_EXTENSION_NAME "XR_META_local_dimming"
+
+typedef enum XrLocalDimmingModeMETA {
+ XR_LOCAL_DIMMING_MODE_OFF_META = 0,
+ XR_LOCAL_DIMMING_MODE_ON_META = 1,
+ XR_LOCAL_DIMMING_MODE_MAX_ENUM_META = 0x7FFFFFFF
+} XrLocalDimmingModeMETA;
+// XrLocalDimmingFrameEndInfoMETA extends XrFrameEndInfo
+typedef struct XrLocalDimmingFrameEndInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrLocalDimmingModeMETA localDimmingMode;
+} XrLocalDimmingFrameEndInfoMETA;
+
+
+
+#define XR_META_virtual_keyboard 1
+XR_DEFINE_HANDLE(XrVirtualKeyboardMETA)
+#define XR_MAX_VIRTUAL_KEYBOARD_COMMIT_TEXT_SIZE_META 3992
+#define XR_META_virtual_keyboard_SPEC_VERSION 1
+#define XR_META_VIRTUAL_KEYBOARD_EXTENSION_NAME "XR_META_virtual_keyboard"
+
+typedef enum XrVirtualKeyboardLocationTypeMETA {
+ XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_CUSTOM_META = 0,
+ XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_FAR_META = 1,
+ XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_DIRECT_META = 2,
+ XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_MAX_ENUM_META = 0x7FFFFFFF
+} XrVirtualKeyboardLocationTypeMETA;
+
+typedef enum XrVirtualKeyboardInputSourceMETA {
+ XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_RAY_LEFT_META = 1,
+ XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_RAY_RIGHT_META = 2,
+ XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_RAY_LEFT_META = 3,
+ XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_RAY_RIGHT_META = 4,
+ XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_DIRECT_LEFT_META = 5,
+ XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_DIRECT_RIGHT_META = 6,
+ XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_DIRECT_INDEX_TIP_LEFT_META = 7,
+ XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_DIRECT_INDEX_TIP_RIGHT_META = 8,
+ XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_MAX_ENUM_META = 0x7FFFFFFF
+} XrVirtualKeyboardInputSourceMETA;
+typedef XrFlags64 XrVirtualKeyboardInputStateFlagsMETA;
+
+// Flag bits for XrVirtualKeyboardInputStateFlagsMETA
+static const XrVirtualKeyboardInputStateFlagsMETA XR_VIRTUAL_KEYBOARD_INPUT_STATE_PRESSED_BIT_META = 0x00000001;
+
+// XrSystemVirtualKeyboardPropertiesMETA extends XrSystemProperties
+typedef struct XrSystemVirtualKeyboardPropertiesMETA {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 supportsVirtualKeyboard;
+} XrSystemVirtualKeyboardPropertiesMETA;
+
+typedef struct XrVirtualKeyboardCreateInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+} XrVirtualKeyboardCreateInfoMETA;
+
+typedef struct XrVirtualKeyboardSpaceCreateInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrVirtualKeyboardLocationTypeMETA locationType;
+ XrSpace space;
+ XrPosef poseInSpace;
+} XrVirtualKeyboardSpaceCreateInfoMETA;
+
+typedef struct XrVirtualKeyboardLocationInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrVirtualKeyboardLocationTypeMETA locationType;
+ XrSpace space;
+ XrPosef poseInSpace;
+ float scale;
+} XrVirtualKeyboardLocationInfoMETA;
+
+typedef struct XrVirtualKeyboardModelVisibilitySetInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrBool32 visible;
+} XrVirtualKeyboardModelVisibilitySetInfoMETA;
+
+typedef struct XrVirtualKeyboardAnimationStateMETA {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ int32_t animationIndex;
+ float fraction;
+} XrVirtualKeyboardAnimationStateMETA;
+
+typedef struct XrVirtualKeyboardModelAnimationStatesMETA {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ uint32_t stateCapacityInput;
+ uint32_t stateCountOutput;
+ XrVirtualKeyboardAnimationStateMETA* states;
+} XrVirtualKeyboardModelAnimationStatesMETA;
+
+typedef struct XrVirtualKeyboardTextureDataMETA {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ uint32_t textureWidth;
+ uint32_t textureHeight;
+ uint32_t bufferCapacityInput;
+ uint32_t bufferCountOutput;
+ uint8_t* buffer;
+} XrVirtualKeyboardTextureDataMETA;
+
+typedef struct XrVirtualKeyboardInputInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrVirtualKeyboardInputSourceMETA inputSource;
+ XrSpace inputSpace;
+ XrPosef inputPoseInSpace;
+ XrVirtualKeyboardInputStateFlagsMETA inputState;
+} XrVirtualKeyboardInputInfoMETA;
+
+typedef struct XrVirtualKeyboardTextContextChangeInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ const char* textContext;
+} XrVirtualKeyboardTextContextChangeInfoMETA;
+
+typedef struct XrEventDataVirtualKeyboardCommitTextMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrVirtualKeyboardMETA keyboard;
+ char text[XR_MAX_VIRTUAL_KEYBOARD_COMMIT_TEXT_SIZE_META];
+} XrEventDataVirtualKeyboardCommitTextMETA;
+
+typedef struct XrEventDataVirtualKeyboardBackspaceMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrVirtualKeyboardMETA keyboard;
+} XrEventDataVirtualKeyboardBackspaceMETA;
+
+typedef struct XrEventDataVirtualKeyboardEnterMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrVirtualKeyboardMETA keyboard;
+} XrEventDataVirtualKeyboardEnterMETA;
+
+typedef struct XrEventDataVirtualKeyboardShownMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrVirtualKeyboardMETA keyboard;
+} XrEventDataVirtualKeyboardShownMETA;
+
+typedef struct XrEventDataVirtualKeyboardHiddenMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrVirtualKeyboardMETA keyboard;
+} XrEventDataVirtualKeyboardHiddenMETA;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateVirtualKeyboardMETA)(XrSession session, const XrVirtualKeyboardCreateInfoMETA* createInfo, XrVirtualKeyboardMETA* keyboard);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyVirtualKeyboardMETA)(XrVirtualKeyboardMETA keyboard);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateVirtualKeyboardSpaceMETA)(XrSession session, XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardSpaceCreateInfoMETA* createInfo, XrSpace* keyboardSpace);
+typedef XrResult (XRAPI_PTR *PFN_xrSuggestVirtualKeyboardLocationMETA)(XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardLocationInfoMETA* locationInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrGetVirtualKeyboardScaleMETA)(XrVirtualKeyboardMETA keyboard, float* scale);
+typedef XrResult (XRAPI_PTR *PFN_xrSetVirtualKeyboardModelVisibilityMETA)(XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardModelVisibilitySetInfoMETA* modelVisibility);
+typedef XrResult (XRAPI_PTR *PFN_xrGetVirtualKeyboardModelAnimationStatesMETA)(XrVirtualKeyboardMETA keyboard, XrVirtualKeyboardModelAnimationStatesMETA* animationStates);
+typedef XrResult (XRAPI_PTR *PFN_xrGetVirtualKeyboardDirtyTexturesMETA)(XrVirtualKeyboardMETA keyboard, uint32_t textureIdCapacityInput, uint32_t* textureIdCountOutput, uint64_t* textureIds);
+typedef XrResult (XRAPI_PTR *PFN_xrGetVirtualKeyboardTextureDataMETA)(XrVirtualKeyboardMETA keyboard, uint64_t textureId, XrVirtualKeyboardTextureDataMETA* textureData);
+typedef XrResult (XRAPI_PTR *PFN_xrSendVirtualKeyboardInputMETA)(XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardInputInfoMETA* info, XrPosef* interactorRootPose);
+typedef XrResult (XRAPI_PTR *PFN_xrChangeVirtualKeyboardTextContextMETA)(XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardTextContextChangeInfoMETA* changeInfo);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateVirtualKeyboardMETA(
+ XrSession session,
+ const XrVirtualKeyboardCreateInfoMETA* createInfo,
+ XrVirtualKeyboardMETA* keyboard);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyVirtualKeyboardMETA(
+ XrVirtualKeyboardMETA keyboard);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateVirtualKeyboardSpaceMETA(
+ XrSession session,
+ XrVirtualKeyboardMETA keyboard,
+ const XrVirtualKeyboardSpaceCreateInfoMETA* createInfo,
+ XrSpace* keyboardSpace);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSuggestVirtualKeyboardLocationMETA(
+ XrVirtualKeyboardMETA keyboard,
+ const XrVirtualKeyboardLocationInfoMETA* locationInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetVirtualKeyboardScaleMETA(
+ XrVirtualKeyboardMETA keyboard,
+ float* scale);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSetVirtualKeyboardModelVisibilityMETA(
+ XrVirtualKeyboardMETA keyboard,
+ const XrVirtualKeyboardModelVisibilitySetInfoMETA* modelVisibility);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetVirtualKeyboardModelAnimationStatesMETA(
+ XrVirtualKeyboardMETA keyboard,
+ XrVirtualKeyboardModelAnimationStatesMETA* animationStates);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetVirtualKeyboardDirtyTexturesMETA(
+ XrVirtualKeyboardMETA keyboard,
+ uint32_t textureIdCapacityInput,
+ uint32_t* textureIdCountOutput,
+ uint64_t* textureIds);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetVirtualKeyboardTextureDataMETA(
+ XrVirtualKeyboardMETA keyboard,
+ uint64_t textureId,
+ XrVirtualKeyboardTextureDataMETA* textureData);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSendVirtualKeyboardInputMETA(
+ XrVirtualKeyboardMETA keyboard,
+ const XrVirtualKeyboardInputInfoMETA* info,
+ XrPosef* interactorRootPose);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrChangeVirtualKeyboardTextContextMETA(
+ XrVirtualKeyboardMETA keyboard,
+ const XrVirtualKeyboardTextContextChangeInfoMETA* changeInfo);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_OCULUS_external_camera 1
+#define XR_MAX_EXTERNAL_CAMERA_NAME_SIZE_OCULUS 32
+#define XR_OCULUS_external_camera_SPEC_VERSION 1
+#define XR_OCULUS_EXTERNAL_CAMERA_EXTENSION_NAME "XR_OCULUS_external_camera"
+
+typedef enum XrExternalCameraAttachedToDeviceOCULUS {
+ XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_NONE_OCULUS = 0,
+ XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_HMD_OCULUS = 1,
+ XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_LTOUCH_OCULUS = 2,
+ XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_RTOUCH_OCULUS = 3,
+ XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_MAX_ENUM_OCULUS = 0x7FFFFFFF
+} XrExternalCameraAttachedToDeviceOCULUS;
+typedef XrFlags64 XrExternalCameraStatusFlagsOCULUS;
+
+// Flag bits for XrExternalCameraStatusFlagsOCULUS
+static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CONNECTED_BIT_OCULUS = 0x00000001;
+static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CALIBRATING_BIT_OCULUS = 0x00000002;
+static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CALIBRATION_FAILED_BIT_OCULUS = 0x00000004;
+static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CALIBRATED_BIT_OCULUS = 0x00000008;
+static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CAPTURING_BIT_OCULUS = 0x00000010;
+
+typedef struct XrExternalCameraIntrinsicsOCULUS {
+ XrTime lastChangeTime;
+ XrFovf fov;
+ float virtualNearPlaneDistance;
+ float virtualFarPlaneDistance;
+ XrExtent2Di imageSensorPixelResolution;
+} XrExternalCameraIntrinsicsOCULUS;
+
+typedef struct XrExternalCameraExtrinsicsOCULUS {
+ XrTime lastChangeTime;
+ XrExternalCameraStatusFlagsOCULUS cameraStatusFlags;
+ XrExternalCameraAttachedToDeviceOCULUS attachedToDevice;
+ XrPosef relativePose;
+} XrExternalCameraExtrinsicsOCULUS;
+
+typedef struct XrExternalCameraOCULUS {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ char name[XR_MAX_EXTERNAL_CAMERA_NAME_SIZE_OCULUS];
+ XrExternalCameraIntrinsicsOCULUS intrinsics;
+ XrExternalCameraExtrinsicsOCULUS extrinsics;
+} XrExternalCameraOCULUS;
+
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateExternalCamerasOCULUS)(XrSession session, uint32_t cameraCapacityInput, uint32_t* cameraCountOutput, XrExternalCameraOCULUS* cameras);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateExternalCamerasOCULUS(
+ XrSession session,
+ uint32_t cameraCapacityInput,
+ uint32_t* cameraCountOutput,
+ XrExternalCameraOCULUS* cameras);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_META_performance_metrics 1
#define XR_META_performance_metrics_SPEC_VERSION 2
#define XR_META_PERFORMANCE_METRICS_EXTENSION_NAME "XR_META_performance_metrics"
@@ -4580,6 +5560,67 @@ XRAPI_ATTR XrResult XRAPI_CALL xrQueryPerformanceMetricsCounterMETA(
#endif /* !XR_NO_PROTOTYPES */
+#define XR_FB_spatial_entity_storage_batch 1
+#define XR_FB_spatial_entity_storage_batch_SPEC_VERSION 1
+#define XR_FB_SPATIAL_ENTITY_STORAGE_BATCH_EXTENSION_NAME "XR_FB_spatial_entity_storage_batch"
+typedef struct XrSpaceListSaveInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ uint32_t spaceCount;
+ XrSpace* spaces;
+ XrSpaceStorageLocationFB location;
+} XrSpaceListSaveInfoFB;
+
+typedef struct XrEventDataSpaceListSaveCompleteFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrAsyncRequestIdFB requestId;
+ XrResult result;
+} XrEventDataSpaceListSaveCompleteFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrSaveSpaceListFB)(XrSession session, const XrSpaceListSaveInfoFB* info, XrAsyncRequestIdFB* requestId);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrSaveSpaceListFB(
+ XrSession session,
+ const XrSpaceListSaveInfoFB* info,
+ XrAsyncRequestIdFB* requestId);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_spatial_entity_user 1
+typedef uint64_t XrSpaceUserIdFB;
+#define XR_FB_spatial_entity_user_SPEC_VERSION 1
+#define XR_FB_SPATIAL_ENTITY_USER_EXTENSION_NAME "XR_FB_spatial_entity_user"
+typedef struct XrSpaceUserCreateInfoFB {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrSpaceUserIdFB userId;
+} XrSpaceUserCreateInfoFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSpaceUserFB)(XrSession session, const XrSpaceUserCreateInfoFB* info, XrSpaceUserFB* user);
+typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceUserIdFB)(XrSpaceUserFB user, XrSpaceUserIdFB* userId);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroySpaceUserFB)(XrSpaceUserFB user);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpaceUserFB(
+ XrSession session,
+ const XrSpaceUserCreateInfoFB* info,
+ XrSpaceUserFB* user);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceUserIdFB(
+ XrSpaceUserFB user,
+ XrSpaceUserIdFB* userId);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpaceUserFB(
+ XrSpaceUserFB user);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_META_headset_id 1
#define XR_META_headset_id_SPEC_VERSION 1
#define XR_META_HEADSET_ID_EXTENSION_NAME "XR_META_headset_id"
@@ -4592,11 +5633,119 @@ typedef struct XrSystemHeadsetIdPropertiesMETA {
+#define XR_META_passthrough_color_lut 1
+XR_DEFINE_HANDLE(XrPassthroughColorLutMETA)
+#define XR_META_passthrough_color_lut_SPEC_VERSION 1
+#define XR_META_PASSTHROUGH_COLOR_LUT_EXTENSION_NAME "XR_META_passthrough_color_lut"
+
+typedef enum XrPassthroughColorLutChannelsMETA {
+ XR_PASSTHROUGH_COLOR_LUT_CHANNELS_RGB_META = 1,
+ XR_PASSTHROUGH_COLOR_LUT_CHANNELS_RGBA_META = 2,
+ XR_PASSTHROUGH_COLOR_LUT_CHANNELS_MAX_ENUM_META = 0x7FFFFFFF
+} XrPassthroughColorLutChannelsMETA;
+typedef struct XrPassthroughColorLutDataMETA {
+ uint32_t bufferSize;
+ const uint8_t* buffer;
+} XrPassthroughColorLutDataMETA;
+
+typedef struct XrPassthroughColorLutCreateInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrPassthroughColorLutChannelsMETA channels;
+ uint32_t resolution;
+ XrPassthroughColorLutDataMETA data;
+} XrPassthroughColorLutCreateInfoMETA;
+
+typedef struct XrPassthroughColorLutUpdateInfoMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrPassthroughColorLutDataMETA data;
+} XrPassthroughColorLutUpdateInfoMETA;
+
+// XrPassthroughColorMapLutMETA extends XrPassthroughStyleFB
+typedef struct XrPassthroughColorMapLutMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrPassthroughColorLutMETA colorLut;
+ float weight;
+} XrPassthroughColorMapLutMETA;
+
+// XrPassthroughColorMapInterpolatedLutMETA extends XrPassthroughStyleFB
+typedef struct XrPassthroughColorMapInterpolatedLutMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrPassthroughColorLutMETA sourceColorLut;
+ XrPassthroughColorLutMETA targetColorLut;
+ float weight;
+} XrPassthroughColorMapInterpolatedLutMETA;
+
+// XrSystemPassthroughColorLutPropertiesMETA extends XrSystemProperties
+typedef struct XrSystemPassthroughColorLutPropertiesMETA {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ uint32_t maxColorLutResolution;
+} XrSystemPassthroughColorLutPropertiesMETA;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughColorLutMETA)(XrPassthroughFB passthrough, const XrPassthroughColorLutCreateInfoMETA* createInfo, XrPassthroughColorLutMETA* colorLut);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughColorLutMETA)(XrPassthroughColorLutMETA colorLut);
+typedef XrResult (XRAPI_PTR *PFN_xrUpdatePassthroughColorLutMETA)(XrPassthroughColorLutMETA colorLut, const XrPassthroughColorLutUpdateInfoMETA* updateInfo);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughColorLutMETA(
+ XrPassthroughFB passthrough,
+ const XrPassthroughColorLutCreateInfoMETA* createInfo,
+ XrPassthroughColorLutMETA* colorLut);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughColorLutMETA(
+ XrPassthroughColorLutMETA colorLut);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrUpdatePassthroughColorLutMETA(
+ XrPassthroughColorLutMETA colorLut,
+ const XrPassthroughColorLutUpdateInfoMETA* updateInfo);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_EXT_uuid 1
#define XR_EXT_uuid_SPEC_VERSION 1
#define XR_EXT_UUID_EXTENSION_NAME "XR_EXT_uuid"
+#define XR_EXT_hand_interaction 1
+#define XR_EXT_hand_interaction_SPEC_VERSION 1
+#define XR_EXT_HAND_INTERACTION_EXTENSION_NAME "XR_EXT_hand_interaction"
+
+
+#define XR_QCOM_tracking_optimization_settings 1
+#define XR_QCOM_tracking_optimization_settings_SPEC_VERSION 1
+#define XR_QCOM_TRACKING_OPTIMIZATION_SETTINGS_EXTENSION_NAME "XR_QCOM_tracking_optimization_settings"
+
+typedef enum XrTrackingOptimizationSettingsDomainQCOM {
+ XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_ALL_QCOM = 1,
+ XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_MAX_ENUM_QCOM = 0x7FFFFFFF
+} XrTrackingOptimizationSettingsDomainQCOM;
+
+typedef enum XrTrackingOptimizationSettingsHintQCOM {
+ XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_NONE_QCOM = 0,
+ XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_LONG_RANGE_PRIORIZATION_QCOM = 1,
+ XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_CLOSE_RANGE_PRIORIZATION_QCOM = 2,
+ XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_LOW_POWER_PRIORIZATION_QCOM = 3,
+ XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_HIGH_POWER_PRIORIZATION_QCOM = 4,
+ XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_MAX_ENUM_QCOM = 0x7FFFFFFF
+} XrTrackingOptimizationSettingsHintQCOM;
+typedef XrResult (XRAPI_PTR *PFN_xrSetTrackingOptimizationSettingsHintQCOM)(XrSession session, XrTrackingOptimizationSettingsDomainQCOM domain, XrTrackingOptimizationSettingsHintQCOM hint);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrSetTrackingOptimizationSettingsHintQCOM(
+ XrSession session,
+ XrTrackingOptimizationSettingsDomainQCOM domain,
+ XrTrackingOptimizationSettingsHintQCOM hint);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
#define XR_HTC_passthrough 1
XR_DEFINE_HANDLE(XrPassthroughHTC)
#define XR_HTC_passthrough_SPEC_VERSION 1
@@ -4741,6 +5890,244 @@ typedef struct XrActiveActionSetPrioritiesEXT {
} XrActiveActionSetPrioritiesEXT;
+
+#define XR_MNDX_force_feedback_curl 1
+#define XR_MNDX_force_feedback_curl_SPEC_VERSION 1
+#define XR_MNDX_FORCE_FEEDBACK_CURL_EXTENSION_NAME "XR_MNDX_force_feedback_curl"
+
+typedef enum XrForceFeedbackCurlLocationMNDX {
+ XR_FORCE_FEEDBACK_CURL_LOCATION_THUMB_CURL_MNDX = 0,
+ XR_FORCE_FEEDBACK_CURL_LOCATION_INDEX_CURL_MNDX = 1,
+ XR_FORCE_FEEDBACK_CURL_LOCATION_MIDDLE_CURL_MNDX = 2,
+ XR_FORCE_FEEDBACK_CURL_LOCATION_RING_CURL_MNDX = 3,
+ XR_FORCE_FEEDBACK_CURL_LOCATION_LITTLE_CURL_MNDX = 4,
+ XR_FORCE_FEEDBACK_CURL_LOCATION_MAX_ENUM_MNDX = 0x7FFFFFFF
+} XrForceFeedbackCurlLocationMNDX;
+// XrSystemForceFeedbackCurlPropertiesMNDX extends XrSystemProperties
+typedef struct XrSystemForceFeedbackCurlPropertiesMNDX {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 supportsForceFeedbackCurl;
+} XrSystemForceFeedbackCurlPropertiesMNDX;
+
+typedef struct XrForceFeedbackCurlApplyLocationMNDX {
+ XrForceFeedbackCurlLocationMNDX location;
+ float value;
+} XrForceFeedbackCurlApplyLocationMNDX;
+
+typedef struct XrForceFeedbackCurlApplyLocationsMNDX {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ uint32_t locationCount;
+ XrForceFeedbackCurlApplyLocationMNDX* locations;
+} XrForceFeedbackCurlApplyLocationsMNDX;
+
+typedef XrResult (XRAPI_PTR *PFN_xrApplyForceFeedbackCurlMNDX)(XrHandTrackerEXT handTracker, const XrForceFeedbackCurlApplyLocationsMNDX* locations);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrApplyForceFeedbackCurlMNDX(
+ XrHandTrackerEXT handTracker,
+ const XrForceFeedbackCurlApplyLocationsMNDX* locations);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_BD_controller_interaction 1
+#define XR_BD_controller_interaction_SPEC_VERSION 1
+#define XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_BD_controller_interaction"
+
+
+#define XR_EXT_local_floor 1
+#define XR_EXT_local_floor_SPEC_VERSION 1
+#define XR_EXT_LOCAL_FLOOR_EXTENSION_NAME "XR_EXT_local_floor"
+
+
+#define XR_EXT_hand_tracking_data_source 1
+#define XR_EXT_hand_tracking_data_source_SPEC_VERSION 1
+#define XR_EXT_HAND_TRACKING_DATA_SOURCE_EXTENSION_NAME "XR_EXT_hand_tracking_data_source"
+
+typedef enum XrHandTrackingDataSourceEXT {
+ XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT = 1,
+ XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT = 2,
+ XR_HAND_TRACKING_DATA_SOURCE_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrHandTrackingDataSourceEXT;
+// XrHandTrackingDataSourceInfoEXT extends XrHandTrackerCreateInfoEXT
+typedef struct XrHandTrackingDataSourceInfoEXT {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ uint32_t requestedDataSourceCount;
+ XrHandTrackingDataSourceEXT* requestedDataSources;
+} XrHandTrackingDataSourceInfoEXT;
+
+// XrHandTrackingDataSourceStateEXT extends XrHandJointLocationsEXT
+typedef struct XrHandTrackingDataSourceStateEXT {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrBool32 isActive;
+ XrHandTrackingDataSourceEXT dataSource;
+} XrHandTrackingDataSourceStateEXT;
+
+
+
+#define XR_EXT_plane_detection 1
+XR_DEFINE_HANDLE(XrPlaneDetectorEXT)
+#define XR_EXT_plane_detection_SPEC_VERSION 1
+#define XR_EXT_PLANE_DETECTION_EXTENSION_NAME "XR_EXT_plane_detection"
+
+typedef enum XrPlaneDetectorOrientationEXT {
+ XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_UPWARD_EXT = 0,
+ XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_DOWNWARD_EXT = 1,
+ XR_PLANE_DETECTOR_ORIENTATION_VERTICAL_EXT = 2,
+ XR_PLANE_DETECTOR_ORIENTATION_ARBITRARY_EXT = 3,
+ XR_PLANE_DETECTOR_ORIENTATION_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrPlaneDetectorOrientationEXT;
+
+typedef enum XrPlaneDetectorSemanticTypeEXT {
+ XR_PLANE_DETECTOR_SEMANTIC_TYPE_UNDEFINED_EXT = 0,
+ XR_PLANE_DETECTOR_SEMANTIC_TYPE_CEILING_EXT = 1,
+ XR_PLANE_DETECTOR_SEMANTIC_TYPE_FLOOR_EXT = 2,
+ XR_PLANE_DETECTOR_SEMANTIC_TYPE_WALL_EXT = 3,
+ XR_PLANE_DETECTOR_SEMANTIC_TYPE_PLATFORM_EXT = 4,
+ XR_PLANE_DETECTOR_SEMANTIC_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrPlaneDetectorSemanticTypeEXT;
+
+typedef enum XrPlaneDetectionStateEXT {
+ XR_PLANE_DETECTION_STATE_NONE_EXT = 0,
+ XR_PLANE_DETECTION_STATE_PENDING_EXT = 1,
+ XR_PLANE_DETECTION_STATE_DONE_EXT = 2,
+ XR_PLANE_DETECTION_STATE_ERROR_EXT = 3,
+ XR_PLANE_DETECTION_STATE_FATAL_EXT = 4,
+ XR_PLANE_DETECTION_STATE_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrPlaneDetectionStateEXT;
+typedef XrFlags64 XrPlaneDetectionCapabilityFlagsEXT;
+
+// Flag bits for XrPlaneDetectionCapabilityFlagsEXT
+static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_PLANE_DETECTION_BIT_EXT = 0x00000001;
+static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_PLANE_HOLES_BIT_EXT = 0x00000002;
+static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_CEILING_BIT_EXT = 0x00000004;
+static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_FLOOR_BIT_EXT = 0x00000008;
+static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_WALL_BIT_EXT = 0x00000010;
+static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_PLATFORM_BIT_EXT = 0x00000020;
+static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_ORIENTATION_BIT_EXT = 0x00000040;
+
+typedef XrFlags64 XrPlaneDetectorFlagsEXT;
+
+// Flag bits for XrPlaneDetectorFlagsEXT
+static const XrPlaneDetectorFlagsEXT XR_PLANE_DETECTOR_ENABLE_CONTOUR_BIT_EXT = 0x00000001;
+
+// XrSystemPlaneDetectionPropertiesEXT extends XrSystemProperties
+typedef struct XrSystemPlaneDetectionPropertiesEXT {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ XrPlaneDetectionCapabilityFlagsEXT supportedFeatures;
+} XrSystemPlaneDetectionPropertiesEXT;
+
+typedef struct XrPlaneDetectorCreateInfoEXT {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrPlaneDetectorFlagsEXT flags;
+} XrPlaneDetectorCreateInfoEXT;
+
+typedef struct XrExtent3DfEXT {
+ float width;
+ float height;
+ float depth;
+} XrExtent3DfEXT;
+
+typedef struct XrPlaneDetectorBeginInfoEXT {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrSpace baseSpace;
+ XrTime time;
+ uint32_t orientationCount;
+ const XrPlaneDetectorOrientationEXT* orientations;
+ uint32_t semanticTypeCount;
+ const XrPlaneDetectorSemanticTypeEXT* semanticTypes;
+ uint32_t maxPlanes;
+ float minArea;
+ XrPosef boundingBoxPose;
+ XrExtent3DfEXT boundingBoxExtent;
+} XrPlaneDetectorBeginInfoEXT;
+
+typedef struct XrPlaneDetectorGetInfoEXT {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ XrSpace baseSpace;
+ XrTime time;
+} XrPlaneDetectorGetInfoEXT;
+
+typedef struct XrPlaneDetectorLocationEXT {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ uint64_t planeId;
+ XrSpaceLocationFlags locationFlags;
+ XrPosef pose;
+ XrExtent2Df extents;
+ XrPlaneDetectorOrientationEXT orientation;
+ XrPlaneDetectorSemanticTypeEXT semanticType;
+ uint32_t polygonBufferCount;
+} XrPlaneDetectorLocationEXT;
+
+typedef struct XrPlaneDetectorLocationsEXT {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ uint32_t planeLocationCapacityInput;
+ uint32_t planeLocationCountOutput;
+ XrPlaneDetectorLocationEXT* planeLocations;
+} XrPlaneDetectorLocationsEXT;
+
+typedef struct XrPlaneDetectorPolygonBufferEXT {
+ XrStructureType type;
+ void* XR_MAY_ALIAS next;
+ uint32_t vertexCapacityInput;
+ uint32_t vertexCountOutput;
+ XrVector2f* vertices;
+} XrPlaneDetectorPolygonBufferEXT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreatePlaneDetectorEXT)(XrSession session, const XrPlaneDetectorCreateInfoEXT* createInfo, XrPlaneDetectorEXT* planeDetector);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyPlaneDetectorEXT)(XrPlaneDetectorEXT planeDetector);
+typedef XrResult (XRAPI_PTR *PFN_xrBeginPlaneDetectionEXT)(XrPlaneDetectorEXT planeDetector, const XrPlaneDetectorBeginInfoEXT* beginInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrGetPlaneDetectionStateEXT)(XrPlaneDetectorEXT planeDetector, XrPlaneDetectionStateEXT* state);
+typedef XrResult (XRAPI_PTR *PFN_xrGetPlaneDetectionsEXT)(XrPlaneDetectorEXT planeDetector, const XrPlaneDetectorGetInfoEXT* info, XrPlaneDetectorLocationsEXT* locations);
+typedef XrResult (XRAPI_PTR *PFN_xrGetPlanePolygonBufferEXT)(XrPlaneDetectorEXT planeDetector, uint64_t planeId, uint32_t polygonBufferIndex, XrPlaneDetectorPolygonBufferEXT* polygonBuffer);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreatePlaneDetectorEXT(
+ XrSession session,
+ const XrPlaneDetectorCreateInfoEXT* createInfo,
+ XrPlaneDetectorEXT* planeDetector);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPlaneDetectorEXT(
+ XrPlaneDetectorEXT planeDetector);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrBeginPlaneDetectionEXT(
+ XrPlaneDetectorEXT planeDetector,
+ const XrPlaneDetectorBeginInfoEXT* beginInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetPlaneDetectionStateEXT(
+ XrPlaneDetectorEXT planeDetector,
+ XrPlaneDetectionStateEXT* state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetPlaneDetectionsEXT(
+ XrPlaneDetectorEXT planeDetector,
+ const XrPlaneDetectorGetInfoEXT* info,
+ XrPlaneDetectorLocationsEXT* locations);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetPlanePolygonBufferEXT(
+ XrPlaneDetectorEXT planeDetector,
+ uint64_t planeId,
+ uint32_t polygonBufferIndex,
+ XrPlaneDetectorPolygonBufferEXT* polygonBuffer);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_OPPO_controller_interaction 1
+#define XR_OPPO_controller_interaction_SPEC_VERSION 1
+#define XR_OPPO_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_OPPO_controller_interaction"
+
#ifdef __cplusplus
}
#endif
diff --git a/thirdparty/openxr/include/openxr/openxr_platform.h b/thirdparty/openxr/include/openxr/openxr_platform.h
index b3aabb23c5..b0a5328f3e 100644
--- a/thirdparty/openxr/include/openxr/openxr_platform.h
+++ b/thirdparty/openxr/include/openxr/openxr_platform.h
@@ -2,7 +2,7 @@
#define OPENXR_PLATFORM_H_ 1
/*
-** Copyright 2017-2022 The Khronos Group Inc.
+** Copyright 2017-2023 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -454,9 +454,9 @@ typedef XrSwapchainImageVulkanKHR XrSwapchainImageVulkan2KHR;
typedef XrGraphicsRequirementsVulkanKHR XrGraphicsRequirementsVulkan2KHR;
-typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult);
-typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanDeviceKHR)(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult);
-typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDevice2KHR)(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, VkPhysicalDevice* vulkanPhysicalDevice);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanDeviceKHR)(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult);
+typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDevice2KHR)(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, VkPhysicalDevice* vulkanPhysicalDevice);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirements2KHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
@@ -565,6 +565,30 @@ typedef struct XrAndroidSurfaceSwapchainCreateInfoFB {
#endif /* XR_USE_PLATFORM_ANDROID */
+#ifdef XR_USE_PLATFORM_ML
+
+#define XR_ML_compat 1
+#define XR_ML_compat_SPEC_VERSION 1
+#define XR_ML_COMPAT_EXTENSION_NAME "XR_ML_compat"
+typedef struct XrCoordinateSpaceCreateInfoML {
+ XrStructureType type;
+ const void* XR_MAY_ALIAS next;
+ MLCoordinateFrameUID cfuid;
+ XrPosef poseInCoordinateSpace;
+} XrCoordinateSpaceCreateInfoML;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSpaceFromCoordinateFrameUIDML)(XrSession session, const XrCoordinateSpaceCreateInfoML *createInfo, XrSpace* space);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpaceFromCoordinateFrameUIDML(
+ XrSession session,
+ const XrCoordinateSpaceCreateInfoML * createInfo,
+ XrSpace* space);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+#endif /* XR_USE_PLATFORM_ML */
+
#ifdef XR_USE_PLATFORM_WIN32
#define XR_OCULUS_audio_device_guid 1
diff --git a/thirdparty/openxr/include/openxr/openxr_platform_defines.h b/thirdparty/openxr/include/openxr/openxr_platform_defines.h
index 31fa05a0c8..820b7b3e1e 100644
--- a/thirdparty/openxr/include/openxr/openxr_platform_defines.h
+++ b/thirdparty/openxr/include/openxr/openxr_platform_defines.h
@@ -1,5 +1,5 @@
/*
-** Copyright (c) 2017-2022, The Khronos Group Inc.
+** Copyright (c) 2017-2023, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -65,7 +65,7 @@ typedef unsigned __int64 uint64_t;
#endif // !defined( XR_NO_STDINT_H )
// XR_PTR_SIZE (in bytes)
-#if (defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__))
+#if (defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(__powerpc64__))
#define XR_PTR_SIZE 8
#else
#define XR_PTR_SIZE 4
@@ -103,6 +103,10 @@ typedef unsigned __int64 uint64_t;
#endif
#endif
+#if !defined(XR_CPP_NULLPTR_SUPPORTED)
+#define XR_CPP_NULLPTR_SUPPORTED 0
+#endif // !defined(XR_CPP_NULLPTR_SUPPORTED)
+
#ifdef __cplusplus
}
#endif
diff --git a/thirdparty/openxr/include/openxr/openxr_reflection.h b/thirdparty/openxr/include/openxr/openxr_reflection.h
index 1a873c1770..c53d412365 100644
--- a/thirdparty/openxr/include/openxr/openxr_reflection.h
+++ b/thirdparty/openxr/include/openxr/openxr_reflection.h
@@ -2,7 +2,7 @@
#define OPENXR_REFLECTION_H_ 1
/*
-** Copyright (c) 2017-2022, The Khronos Group Inc.
+** Copyright (c) 2017-2023, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -116,6 +116,15 @@ XR_ENUM_STR(XrResult);
_(XR_ERROR_MARKER_ID_INVALID_VARJO, -1000124001) \
_(XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT, -1000142001) \
_(XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT, -1000142002) \
+ _(XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB, -1000169000) \
+ _(XR_ERROR_SPACE_LOCALIZATION_FAILED_FB, -1000169001) \
+ _(XR_ERROR_SPACE_NETWORK_TIMEOUT_FB, -1000169002) \
+ _(XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB, -1000169003) \
+ _(XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB, -1000169004) \
+ _(XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META, -1000266000) \
+ _(XR_ERROR_HINT_ALREADY_SET_QCOM, -1000306000) \
+ _(XR_ERROR_SPACE_NOT_LOCATABLE_EXT, -1000429000) \
+ _(XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT, -1000429001) \
_(XR_RESULT_MAX_ENUM, 0x7FFFFFFF)
#define XR_LIST_ENUM_XrStructureType(_) \
@@ -242,6 +251,11 @@ XR_ENUM_STR(XrResult);
_(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT, 1000066001) \
_(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB, 1000070000) \
_(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB, 1000072000) \
+ _(XR_TYPE_BODY_TRACKER_CREATE_INFO_FB, 1000076001) \
+ _(XR_TYPE_BODY_JOINTS_LOCATE_INFO_FB, 1000076002) \
+ _(XR_TYPE_SYSTEM_BODY_TRACKING_PROPERTIES_FB, 1000076004) \
+ _(XR_TYPE_BODY_JOINT_LOCATIONS_FB, 1000076005) \
+ _(XR_TYPE_BODY_SKELETON_FB, 1000076006) \
_(XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT, 1000078000) \
_(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE, 1000079000) \
_(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, 1000080000) \
@@ -322,6 +336,9 @@ XR_ENUM_STR(XrResult);
_(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO, 1000124000) \
_(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO, 1000124001) \
_(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO, 1000124002) \
+ _(XR_TYPE_FRAME_END_INFO_ML, 1000135000) \
+ _(XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML, 1000136000) \
+ _(XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML, 1000137000) \
_(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT, 1000142000) \
_(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT, 1000142001) \
_(XR_TYPE_SPACE_QUERY_INFO_FB, 1000156001) \
@@ -339,19 +356,64 @@ XR_ENUM_STR(XrResult);
_(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB, 1000161000) \
_(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB, 1000162000) \
_(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB, 1000163000) \
+ _(XR_TYPE_SPACE_SHARE_INFO_FB, 1000169001) \
+ _(XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB, 1000169002) \
_(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB, 1000171000) \
_(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB, 1000171001) \
+ _(XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB, 1000173001) \
_(XR_TYPE_SEMANTIC_LABELS_FB, 1000175000) \
_(XR_TYPE_ROOM_LAYOUT_FB, 1000175001) \
_(XR_TYPE_BOUNDARY_2D_FB, 1000175002) \
+ _(XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB, 1000175010) \
_(XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE, 1000196000) \
+ _(XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB, 1000198001) \
+ _(XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB, 1000198050) \
_(XR_TYPE_SPACE_CONTAINER_FB, 1000199000) \
+ _(XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META, 1000200000) \
+ _(XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META, 1000200001) \
+ _(XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META, 1000200002) \
+ _(XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_FB, 1000201004) \
+ _(XR_TYPE_FACE_TRACKER_CREATE_INFO_FB, 1000201005) \
+ _(XR_TYPE_FACE_EXPRESSION_INFO_FB, 1000201002) \
+ _(XR_TYPE_FACE_EXPRESSION_WEIGHTS_FB, 1000201006) \
+ _(XR_TYPE_EYE_TRACKER_CREATE_INFO_FB, 1000202001) \
+ _(XR_TYPE_EYE_GAZES_INFO_FB, 1000202002) \
+ _(XR_TYPE_EYE_GAZES_FB, 1000202003) \
+ _(XR_TYPE_SYSTEM_EYE_TRACKING_PROPERTIES_FB, 1000202004) \
_(XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB, 1000203002) \
_(XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB, 1000204000) \
+ _(XR_TYPE_HAPTIC_PCM_VIBRATION_FB, 1000209001) \
+ _(XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB, 1000209002) \
+ _(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_FB, 1000212000) \
+ _(XR_TYPE_LOCAL_DIMMING_FRAME_END_INFO_META, 1000216000) \
+ _(XR_TYPE_SYSTEM_VIRTUAL_KEYBOARD_PROPERTIES_META, 1000219001) \
+ _(XR_TYPE_VIRTUAL_KEYBOARD_CREATE_INFO_META, 1000219002) \
+ _(XR_TYPE_VIRTUAL_KEYBOARD_SPACE_CREATE_INFO_META, 1000219003) \
+ _(XR_TYPE_VIRTUAL_KEYBOARD_LOCATION_INFO_META, 1000219004) \
+ _(XR_TYPE_VIRTUAL_KEYBOARD_MODEL_VISIBILITY_SET_INFO_META, 1000219005) \
+ _(XR_TYPE_VIRTUAL_KEYBOARD_ANIMATION_STATE_META, 1000219006) \
+ _(XR_TYPE_VIRTUAL_KEYBOARD_MODEL_ANIMATION_STATES_META, 1000219007) \
+ _(XR_TYPE_VIRTUAL_KEYBOARD_TEXTURE_DATA_META, 1000219009) \
+ _(XR_TYPE_VIRTUAL_KEYBOARD_INPUT_INFO_META, 1000219010) \
+ _(XR_TYPE_VIRTUAL_KEYBOARD_TEXT_CONTEXT_CHANGE_INFO_META, 1000219011) \
+ _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_COMMIT_TEXT_META, 1000219014) \
+ _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_BACKSPACE_META, 1000219015) \
+ _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_ENTER_META, 1000219016) \
+ _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_SHOWN_META, 1000219017) \
+ _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_HIDDEN_META, 1000219018) \
+ _(XR_TYPE_EXTERNAL_CAMERA_OCULUS, 1000226000) \
_(XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META, 1000227000) \
_(XR_TYPE_PERFORMANCE_METRICS_STATE_META, 1000232001) \
_(XR_TYPE_PERFORMANCE_METRICS_COUNTER_META, 1000232002) \
+ _(XR_TYPE_SPACE_LIST_SAVE_INFO_FB, 1000238000) \
+ _(XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB, 1000238001) \
+ _(XR_TYPE_SPACE_USER_CREATE_INFO_FB, 1000241001) \
_(XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META, 1000245000) \
+ _(XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META, 1000266000) \
+ _(XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META, 1000266001) \
+ _(XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META, 1000266002) \
+ _(XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META, 1000266100) \
+ _(XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META, 1000266101) \
_(XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC, 1000317001) \
_(XR_TYPE_PASSTHROUGH_COLOR_HTC, 1000317002) \
_(XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC, 1000317003) \
@@ -360,6 +422,17 @@ XR_ENUM_STR(XrResult);
_(XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC, 1000318001) \
_(XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC, 1000318002) \
_(XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT, 1000373000) \
+ _(XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX, 1000375000) \
+ _(XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX, 1000375001) \
+ _(XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT, 1000428000) \
+ _(XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT, 1000428001) \
+ _(XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT, 1000429001) \
+ _(XR_TYPE_PLANE_DETECTOR_BEGIN_INFO_EXT, 1000429002) \
+ _(XR_TYPE_PLANE_DETECTOR_GET_INFO_EXT, 1000429003) \
+ _(XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT, 1000429004) \
+ _(XR_TYPE_PLANE_DETECTOR_LOCATION_EXT, 1000429005) \
+ _(XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT, 1000429006) \
+ _(XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT, 1000429007) \
_(XR_STRUCTURE_TYPE_MAX_ENUM, 0x7FFFFFFF)
#define XR_LIST_ENUM_XrFormFactor(_) \
@@ -386,6 +459,7 @@ XR_ENUM_STR(XrResult);
_(XR_REFERENCE_SPACE_TYPE_STAGE, 3) \
_(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT, 1000038000) \
_(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO, 1000121000) \
+ _(XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT, 1000426000) \
_(XR_REFERENCE_SPACE_TYPE_MAX_ENUM, 0x7FFFFFFF)
#define XR_LIST_ENUM_XrActionType(_) \
@@ -426,6 +500,7 @@ XR_ENUM_STR(XrResult);
_(XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT, 1000039000) \
_(XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT, 1000049000) \
_(XR_OBJECT_TYPE_HAND_TRACKER_EXT, 1000051000) \
+ _(XR_OBJECT_TYPE_BODY_TRACKER_FB, 1000076000) \
_(XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT, 1000097000) \
_(XR_OBJECT_TYPE_SCENE_MSFT, 1000097001) \
_(XR_OBJECT_TYPE_FACIAL_TRACKER_HTC, 1000104000) \
@@ -435,7 +510,13 @@ XR_ENUM_STR(XrResult);
_(XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB, 1000118002) \
_(XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB, 1000118004) \
_(XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT, 1000142000) \
+ _(XR_OBJECT_TYPE_FACE_TRACKER_FB, 1000201000) \
+ _(XR_OBJECT_TYPE_EYE_TRACKER_FB, 1000202000) \
+ _(XR_OBJECT_TYPE_VIRTUAL_KEYBOARD_META, 1000219000) \
+ _(XR_OBJECT_TYPE_SPACE_USER_FB, 1000241000) \
+ _(XR_OBJECT_TYPE_PASSTHROUGH_COLOR_LUT_META, 1000266000) \
_(XR_OBJECT_TYPE_PASSTHROUGH_HTC, 1000317000) \
+ _(XR_OBJECT_TYPE_PLANE_DETECTOR_EXT, 1000429000) \
_(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF)
#define XR_LIST_ENUM_XrAndroidThreadTypeKHR(_) \
@@ -540,6 +621,85 @@ XR_ENUM_STR(XrResult);
_(XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT, 4) \
_(XR_REPROJECTION_MODE_MAX_ENUM_MSFT, 0x7FFFFFFF)
+#define XR_LIST_ENUM_XrBodyJointFB(_) \
+ _(XR_BODY_JOINT_ROOT_FB, 0) \
+ _(XR_BODY_JOINT_HIPS_FB, 1) \
+ _(XR_BODY_JOINT_SPINE_LOWER_FB, 2) \
+ _(XR_BODY_JOINT_SPINE_MIDDLE_FB, 3) \
+ _(XR_BODY_JOINT_SPINE_UPPER_FB, 4) \
+ _(XR_BODY_JOINT_CHEST_FB, 5) \
+ _(XR_BODY_JOINT_NECK_FB, 6) \
+ _(XR_BODY_JOINT_HEAD_FB, 7) \
+ _(XR_BODY_JOINT_LEFT_SHOULDER_FB, 8) \
+ _(XR_BODY_JOINT_LEFT_SCAPULA_FB, 9) \
+ _(XR_BODY_JOINT_LEFT_ARM_UPPER_FB, 10) \
+ _(XR_BODY_JOINT_LEFT_ARM_LOWER_FB, 11) \
+ _(XR_BODY_JOINT_LEFT_HAND_WRIST_TWIST_FB, 12) \
+ _(XR_BODY_JOINT_RIGHT_SHOULDER_FB, 13) \
+ _(XR_BODY_JOINT_RIGHT_SCAPULA_FB, 14) \
+ _(XR_BODY_JOINT_RIGHT_ARM_UPPER_FB, 15) \
+ _(XR_BODY_JOINT_RIGHT_ARM_LOWER_FB, 16) \
+ _(XR_BODY_JOINT_RIGHT_HAND_WRIST_TWIST_FB, 17) \
+ _(XR_BODY_JOINT_LEFT_HAND_PALM_FB, 18) \
+ _(XR_BODY_JOINT_LEFT_HAND_WRIST_FB, 19) \
+ _(XR_BODY_JOINT_LEFT_HAND_THUMB_METACARPAL_FB, 20) \
+ _(XR_BODY_JOINT_LEFT_HAND_THUMB_PROXIMAL_FB, 21) \
+ _(XR_BODY_JOINT_LEFT_HAND_THUMB_DISTAL_FB, 22) \
+ _(XR_BODY_JOINT_LEFT_HAND_THUMB_TIP_FB, 23) \
+ _(XR_BODY_JOINT_LEFT_HAND_INDEX_METACARPAL_FB, 24) \
+ _(XR_BODY_JOINT_LEFT_HAND_INDEX_PROXIMAL_FB, 25) \
+ _(XR_BODY_JOINT_LEFT_HAND_INDEX_INTERMEDIATE_FB, 26) \
+ _(XR_BODY_JOINT_LEFT_HAND_INDEX_DISTAL_FB, 27) \
+ _(XR_BODY_JOINT_LEFT_HAND_INDEX_TIP_FB, 28) \
+ _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_METACARPAL_FB, 29) \
+ _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_PROXIMAL_FB, 30) \
+ _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_INTERMEDIATE_FB, 31) \
+ _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_DISTAL_FB, 32) \
+ _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_TIP_FB, 33) \
+ _(XR_BODY_JOINT_LEFT_HAND_RING_METACARPAL_FB, 34) \
+ _(XR_BODY_JOINT_LEFT_HAND_RING_PROXIMAL_FB, 35) \
+ _(XR_BODY_JOINT_LEFT_HAND_RING_INTERMEDIATE_FB, 36) \
+ _(XR_BODY_JOINT_LEFT_HAND_RING_DISTAL_FB, 37) \
+ _(XR_BODY_JOINT_LEFT_HAND_RING_TIP_FB, 38) \
+ _(XR_BODY_JOINT_LEFT_HAND_LITTLE_METACARPAL_FB, 39) \
+ _(XR_BODY_JOINT_LEFT_HAND_LITTLE_PROXIMAL_FB, 40) \
+ _(XR_BODY_JOINT_LEFT_HAND_LITTLE_INTERMEDIATE_FB, 41) \
+ _(XR_BODY_JOINT_LEFT_HAND_LITTLE_DISTAL_FB, 42) \
+ _(XR_BODY_JOINT_LEFT_HAND_LITTLE_TIP_FB, 43) \
+ _(XR_BODY_JOINT_RIGHT_HAND_PALM_FB, 44) \
+ _(XR_BODY_JOINT_RIGHT_HAND_WRIST_FB, 45) \
+ _(XR_BODY_JOINT_RIGHT_HAND_THUMB_METACARPAL_FB, 46) \
+ _(XR_BODY_JOINT_RIGHT_HAND_THUMB_PROXIMAL_FB, 47) \
+ _(XR_BODY_JOINT_RIGHT_HAND_THUMB_DISTAL_FB, 48) \
+ _(XR_BODY_JOINT_RIGHT_HAND_THUMB_TIP_FB, 49) \
+ _(XR_BODY_JOINT_RIGHT_HAND_INDEX_METACARPAL_FB, 50) \
+ _(XR_BODY_JOINT_RIGHT_HAND_INDEX_PROXIMAL_FB, 51) \
+ _(XR_BODY_JOINT_RIGHT_HAND_INDEX_INTERMEDIATE_FB, 52) \
+ _(XR_BODY_JOINT_RIGHT_HAND_INDEX_DISTAL_FB, 53) \
+ _(XR_BODY_JOINT_RIGHT_HAND_INDEX_TIP_FB, 54) \
+ _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_METACARPAL_FB, 55) \
+ _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_PROXIMAL_FB, 56) \
+ _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_INTERMEDIATE_FB, 57) \
+ _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_DISTAL_FB, 58) \
+ _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_TIP_FB, 59) \
+ _(XR_BODY_JOINT_RIGHT_HAND_RING_METACARPAL_FB, 60) \
+ _(XR_BODY_JOINT_RIGHT_HAND_RING_PROXIMAL_FB, 61) \
+ _(XR_BODY_JOINT_RIGHT_HAND_RING_INTERMEDIATE_FB, 62) \
+ _(XR_BODY_JOINT_RIGHT_HAND_RING_DISTAL_FB, 63) \
+ _(XR_BODY_JOINT_RIGHT_HAND_RING_TIP_FB, 64) \
+ _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_METACARPAL_FB, 65) \
+ _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_PROXIMAL_FB, 66) \
+ _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_INTERMEDIATE_FB, 67) \
+ _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_DISTAL_FB, 68) \
+ _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_TIP_FB, 69) \
+ _(XR_BODY_JOINT_COUNT_FB, 70) \
+ _(XR_BODY_JOINT_NONE_FB, -1) \
+ _(XR_BODY_JOINT_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrBodyJointSetFB(_) \
+ _(XR_BODY_JOINT_SET_DEFAULT_FB, 0) \
+ _(XR_BODY_JOINT_SET_MAX_ENUM_FB, 0x7FFFFFFF)
+
#define XR_LIST_ENUM_XrHandJointsMotionRangeEXT(_) \
_(XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT, 1) \
_(XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT, 2) \
@@ -674,6 +834,7 @@ XR_ENUM_STR(XrResult);
#define XR_LIST_ENUM_XrSpaceComponentTypeFB(_) \
_(XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB, 0) \
_(XR_SPACE_COMPONENT_TYPE_STORABLE_FB, 1) \
+ _(XR_SPACE_COMPONENT_TYPE_SHARABLE_FB, 2) \
_(XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB, 3) \
_(XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB, 4) \
_(XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB, 5) \
@@ -743,6 +904,7 @@ XR_ENUM_STR(XrResult);
#define XR_LIST_ENUM_XrSpaceStorageLocationFB(_) \
_(XR_SPACE_STORAGE_LOCATION_INVALID_FB, 0) \
_(XR_SPACE_STORAGE_LOCATION_LOCAL_FB, 1) \
+ _(XR_SPACE_STORAGE_LOCATION_CLOUD_FB, 2) \
_(XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB, 0x7FFFFFFF)
#define XR_LIST_ENUM_XrSpacePersistenceModeFB(_) \
@@ -750,6 +912,129 @@ XR_ENUM_STR(XrResult);
_(XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB, 1) \
_(XR_SPACE_PERSISTENCE_MODE_MAX_ENUM_FB, 0x7FFFFFFF)
+#define XR_LIST_ENUM_XrFaceExpressionFB(_) \
+ _(XR_FACE_EXPRESSION_BROW_LOWERER_L_FB, 0) \
+ _(XR_FACE_EXPRESSION_BROW_LOWERER_R_FB, 1) \
+ _(XR_FACE_EXPRESSION_CHEEK_PUFF_L_FB, 2) \
+ _(XR_FACE_EXPRESSION_CHEEK_PUFF_R_FB, 3) \
+ _(XR_FACE_EXPRESSION_CHEEK_RAISER_L_FB, 4) \
+ _(XR_FACE_EXPRESSION_CHEEK_RAISER_R_FB, 5) \
+ _(XR_FACE_EXPRESSION_CHEEK_SUCK_L_FB, 6) \
+ _(XR_FACE_EXPRESSION_CHEEK_SUCK_R_FB, 7) \
+ _(XR_FACE_EXPRESSION_CHIN_RAISER_B_FB, 8) \
+ _(XR_FACE_EXPRESSION_CHIN_RAISER_T_FB, 9) \
+ _(XR_FACE_EXPRESSION_DIMPLER_L_FB, 10) \
+ _(XR_FACE_EXPRESSION_DIMPLER_R_FB, 11) \
+ _(XR_FACE_EXPRESSION_EYES_CLOSED_L_FB, 12) \
+ _(XR_FACE_EXPRESSION_EYES_CLOSED_R_FB, 13) \
+ _(XR_FACE_EXPRESSION_EYES_LOOK_DOWN_L_FB, 14) \
+ _(XR_FACE_EXPRESSION_EYES_LOOK_DOWN_R_FB, 15) \
+ _(XR_FACE_EXPRESSION_EYES_LOOK_LEFT_L_FB, 16) \
+ _(XR_FACE_EXPRESSION_EYES_LOOK_LEFT_R_FB, 17) \
+ _(XR_FACE_EXPRESSION_EYES_LOOK_RIGHT_L_FB, 18) \
+ _(XR_FACE_EXPRESSION_EYES_LOOK_RIGHT_R_FB, 19) \
+ _(XR_FACE_EXPRESSION_EYES_LOOK_UP_L_FB, 20) \
+ _(XR_FACE_EXPRESSION_EYES_LOOK_UP_R_FB, 21) \
+ _(XR_FACE_EXPRESSION_INNER_BROW_RAISER_L_FB, 22) \
+ _(XR_FACE_EXPRESSION_INNER_BROW_RAISER_R_FB, 23) \
+ _(XR_FACE_EXPRESSION_JAW_DROP_FB, 24) \
+ _(XR_FACE_EXPRESSION_JAW_SIDEWAYS_LEFT_FB, 25) \
+ _(XR_FACE_EXPRESSION_JAW_SIDEWAYS_RIGHT_FB, 26) \
+ _(XR_FACE_EXPRESSION_JAW_THRUST_FB, 27) \
+ _(XR_FACE_EXPRESSION_LID_TIGHTENER_L_FB, 28) \
+ _(XR_FACE_EXPRESSION_LID_TIGHTENER_R_FB, 29) \
+ _(XR_FACE_EXPRESSION_LIP_CORNER_DEPRESSOR_L_FB, 30) \
+ _(XR_FACE_EXPRESSION_LIP_CORNER_DEPRESSOR_R_FB, 31) \
+ _(XR_FACE_EXPRESSION_LIP_CORNER_PULLER_L_FB, 32) \
+ _(XR_FACE_EXPRESSION_LIP_CORNER_PULLER_R_FB, 33) \
+ _(XR_FACE_EXPRESSION_LIP_FUNNELER_LB_FB, 34) \
+ _(XR_FACE_EXPRESSION_LIP_FUNNELER_LT_FB, 35) \
+ _(XR_FACE_EXPRESSION_LIP_FUNNELER_RB_FB, 36) \
+ _(XR_FACE_EXPRESSION_LIP_FUNNELER_RT_FB, 37) \
+ _(XR_FACE_EXPRESSION_LIP_PRESSOR_L_FB, 38) \
+ _(XR_FACE_EXPRESSION_LIP_PRESSOR_R_FB, 39) \
+ _(XR_FACE_EXPRESSION_LIP_PUCKER_L_FB, 40) \
+ _(XR_FACE_EXPRESSION_LIP_PUCKER_R_FB, 41) \
+ _(XR_FACE_EXPRESSION_LIP_STRETCHER_L_FB, 42) \
+ _(XR_FACE_EXPRESSION_LIP_STRETCHER_R_FB, 43) \
+ _(XR_FACE_EXPRESSION_LIP_SUCK_LB_FB, 44) \
+ _(XR_FACE_EXPRESSION_LIP_SUCK_LT_FB, 45) \
+ _(XR_FACE_EXPRESSION_LIP_SUCK_RB_FB, 46) \
+ _(XR_FACE_EXPRESSION_LIP_SUCK_RT_FB, 47) \
+ _(XR_FACE_EXPRESSION_LIP_TIGHTENER_L_FB, 48) \
+ _(XR_FACE_EXPRESSION_LIP_TIGHTENER_R_FB, 49) \
+ _(XR_FACE_EXPRESSION_LIPS_TOWARD_FB, 50) \
+ _(XR_FACE_EXPRESSION_LOWER_LIP_DEPRESSOR_L_FB, 51) \
+ _(XR_FACE_EXPRESSION_LOWER_LIP_DEPRESSOR_R_FB, 52) \
+ _(XR_FACE_EXPRESSION_MOUTH_LEFT_FB, 53) \
+ _(XR_FACE_EXPRESSION_MOUTH_RIGHT_FB, 54) \
+ _(XR_FACE_EXPRESSION_NOSE_WRINKLER_L_FB, 55) \
+ _(XR_FACE_EXPRESSION_NOSE_WRINKLER_R_FB, 56) \
+ _(XR_FACE_EXPRESSION_OUTER_BROW_RAISER_L_FB, 57) \
+ _(XR_FACE_EXPRESSION_OUTER_BROW_RAISER_R_FB, 58) \
+ _(XR_FACE_EXPRESSION_UPPER_LID_RAISER_L_FB, 59) \
+ _(XR_FACE_EXPRESSION_UPPER_LID_RAISER_R_FB, 60) \
+ _(XR_FACE_EXPRESSION_UPPER_LIP_RAISER_L_FB, 61) \
+ _(XR_FACE_EXPRESSION_UPPER_LIP_RAISER_R_FB, 62) \
+ _(XR_FACE_EXPRESSION_COUNT_FB, 63) \
+ _(XR_FACE_EXPRESSION_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrFaceExpressionSetFB(_) \
+ _(XR_FACE_EXPRESSION_SET_DEFAULT_FB, 0) \
+ _(XR_FACE_EXPRESSION_SET_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrFaceConfidenceFB(_) \
+ _(XR_FACE_CONFIDENCE_LOWER_FACE_FB, 0) \
+ _(XR_FACE_CONFIDENCE_UPPER_FACE_FB, 1) \
+ _(XR_FACE_CONFIDENCE_COUNT_FB, 2) \
+ _(XR_FACE_CONFIDENCE_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrEyePositionFB(_) \
+ _(XR_EYE_POSITION_LEFT_FB, 0) \
+ _(XR_EYE_POSITION_RIGHT_FB, 1) \
+ _(XR_EYE_POSITION_COUNT_FB, 2) \
+ _(XR_EYE_POSITION_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrCompareOpFB(_) \
+ _(XR_COMPARE_OP_NEVER_FB, 0) \
+ _(XR_COMPARE_OP_LESS_FB, 1) \
+ _(XR_COMPARE_OP_EQUAL_FB, 2) \
+ _(XR_COMPARE_OP_LESS_OR_EQUAL_FB, 3) \
+ _(XR_COMPARE_OP_GREATER_FB, 4) \
+ _(XR_COMPARE_OP_NOT_EQUAL_FB, 5) \
+ _(XR_COMPARE_OP_GREATER_OR_EQUAL_FB, 6) \
+ _(XR_COMPARE_OP_ALWAYS_FB, 7) \
+ _(XR_COMPARE_OPFB_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrLocalDimmingModeMETA(_) \
+ _(XR_LOCAL_DIMMING_MODE_OFF_META, 0) \
+ _(XR_LOCAL_DIMMING_MODE_ON_META, 1) \
+ _(XR_LOCAL_DIMMING_MODE_MAX_ENUM_META, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrVirtualKeyboardLocationTypeMETA(_) \
+ _(XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_CUSTOM_META, 0) \
+ _(XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_FAR_META, 1) \
+ _(XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_DIRECT_META, 2) \
+ _(XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_MAX_ENUM_META, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrVirtualKeyboardInputSourceMETA(_) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_RAY_LEFT_META, 1) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_RAY_RIGHT_META, 2) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_RAY_LEFT_META, 3) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_RAY_RIGHT_META, 4) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_DIRECT_LEFT_META, 5) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_DIRECT_RIGHT_META, 6) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_DIRECT_INDEX_TIP_LEFT_META, 7) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_DIRECT_INDEX_TIP_RIGHT_META, 8) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_MAX_ENUM_META, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrExternalCameraAttachedToDeviceOCULUS(_) \
+ _(XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_NONE_OCULUS, 0) \
+ _(XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_HMD_OCULUS, 1) \
+ _(XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_LTOUCH_OCULUS, 2) \
+ _(XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_RTOUCH_OCULUS, 3) \
+ _(XR_EXTERNAL_CAMERA_ATTACHED_TODEVICE_MAX_ENUM_OCULUS, 0x7FFFFFFF)
+
#define XR_LIST_ENUM_XrPerformanceMetricsCounterUnitMETA(_) \
_(XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META, 0) \
_(XR_PERFORMANCE_METRICS_COUNTER_UNIT_PERCENTAGE_META, 1) \
@@ -758,6 +1043,23 @@ XR_ENUM_STR(XrResult);
_(XR_PERFORMANCE_METRICS_COUNTER_UNIT_HERTZ_META, 4) \
_(XR_PERFORMANCE_METRICS_COUNTER_UNIT_MAX_ENUM_META, 0x7FFFFFFF)
+#define XR_LIST_ENUM_XrPassthroughColorLutChannelsMETA(_) \
+ _(XR_PASSTHROUGH_COLOR_LUT_CHANNELS_RGB_META, 1) \
+ _(XR_PASSTHROUGH_COLOR_LUT_CHANNELS_RGBA_META, 2) \
+ _(XR_PASSTHROUGH_COLOR_LUT_CHANNELS_MAX_ENUM_META, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrTrackingOptimizationSettingsDomainQCOM(_) \
+ _(XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_ALL_QCOM, 1) \
+ _(XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_MAX_ENUM_QCOM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrTrackingOptimizationSettingsHintQCOM(_) \
+ _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_NONE_QCOM, 0) \
+ _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_LONG_RANGE_PRIORIZATION_QCOM, 1) \
+ _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_CLOSE_RANGE_PRIORIZATION_QCOM, 2) \
+ _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_LOW_POWER_PRIORIZATION_QCOM, 3) \
+ _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_HIGH_POWER_PRIORIZATION_QCOM, 4) \
+ _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_MAX_ENUM_QCOM, 0x7FFFFFFF)
+
#define XR_LIST_ENUM_XrPassthroughFormHTC(_) \
_(XR_PASSTHROUGH_FORM_PLANAR_HTC, 0) \
_(XR_PASSTHROUGH_FORM_PROJECTED_HTC, 1) \
@@ -777,6 +1079,42 @@ XR_ENUM_STR(XrResult);
_(XR_FOVEATION_LEVEL_HIGH_HTC, 3) \
_(XR_FOVEATION_LEVEL_MAX_ENUM_HTC, 0x7FFFFFFF)
+#define XR_LIST_ENUM_XrForceFeedbackCurlLocationMNDX(_) \
+ _(XR_FORCE_FEEDBACK_CURL_LOCATION_THUMB_CURL_MNDX, 0) \
+ _(XR_FORCE_FEEDBACK_CURL_LOCATION_INDEX_CURL_MNDX, 1) \
+ _(XR_FORCE_FEEDBACK_CURL_LOCATION_MIDDLE_CURL_MNDX, 2) \
+ _(XR_FORCE_FEEDBACK_CURL_LOCATION_RING_CURL_MNDX, 3) \
+ _(XR_FORCE_FEEDBACK_CURL_LOCATION_LITTLE_CURL_MNDX, 4) \
+ _(XR_FORCE_FEEDBACK_CURL_LOCATION_MAX_ENUM_MNDX, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrHandTrackingDataSourceEXT(_) \
+ _(XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT, 1) \
+ _(XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT, 2) \
+ _(XR_HAND_TRACKING_DATA_SOURCE_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrPlaneDetectorOrientationEXT(_) \
+ _(XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_UPWARD_EXT, 0) \
+ _(XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_DOWNWARD_EXT, 1) \
+ _(XR_PLANE_DETECTOR_ORIENTATION_VERTICAL_EXT, 2) \
+ _(XR_PLANE_DETECTOR_ORIENTATION_ARBITRARY_EXT, 3) \
+ _(XR_PLANE_DETECTOR_ORIENTATION_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrPlaneDetectorSemanticTypeEXT(_) \
+ _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_UNDEFINED_EXT, 0) \
+ _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_CEILING_EXT, 1) \
+ _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_FLOOR_EXT, 2) \
+ _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_WALL_EXT, 3) \
+ _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_PLATFORM_EXT, 4) \
+ _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrPlaneDetectionStateEXT(_) \
+ _(XR_PLANE_DETECTION_STATE_NONE_EXT, 0) \
+ _(XR_PLANE_DETECTION_STATE_PENDING_EXT, 1) \
+ _(XR_PLANE_DETECTION_STATE_DONE_EXT, 2) \
+ _(XR_PLANE_DETECTION_STATE_ERROR_EXT, 3) \
+ _(XR_PLANE_DETECTION_STATE_FATAL_EXT, 4) \
+ _(XR_PLANE_DETECTION_STATE_MAX_ENUM_EXT, 0x7FFFFFFF)
+
#define XR_LIST_BITS_XrInstanceCreateFlags(_)
#define XR_LIST_BITS_XrSessionCreateFlags(_)
@@ -903,18 +1241,44 @@ XR_ENUM_STR(XrResult);
_(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_1_BIT_FB, 0x00000001) \
_(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_2_BIT_FB, 0x00000002) \
+#define XR_LIST_BITS_XrFrameEndInfoFlagsML(_) \
+ _(XR_FRAME_END_INFO_PROTECTED_BIT_ML, 0x00000001) \
+ _(XR_FRAME_END_INFO_VIGNETTE_BIT_ML, 0x00000002) \
+
+#define XR_LIST_BITS_XrGlobalDimmerFrameEndInfoFlagsML(_) \
+ _(XR_GLOBAL_DIMMER_FRAME_END_INFO_ENABLED_BIT_ML, 0x00000001) \
+
#define XR_LIST_BITS_XrCompositionLayerSpaceWarpInfoFlagsFB(_) \
_(XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0x00000001) \
+#define XR_LIST_BITS_XrSemanticLabelsSupportFlagsFB(_) \
+ _(XR_SEMANTIC_LABELS_SUPPORT_MULTIPLE_SEMANTIC_LABELS_BIT_FB, 0x00000001) \
+ _(XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_DESK_TO_TABLE_MIGRATION_BIT_FB, 0x00000002) \
+
#define XR_LIST_BITS_XrDigitalLensControlFlagsALMALENCE(_) \
_(XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE, 0x00000001) \
+#define XR_LIST_BITS_XrFoveationEyeTrackedProfileCreateFlagsMETA(_)
+
+#define XR_LIST_BITS_XrFoveationEyeTrackedStateFlagsMETA(_) \
+ _(XR_FOVEATION_EYE_TRACKED_STATE_VALID_BIT_META, 0x00000001) \
+
#define XR_LIST_BITS_XrCompositionLayerSettingsFlagsFB(_) \
_(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SUPER_SAMPLING_BIT_FB, 0x00000001) \
_(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB, 0x00000002) \
_(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB, 0x00000004) \
_(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB, 0x00000008) \
+#define XR_LIST_BITS_XrVirtualKeyboardInputStateFlagsMETA(_) \
+ _(XR_VIRTUAL_KEYBOARD_INPUT_STATE_PRESSED_BIT_META, 0x00000001) \
+
+#define XR_LIST_BITS_XrExternalCameraStatusFlagsOCULUS(_) \
+ _(XR_EXTERNAL_CAMERA_STATUS_CONNECTED_BIT_OCULUS, 0x00000001) \
+ _(XR_EXTERNAL_CAMERA_STATUS_CALIBRATING_BIT_OCULUS, 0x00000002) \
+ _(XR_EXTERNAL_CAMERA_STATUS_CALIBRATION_FAILED_BIT_OCULUS, 0x00000004) \
+ _(XR_EXTERNAL_CAMERA_STATUS_CALIBRATED_BIT_OCULUS, 0x00000008) \
+ _(XR_EXTERNAL_CAMERA_STATUS_CAPTURING_BIT_OCULUS, 0x00000010) \
+
#define XR_LIST_BITS_XrPerformanceMetricsCounterFlagsMETA(_) \
_(XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META, 0x00000001) \
_(XR_PERFORMANCE_METRICS_COUNTER_UINT_VALUE_VALID_BIT_META, 0x00000002) \
@@ -925,6 +1289,18 @@ XR_ENUM_STR(XrResult);
_(XR_FOVEATION_DYNAMIC_CLEAR_FOV_ENABLED_BIT_HTC, 0x00000002) \
_(XR_FOVEATION_DYNAMIC_FOCAL_CENTER_OFFSET_ENABLED_BIT_HTC, 0x00000004) \
+#define XR_LIST_BITS_XrPlaneDetectionCapabilityFlagsEXT(_) \
+ _(XR_PLANE_DETECTION_CAPABILITY_PLANE_DETECTION_BIT_EXT, 0x00000001) \
+ _(XR_PLANE_DETECTION_CAPABILITY_PLANE_HOLES_BIT_EXT, 0x00000002) \
+ _(XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_CEILING_BIT_EXT, 0x00000004) \
+ _(XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_FLOOR_BIT_EXT, 0x00000008) \
+ _(XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_WALL_BIT_EXT, 0x00000010) \
+ _(XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_PLATFORM_BIT_EXT, 0x00000020) \
+ _(XR_PLANE_DETECTION_CAPABILITY_ORIENTATION_BIT_EXT, 0x00000040) \
+
+#define XR_LIST_BITS_XrPlaneDetectorFlagsEXT(_) \
+ _(XR_PLANE_DETECTOR_ENABLE_CONTOUR_BIT_EXT, 0x00000001) \
+
/// Calls your macro with the name of each member of XrApiLayerProperties, in order.
#define XR_LIST_STRUCT_XrApiLayerProperties(_) \
_(type) \
@@ -2095,6 +2471,54 @@ XR_ENUM_STR(XrResult);
_(next) \
_(flags) \
+/// Calls your macro with the name of each member of XrBodyJointLocationFB, in order.
+#define XR_LIST_STRUCT_XrBodyJointLocationFB(_) \
+ _(locationFlags) \
+ _(pose) \
+
+/// Calls your macro with the name of each member of XrSystemBodyTrackingPropertiesFB, in order.
+#define XR_LIST_STRUCT_XrSystemBodyTrackingPropertiesFB(_) \
+ _(type) \
+ _(next) \
+ _(supportsBodyTracking) \
+
+/// Calls your macro with the name of each member of XrBodyTrackerCreateInfoFB, in order.
+#define XR_LIST_STRUCT_XrBodyTrackerCreateInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(bodyJointSet) \
+
+/// Calls your macro with the name of each member of XrBodySkeletonJointFB, in order.
+#define XR_LIST_STRUCT_XrBodySkeletonJointFB(_) \
+ _(joint) \
+ _(parentJoint) \
+ _(pose) \
+
+/// Calls your macro with the name of each member of XrBodySkeletonFB, in order.
+#define XR_LIST_STRUCT_XrBodySkeletonFB(_) \
+ _(type) \
+ _(next) \
+ _(jointCount) \
+ _(joints) \
+
+/// Calls your macro with the name of each member of XrBodyJointsLocateInfoFB, in order.
+#define XR_LIST_STRUCT_XrBodyJointsLocateInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(baseSpace) \
+ _(time) \
+
+/// Calls your macro with the name of each member of XrBodyJointLocationsFB, in order.
+#define XR_LIST_STRUCT_XrBodyJointLocationsFB(_) \
+ _(type) \
+ _(next) \
+ _(isActive) \
+ _(confidence) \
+ _(jointCount) \
+ _(jointLocations) \
+ _(skeletonChangedCount) \
+ _(time) \
+
/// Calls your macro with the name of each member of XrInteractionProfileDpadBindingEXT, in order.
#define XR_LIST_STRUCT_XrInteractionProfileDpadBindingEXT(_) \
_(type) \
@@ -2731,6 +3155,27 @@ XR_ENUM_STR(XrResult);
_(markerId) \
_(poseInMarkerSpace) \
+/// Calls your macro with the name of each member of XrFrameEndInfoML, in order.
+#define XR_LIST_STRUCT_XrFrameEndInfoML(_) \
+ _(type) \
+ _(next) \
+ _(focusDistance) \
+ _(flags) \
+
+/// Calls your macro with the name of each member of XrGlobalDimmerFrameEndInfoML, in order.
+#define XR_LIST_STRUCT_XrGlobalDimmerFrameEndInfoML(_) \
+ _(type) \
+ _(next) \
+ _(dimmerValue) \
+ _(flags) \
+
+/// Calls your macro with the name of each member of XrCoordinateSpaceCreateInfoML, in order.
+#define XR_LIST_STRUCT_XrCoordinateSpaceCreateInfoML(_) \
+ _(type) \
+ _(next) \
+ _(cfuid) \
+ _(poseInCoordinateSpace) \
+
/// Calls your macro with the name of each member of XrSpatialAnchorPersistenceNameMSFT, in order.
#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceNameMSFT(_) \
_(name) \
@@ -2895,6 +3340,22 @@ XR_ENUM_STR(XrResult);
_(maxAnisotropy) \
_(borderColor) \
+/// Calls your macro with the name of each member of XrSpaceShareInfoFB, in order.
+#define XR_LIST_STRUCT_XrSpaceShareInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(spaceCount) \
+ _(spaces) \
+ _(userCount) \
+ _(users) \
+
+/// Calls your macro with the name of each member of XrEventDataSpaceShareCompleteFB, in order.
+#define XR_LIST_STRUCT_XrEventDataSpaceShareCompleteFB(_) \
+ _(type) \
+ _(next) \
+ _(requestId) \
+ _(result) \
+
/// Calls your macro with the name of each member of XrCompositionLayerSpaceWarpInfoFB, in order.
#define XR_LIST_STRUCT_XrCompositionLayerSpaceWarpInfoFB(_) \
_(type) \
@@ -2915,6 +3376,14 @@ XR_ENUM_STR(XrResult);
_(recommendedMotionVectorImageRectWidth) \
_(recommendedMotionVectorImageRectHeight) \
+/// Calls your macro with the name of each member of XrHapticAmplitudeEnvelopeVibrationFB, in order.
+#define XR_LIST_STRUCT_XrHapticAmplitudeEnvelopeVibrationFB(_) \
+ _(type) \
+ _(next) \
+ _(duration) \
+ _(amplitudeCount) \
+ _(amplitudes) \
+
/// Calls your macro with the name of each member of XrExtent3DfFB, in order.
#define XR_LIST_STRUCT_XrExtent3DfFB(_) \
_(width) \
@@ -2958,12 +3427,33 @@ XR_ENUM_STR(XrResult);
_(vertexCountOutput) \
_(vertices) \
+/// Calls your macro with the name of each member of XrSemanticLabelsSupportInfoFB, in order.
+#define XR_LIST_STRUCT_XrSemanticLabelsSupportInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(flags) \
+ _(recognizedLabels) \
+
/// Calls your macro with the name of each member of XrDigitalLensControlALMALENCE, in order.
#define XR_LIST_STRUCT_XrDigitalLensControlALMALENCE(_) \
_(type) \
_(next) \
_(flags) \
+/// Calls your macro with the name of each member of XrEventDataSceneCaptureCompleteFB, in order.
+#define XR_LIST_STRUCT_XrEventDataSceneCaptureCompleteFB(_) \
+ _(type) \
+ _(next) \
+ _(requestId) \
+ _(result) \
+
+/// Calls your macro with the name of each member of XrSceneCaptureRequestInfoFB, in order.
+#define XR_LIST_STRUCT_XrSceneCaptureRequestInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(requestByteCount) \
+ _(request) \
+
/// Calls your macro with the name of each member of XrSpaceContainerFB, in order.
#define XR_LIST_STRUCT_XrSpaceContainerFB(_) \
_(type) \
@@ -2972,6 +3462,90 @@ XR_ENUM_STR(XrResult);
_(uuidCountOutput) \
_(uuids) \
+/// Calls your macro with the name of each member of XrFoveationEyeTrackedProfileCreateInfoMETA, in order.
+#define XR_LIST_STRUCT_XrFoveationEyeTrackedProfileCreateInfoMETA(_) \
+ _(type) \
+ _(next) \
+ _(flags) \
+
+/// Calls your macro with the name of each member of XrFoveationEyeTrackedStateMETA, in order.
+#define XR_LIST_STRUCT_XrFoveationEyeTrackedStateMETA(_) \
+ _(type) \
+ _(next) \
+ _(foveationCenter) \
+ _(flags) \
+
+/// Calls your macro with the name of each member of XrSystemFoveationEyeTrackedPropertiesMETA, in order.
+#define XR_LIST_STRUCT_XrSystemFoveationEyeTrackedPropertiesMETA(_) \
+ _(type) \
+ _(next) \
+ _(supportsFoveationEyeTracked) \
+
+/// Calls your macro with the name of each member of XrSystemFaceTrackingPropertiesFB, in order.
+#define XR_LIST_STRUCT_XrSystemFaceTrackingPropertiesFB(_) \
+ _(type) \
+ _(next) \
+ _(supportsFaceTracking) \
+
+/// Calls your macro with the name of each member of XrFaceTrackerCreateInfoFB, in order.
+#define XR_LIST_STRUCT_XrFaceTrackerCreateInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(faceExpressionSet) \
+
+/// Calls your macro with the name of each member of XrFaceExpressionInfoFB, in order.
+#define XR_LIST_STRUCT_XrFaceExpressionInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(time) \
+
+/// Calls your macro with the name of each member of XrFaceExpressionStatusFB, in order.
+#define XR_LIST_STRUCT_XrFaceExpressionStatusFB(_) \
+ _(isValid) \
+ _(isEyeFollowingBlendshapesValid) \
+
+/// Calls your macro with the name of each member of XrFaceExpressionWeightsFB, in order.
+#define XR_LIST_STRUCT_XrFaceExpressionWeightsFB(_) \
+ _(type) \
+ _(next) \
+ _(weightCount) \
+ _(weights) \
+ _(confidenceCount) \
+ _(confidences) \
+ _(status) \
+ _(time) \
+
+/// Calls your macro with the name of each member of XrEyeGazeFB, in order.
+#define XR_LIST_STRUCT_XrEyeGazeFB(_) \
+ _(isValid) \
+ _(gazePose) \
+ _(gazeConfidence) \
+
+/// Calls your macro with the name of each member of XrEyeTrackerCreateInfoFB, in order.
+#define XR_LIST_STRUCT_XrEyeTrackerCreateInfoFB(_) \
+ _(type) \
+ _(next) \
+
+/// Calls your macro with the name of each member of XrEyeGazesInfoFB, in order.
+#define XR_LIST_STRUCT_XrEyeGazesInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(baseSpace) \
+ _(time) \
+
+/// Calls your macro with the name of each member of XrSystemEyeTrackingPropertiesFB, in order.
+#define XR_LIST_STRUCT_XrSystemEyeTrackingPropertiesFB(_) \
+ _(type) \
+ _(next) \
+ _(supportsEyeTracking) \
+
+/// Calls your macro with the name of each member of XrEyeGazesFB, in order.
+#define XR_LIST_STRUCT_XrEyeGazesFB(_) \
+ _(type) \
+ _(next) \
+ _(gaze) \
+ _(time) \
+
/// Calls your macro with the name of each member of XrPassthroughKeyboardHandsIntensityFB, in order.
#define XR_LIST_STRUCT_XrPassthroughKeyboardHandsIntensityFB(_) \
_(type) \
@@ -2985,6 +3559,163 @@ XR_ENUM_STR(XrResult);
_(next) \
_(layerFlags) \
+/// Calls your macro with the name of each member of XrHapticPcmVibrationFB, in order.
+#define XR_LIST_STRUCT_XrHapticPcmVibrationFB(_) \
+ _(type) \
+ _(next) \
+ _(bufferSize) \
+ _(buffer) \
+ _(sampleRate) \
+ _(append) \
+ _(samplesConsumed) \
+
+/// Calls your macro with the name of each member of XrDevicePcmSampleRateStateFB, in order.
+#define XR_LIST_STRUCT_XrDevicePcmSampleRateStateFB(_) \
+ _(type) \
+ _(next) \
+ _(sampleRate) \
+
+/// Calls your macro with the name of each member of XrCompositionLayerDepthTestFB, in order.
+#define XR_LIST_STRUCT_XrCompositionLayerDepthTestFB(_) \
+ _(type) \
+ _(next) \
+ _(depthMask) \
+ _(compareOp) \
+
+/// Calls your macro with the name of each member of XrLocalDimmingFrameEndInfoMETA, in order.
+#define XR_LIST_STRUCT_XrLocalDimmingFrameEndInfoMETA(_) \
+ _(type) \
+ _(next) \
+ _(localDimmingMode) \
+
+/// Calls your macro with the name of each member of XrSystemVirtualKeyboardPropertiesMETA, in order.
+#define XR_LIST_STRUCT_XrSystemVirtualKeyboardPropertiesMETA(_) \
+ _(type) \
+ _(next) \
+ _(supportsVirtualKeyboard) \
+
+/// Calls your macro with the name of each member of XrVirtualKeyboardCreateInfoMETA, in order.
+#define XR_LIST_STRUCT_XrVirtualKeyboardCreateInfoMETA(_) \
+ _(type) \
+ _(next) \
+
+/// Calls your macro with the name of each member of XrVirtualKeyboardSpaceCreateInfoMETA, in order.
+#define XR_LIST_STRUCT_XrVirtualKeyboardSpaceCreateInfoMETA(_) \
+ _(type) \
+ _(next) \
+ _(locationType) \
+ _(space) \
+ _(poseInSpace) \
+
+/// Calls your macro with the name of each member of XrVirtualKeyboardLocationInfoMETA, in order.
+#define XR_LIST_STRUCT_XrVirtualKeyboardLocationInfoMETA(_) \
+ _(type) \
+ _(next) \
+ _(locationType) \
+ _(space) \
+ _(poseInSpace) \
+ _(scale) \
+
+/// Calls your macro with the name of each member of XrVirtualKeyboardModelVisibilitySetInfoMETA, in order.
+#define XR_LIST_STRUCT_XrVirtualKeyboardModelVisibilitySetInfoMETA(_) \
+ _(type) \
+ _(next) \
+ _(visible) \
+
+/// Calls your macro with the name of each member of XrVirtualKeyboardAnimationStateMETA, in order.
+#define XR_LIST_STRUCT_XrVirtualKeyboardAnimationStateMETA(_) \
+ _(type) \
+ _(next) \
+ _(animationIndex) \
+ _(fraction) \
+
+/// Calls your macro with the name of each member of XrVirtualKeyboardModelAnimationStatesMETA, in order.
+#define XR_LIST_STRUCT_XrVirtualKeyboardModelAnimationStatesMETA(_) \
+ _(type) \
+ _(next) \
+ _(stateCapacityInput) \
+ _(stateCountOutput) \
+ _(states) \
+
+/// Calls your macro with the name of each member of XrVirtualKeyboardTextureDataMETA, in order.
+#define XR_LIST_STRUCT_XrVirtualKeyboardTextureDataMETA(_) \
+ _(type) \
+ _(next) \
+ _(textureWidth) \
+ _(textureHeight) \
+ _(bufferCapacityInput) \
+ _(bufferCountOutput) \
+ _(buffer) \
+
+/// Calls your macro with the name of each member of XrVirtualKeyboardInputInfoMETA, in order.
+#define XR_LIST_STRUCT_XrVirtualKeyboardInputInfoMETA(_) \
+ _(type) \
+ _(next) \
+ _(inputSource) \
+ _(inputSpace) \
+ _(inputPoseInSpace) \
+ _(inputState) \
+
+/// Calls your macro with the name of each member of XrVirtualKeyboardTextContextChangeInfoMETA, in order.
+#define XR_LIST_STRUCT_XrVirtualKeyboardTextContextChangeInfoMETA(_) \
+ _(type) \
+ _(next) \
+ _(textContext) \
+
+/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardCommitTextMETA, in order.
+#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardCommitTextMETA(_) \
+ _(type) \
+ _(next) \
+ _(keyboard) \
+ _(text) \
+
+/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardBackspaceMETA, in order.
+#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardBackspaceMETA(_) \
+ _(type) \
+ _(next) \
+ _(keyboard) \
+
+/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardEnterMETA, in order.
+#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardEnterMETA(_) \
+ _(type) \
+ _(next) \
+ _(keyboard) \
+
+/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardShownMETA, in order.
+#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardShownMETA(_) \
+ _(type) \
+ _(next) \
+ _(keyboard) \
+
+/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardHiddenMETA, in order.
+#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardHiddenMETA(_) \
+ _(type) \
+ _(next) \
+ _(keyboard) \
+
+/// Calls your macro with the name of each member of XrExternalCameraIntrinsicsOCULUS, in order.
+#define XR_LIST_STRUCT_XrExternalCameraIntrinsicsOCULUS(_) \
+ _(lastChangeTime) \
+ _(fov) \
+ _(virtualNearPlaneDistance) \
+ _(virtualFarPlaneDistance) \
+ _(imageSensorPixelResolution) \
+
+/// Calls your macro with the name of each member of XrExternalCameraExtrinsicsOCULUS, in order.
+#define XR_LIST_STRUCT_XrExternalCameraExtrinsicsOCULUS(_) \
+ _(lastChangeTime) \
+ _(cameraStatusFlags) \
+ _(attachedToDevice) \
+ _(relativePose) \
+
+/// Calls your macro with the name of each member of XrExternalCameraOCULUS, in order.
+#define XR_LIST_STRUCT_XrExternalCameraOCULUS(_) \
+ _(type) \
+ _(next) \
+ _(name) \
+ _(intrinsics) \
+ _(extrinsics) \
+
/// Calls your macro with the name of each member of XrVulkanSwapchainCreateInfoMETA, in order.
#define XR_LIST_STRUCT_XrVulkanSwapchainCreateInfoMETA(_) \
_(type) \
@@ -3007,12 +3738,73 @@ XR_ENUM_STR(XrResult);
_(uintValue) \
_(floatValue) \
+/// Calls your macro with the name of each member of XrSpaceListSaveInfoFB, in order.
+#define XR_LIST_STRUCT_XrSpaceListSaveInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(spaceCount) \
+ _(spaces) \
+ _(location) \
+
+/// Calls your macro with the name of each member of XrEventDataSpaceListSaveCompleteFB, in order.
+#define XR_LIST_STRUCT_XrEventDataSpaceListSaveCompleteFB(_) \
+ _(type) \
+ _(next) \
+ _(requestId) \
+ _(result) \
+
+/// Calls your macro with the name of each member of XrSpaceUserCreateInfoFB, in order.
+#define XR_LIST_STRUCT_XrSpaceUserCreateInfoFB(_) \
+ _(type) \
+ _(next) \
+ _(userId) \
+
/// Calls your macro with the name of each member of XrSystemHeadsetIdPropertiesMETA, in order.
#define XR_LIST_STRUCT_XrSystemHeadsetIdPropertiesMETA(_) \
_(type) \
_(next) \
_(id) \
+/// Calls your macro with the name of each member of XrPassthroughColorLutDataMETA, in order.
+#define XR_LIST_STRUCT_XrPassthroughColorLutDataMETA(_) \
+ _(bufferSize) \
+ _(buffer) \
+
+/// Calls your macro with the name of each member of XrPassthroughColorLutCreateInfoMETA, in order.
+#define XR_LIST_STRUCT_XrPassthroughColorLutCreateInfoMETA(_) \
+ _(type) \
+ _(next) \
+ _(channels) \
+ _(resolution) \
+ _(data) \
+
+/// Calls your macro with the name of each member of XrPassthroughColorLutUpdateInfoMETA, in order.
+#define XR_LIST_STRUCT_XrPassthroughColorLutUpdateInfoMETA(_) \
+ _(type) \
+ _(next) \
+ _(data) \
+
+/// Calls your macro with the name of each member of XrPassthroughColorMapLutMETA, in order.
+#define XR_LIST_STRUCT_XrPassthroughColorMapLutMETA(_) \
+ _(type) \
+ _(next) \
+ _(colorLut) \
+ _(weight) \
+
+/// Calls your macro with the name of each member of XrPassthroughColorMapInterpolatedLutMETA, in order.
+#define XR_LIST_STRUCT_XrPassthroughColorMapInterpolatedLutMETA(_) \
+ _(type) \
+ _(next) \
+ _(sourceColorLut) \
+ _(targetColorLut) \
+ _(weight) \
+
+/// Calls your macro with the name of each member of XrSystemPassthroughColorLutPropertiesMETA, in order.
+#define XR_LIST_STRUCT_XrSystemPassthroughColorLutPropertiesMETA(_) \
+ _(type) \
+ _(next) \
+ _(maxColorLutResolution) \
+
/// Calls your macro with the name of each member of XrPassthroughCreateInfoHTC, in order.
#define XR_LIST_STRUCT_XrPassthroughCreateInfoHTC(_) \
_(type) \
@@ -3086,6 +3878,106 @@ XR_ENUM_STR(XrResult);
_(actionSetPriorityCount) \
_(actionSetPriorities) \
+/// Calls your macro with the name of each member of XrSystemForceFeedbackCurlPropertiesMNDX, in order.
+#define XR_LIST_STRUCT_XrSystemForceFeedbackCurlPropertiesMNDX(_) \
+ _(type) \
+ _(next) \
+ _(supportsForceFeedbackCurl) \
+
+/// Calls your macro with the name of each member of XrForceFeedbackCurlApplyLocationMNDX, in order.
+#define XR_LIST_STRUCT_XrForceFeedbackCurlApplyLocationMNDX(_) \
+ _(location) \
+ _(value) \
+
+/// Calls your macro with the name of each member of XrForceFeedbackCurlApplyLocationsMNDX, in order.
+#define XR_LIST_STRUCT_XrForceFeedbackCurlApplyLocationsMNDX(_) \
+ _(type) \
+ _(next) \
+ _(locationCount) \
+ _(locations) \
+
+/// Calls your macro with the name of each member of XrHandTrackingDataSourceInfoEXT, in order.
+#define XR_LIST_STRUCT_XrHandTrackingDataSourceInfoEXT(_) \
+ _(type) \
+ _(next) \
+ _(requestedDataSourceCount) \
+ _(requestedDataSources) \
+
+/// Calls your macro with the name of each member of XrHandTrackingDataSourceStateEXT, in order.
+#define XR_LIST_STRUCT_XrHandTrackingDataSourceStateEXT(_) \
+ _(type) \
+ _(next) \
+ _(isActive) \
+ _(dataSource) \
+
+/// Calls your macro with the name of each member of XrSystemPlaneDetectionPropertiesEXT, in order.
+#define XR_LIST_STRUCT_XrSystemPlaneDetectionPropertiesEXT(_) \
+ _(type) \
+ _(next) \
+ _(supportedFeatures) \
+
+/// Calls your macro with the name of each member of XrPlaneDetectorCreateInfoEXT, in order.
+#define XR_LIST_STRUCT_XrPlaneDetectorCreateInfoEXT(_) \
+ _(type) \
+ _(next) \
+ _(flags) \
+
+/// Calls your macro with the name of each member of XrExtent3DfEXT, in order.
+#define XR_LIST_STRUCT_XrExtent3DfEXT(_) \
+ _(width) \
+ _(height) \
+ _(depth) \
+
+/// Calls your macro with the name of each member of XrPlaneDetectorBeginInfoEXT, in order.
+#define XR_LIST_STRUCT_XrPlaneDetectorBeginInfoEXT(_) \
+ _(type) \
+ _(next) \
+ _(baseSpace) \
+ _(time) \
+ _(orientationCount) \
+ _(orientations) \
+ _(semanticTypeCount) \
+ _(semanticTypes) \
+ _(maxPlanes) \
+ _(minArea) \
+ _(boundingBoxPose) \
+ _(boundingBoxExtent) \
+
+/// Calls your macro with the name of each member of XrPlaneDetectorGetInfoEXT, in order.
+#define XR_LIST_STRUCT_XrPlaneDetectorGetInfoEXT(_) \
+ _(type) \
+ _(next) \
+ _(baseSpace) \
+ _(time) \
+
+/// Calls your macro with the name of each member of XrPlaneDetectorLocationEXT, in order.
+#define XR_LIST_STRUCT_XrPlaneDetectorLocationEXT(_) \
+ _(type) \
+ _(next) \
+ _(planeId) \
+ _(locationFlags) \
+ _(pose) \
+ _(extents) \
+ _(orientation) \
+ _(semanticType) \
+ _(polygonBufferCount) \
+
+/// Calls your macro with the name of each member of XrPlaneDetectorLocationsEXT, in order.
+#define XR_LIST_STRUCT_XrPlaneDetectorLocationsEXT(_) \
+ _(type) \
+ _(next) \
+ _(planeLocationCapacityInput) \
+ _(planeLocationCountOutput) \
+ _(planeLocations) \
+
+/// Calls your macro with the name of each member of XrPlaneDetectorPolygonBufferEXT, in order.
+#define XR_LIST_STRUCT_XrPlaneDetectorPolygonBufferEXT(_) \
+ _(type) \
+ _(next) \
+ _(vertexCapacityInput) \
+ _(vertexCountOutput) \
+ _(vertices) \
+
/// Calls your macro with the structure type name and the XrStructureType constant for
@@ -3104,6 +3996,7 @@ XR_ENUM_STR(XrResult);
XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \
XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \
XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \
+ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_) \
XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \
@@ -3210,6 +4103,11 @@ XR_ENUM_STR(XrResult);
_(XrCompositionLayerReprojectionInfoMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) \
_(XrCompositionLayerReprojectionPlaneOverrideMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) \
_(XrCompositionLayerSecureContentFB, XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) \
+ _(XrSystemBodyTrackingPropertiesFB, XR_TYPE_SYSTEM_BODY_TRACKING_PROPERTIES_FB) \
+ _(XrBodyTrackerCreateInfoFB, XR_TYPE_BODY_TRACKER_CREATE_INFO_FB) \
+ _(XrBodySkeletonFB, XR_TYPE_BODY_SKELETON_FB) \
+ _(XrBodyJointsLocateInfoFB, XR_TYPE_BODY_JOINTS_LOCATE_INFO_FB) \
+ _(XrBodyJointLocationsFB, XR_TYPE_BODY_JOINT_LOCATIONS_FB) \
_(XrInteractionProfileDpadBindingEXT, XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT) \
_(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \
_(XrHandJointsMotionRangeInfoEXT, XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) \
@@ -3284,6 +4182,8 @@ XR_ENUM_STR(XrResult);
_(XrSystemMarkerTrackingPropertiesVARJO, XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) \
_(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \
_(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \
+ _(XrFrameEndInfoML, XR_TYPE_FRAME_END_INFO_ML) \
+ _(XrGlobalDimmerFrameEndInfoML, XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML) \
_(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \
_(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \
_(XrSpaceQueryInfoFB, XR_TYPE_SPACE_QUERY_INFO_FB) \
@@ -3297,18 +4197,63 @@ XR_ENUM_STR(XrResult);
_(XrSpaceEraseInfoFB, XR_TYPE_SPACE_ERASE_INFO_FB) \
_(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \
_(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \
+ _(XrSpaceShareInfoFB, XR_TYPE_SPACE_SHARE_INFO_FB) \
+ _(XrEventDataSpaceShareCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB) \
_(XrCompositionLayerSpaceWarpInfoFB, XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) \
_(XrSystemSpaceWarpPropertiesFB, XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) \
+ _(XrHapticAmplitudeEnvelopeVibrationFB, XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB) \
_(XrSemanticLabelsFB, XR_TYPE_SEMANTIC_LABELS_FB) \
_(XrRoomLayoutFB, XR_TYPE_ROOM_LAYOUT_FB) \
_(XrBoundary2DFB, XR_TYPE_BOUNDARY_2D_FB) \
+ _(XrSemanticLabelsSupportInfoFB, XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB) \
_(XrDigitalLensControlALMALENCE, XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE) \
+ _(XrEventDataSceneCaptureCompleteFB, XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB) \
+ _(XrSceneCaptureRequestInfoFB, XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB) \
_(XrSpaceContainerFB, XR_TYPE_SPACE_CONTAINER_FB) \
+ _(XrFoveationEyeTrackedProfileCreateInfoMETA, XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META) \
+ _(XrFoveationEyeTrackedStateMETA, XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META) \
+ _(XrSystemFoveationEyeTrackedPropertiesMETA, XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META) \
+ _(XrSystemFaceTrackingPropertiesFB, XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_FB) \
+ _(XrFaceTrackerCreateInfoFB, XR_TYPE_FACE_TRACKER_CREATE_INFO_FB) \
+ _(XrFaceExpressionInfoFB, XR_TYPE_FACE_EXPRESSION_INFO_FB) \
+ _(XrFaceExpressionWeightsFB, XR_TYPE_FACE_EXPRESSION_WEIGHTS_FB) \
+ _(XrEyeTrackerCreateInfoFB, XR_TYPE_EYE_TRACKER_CREATE_INFO_FB) \
+ _(XrEyeGazesInfoFB, XR_TYPE_EYE_GAZES_INFO_FB) \
+ _(XrSystemEyeTrackingPropertiesFB, XR_TYPE_SYSTEM_EYE_TRACKING_PROPERTIES_FB) \
+ _(XrEyeGazesFB, XR_TYPE_EYE_GAZES_FB) \
_(XrPassthroughKeyboardHandsIntensityFB, XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB) \
_(XrCompositionLayerSettingsFB, XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB) \
+ _(XrHapticPcmVibrationFB, XR_TYPE_HAPTIC_PCM_VIBRATION_FB) \
+ _(XrDevicePcmSampleRateStateFB, XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB) \
+ _(XrCompositionLayerDepthTestFB, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_FB) \
+ _(XrLocalDimmingFrameEndInfoMETA, XR_TYPE_LOCAL_DIMMING_FRAME_END_INFO_META) \
+ _(XrSystemVirtualKeyboardPropertiesMETA, XR_TYPE_SYSTEM_VIRTUAL_KEYBOARD_PROPERTIES_META) \
+ _(XrVirtualKeyboardCreateInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_CREATE_INFO_META) \
+ _(XrVirtualKeyboardSpaceCreateInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_SPACE_CREATE_INFO_META) \
+ _(XrVirtualKeyboardLocationInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_LOCATION_INFO_META) \
+ _(XrVirtualKeyboardModelVisibilitySetInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_MODEL_VISIBILITY_SET_INFO_META) \
+ _(XrVirtualKeyboardAnimationStateMETA, XR_TYPE_VIRTUAL_KEYBOARD_ANIMATION_STATE_META) \
+ _(XrVirtualKeyboardModelAnimationStatesMETA, XR_TYPE_VIRTUAL_KEYBOARD_MODEL_ANIMATION_STATES_META) \
+ _(XrVirtualKeyboardTextureDataMETA, XR_TYPE_VIRTUAL_KEYBOARD_TEXTURE_DATA_META) \
+ _(XrVirtualKeyboardInputInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_INPUT_INFO_META) \
+ _(XrVirtualKeyboardTextContextChangeInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_TEXT_CONTEXT_CHANGE_INFO_META) \
+ _(XrEventDataVirtualKeyboardCommitTextMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_COMMIT_TEXT_META) \
+ _(XrEventDataVirtualKeyboardBackspaceMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_BACKSPACE_META) \
+ _(XrEventDataVirtualKeyboardEnterMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_ENTER_META) \
+ _(XrEventDataVirtualKeyboardShownMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_SHOWN_META) \
+ _(XrEventDataVirtualKeyboardHiddenMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_HIDDEN_META) \
+ _(XrExternalCameraOCULUS, XR_TYPE_EXTERNAL_CAMERA_OCULUS) \
_(XrPerformanceMetricsStateMETA, XR_TYPE_PERFORMANCE_METRICS_STATE_META) \
_(XrPerformanceMetricsCounterMETA, XR_TYPE_PERFORMANCE_METRICS_COUNTER_META) \
+ _(XrSpaceListSaveInfoFB, XR_TYPE_SPACE_LIST_SAVE_INFO_FB) \
+ _(XrEventDataSpaceListSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB) \
+ _(XrSpaceUserCreateInfoFB, XR_TYPE_SPACE_USER_CREATE_INFO_FB) \
_(XrSystemHeadsetIdPropertiesMETA, XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META) \
+ _(XrPassthroughColorLutCreateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META) \
+ _(XrPassthroughColorLutUpdateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META) \
+ _(XrPassthroughColorMapLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META) \
+ _(XrPassthroughColorMapInterpolatedLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META) \
+ _(XrSystemPassthroughColorLutPropertiesMETA, XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META) \
_(XrPassthroughCreateInfoHTC, XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC) \
_(XrPassthroughColorHTC, XR_TYPE_PASSTHROUGH_COLOR_HTC) \
_(XrPassthroughMeshTransformInfoHTC, XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC) \
@@ -3317,6 +4262,17 @@ XR_ENUM_STR(XrResult);
_(XrFoveationDynamicModeInfoHTC, XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC) \
_(XrFoveationCustomModeInfoHTC, XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC) \
_(XrActiveActionSetPrioritiesEXT, XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT) \
+ _(XrSystemForceFeedbackCurlPropertiesMNDX, XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX) \
+ _(XrForceFeedbackCurlApplyLocationsMNDX, XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX) \
+ _(XrHandTrackingDataSourceInfoEXT, XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT) \
+ _(XrHandTrackingDataSourceStateEXT, XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT) \
+ _(XrSystemPlaneDetectionPropertiesEXT, XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT) \
+ _(XrPlaneDetectorCreateInfoEXT, XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT) \
+ _(XrPlaneDetectorBeginInfoEXT, XR_TYPE_PLANE_DETECTOR_BEGIN_INFO_EXT) \
+ _(XrPlaneDetectorGetInfoEXT, XR_TYPE_PLANE_DETECTOR_GET_INFO_EXT) \
+ _(XrPlaneDetectorLocationEXT, XR_TYPE_PLANE_DETECTOR_LOCATION_EXT) \
+ _(XrPlaneDetectorLocationsEXT, XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT) \
+ _(XrPlaneDetectorPolygonBufferEXT, XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT) \
#if defined(XR_USE_GRAPHICS_API_D3D11)
@@ -3458,6 +4414,16 @@ XR_ENUM_STR(XrResult);
#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_)
#endif
+#if defined(XR_USE_PLATFORM_ML)
+/// Implementation detail of XR_LIST_STRUCTURE_TYPES()
+/// Structure types available only when XR_USE_PLATFORM_ML is defined
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_) \
+ _(XrCoordinateSpaceCreateInfoML, XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML) \
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_)
+#endif
+
#if defined(XR_USE_PLATFORM_WIN32)
/// Implementation detail of XR_LIST_STRUCTURE_TYPES()
/// Structure types available only when XR_USE_PLATFORM_WIN32 is defined
@@ -3521,6 +4487,7 @@ XR_ENUM_STR(XrResult);
_(XR_FB_android_surface_swapchain_create, 71) \
_(XR_FB_swapchain_update_state, 72) \
_(XR_FB_composition_layer_secure_content, 73) \
+ _(XR_FB_body_tracking, 77) \
_(XR_EXT_dpad_binding, 79) \
_(XR_VALVE_analog_threshold, 80) \
_(XR_EXT_hand_joints_motion_range, 81) \
@@ -3558,6 +4525,9 @@ XR_ENUM_STR(XrResult);
_(XR_VARJO_marker_tracking, 125) \
_(XR_VARJO_view_offset, 126) \
_(XR_ML_ml2_controller_interaction, 135) \
+ _(XR_ML_frame_end_info, 136) \
+ _(XR_ML_global_dimmer, 137) \
+ _(XR_ML_compat, 138) \
_(XR_MSFT_spatial_anchor_persistence, 143) \
_(XR_ULTRALEAP_hand_tracking_forearm, 150) \
_(XR_FB_spatial_entity_query, 157) \
@@ -3568,20 +4538,44 @@ XR_ENUM_STR(XrResult);
_(XR_FB_swapchain_update_state_opengl_es, 163) \
_(XR_FB_swapchain_update_state_vulkan, 164) \
_(XR_KHR_swapchain_usage_input_attachment_bit, 166) \
+ _(XR_FB_touch_controller_pro, 168) \
+ _(XR_FB_spatial_entity_sharing, 170) \
_(XR_FB_space_warp, 172) \
+ _(XR_FB_haptic_amplitude_envelope, 174) \
_(XR_FB_scene, 176) \
_(XR_EXT_palm_pose, 177) \
_(XR_ALMALENCE_digital_lens_control, 197) \
+ _(XR_FB_scene_capture, 199) \
_(XR_FB_spatial_entity_container, 200) \
+ _(XR_META_foveation_eye_tracked, 201) \
+ _(XR_FB_face_tracking, 202) \
+ _(XR_FB_eye_tracking_social, 203) \
_(XR_FB_passthrough_keyboard_hands, 204) \
_(XR_FB_composition_layer_settings, 205) \
+ _(XR_FB_touch_controller_proximity, 207) \
+ _(XR_FB_haptic_pcm, 210) \
+ _(XR_FB_composition_layer_depth_test, 213) \
+ _(XR_META_local_dimming, 217) \
+ _(XR_META_virtual_keyboard, 220) \
+ _(XR_OCULUS_external_camera, 227) \
_(XR_META_vulkan_swapchain_create_info, 228) \
_(XR_META_performance_metrics, 233) \
+ _(XR_FB_spatial_entity_storage_batch, 239) \
+ _(XR_FB_spatial_entity_user, 242) \
_(XR_META_headset_id, 246) \
+ _(XR_META_passthrough_color_lut, 267) \
_(XR_EXT_uuid, 300) \
+ _(XR_EXT_hand_interaction, 303) \
+ _(XR_QCOM_tracking_optimization_settings, 307) \
_(XR_HTC_passthrough, 318) \
_(XR_HTC_foveation, 319) \
_(XR_EXT_active_action_set_priority, 374) \
+ _(XR_MNDX_force_feedback_curl, 376) \
+ _(XR_BD_controller_interaction, 385) \
+ _(XR_EXT_local_floor, 427) \
+ _(XR_EXT_hand_tracking_data_source, 429) \
+ _(XR_EXT_plane_detection, 430) \
+ _(XR_OPPO_controller_interaction, 454) \
#endif
diff --git a/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h b/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h
index 19b0e1c3f6..d0d05e97d0 100644
--- a/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h
+++ b/thirdparty/openxr/include/openxr/openxr_reflection_parent_structs.h
@@ -2,7 +2,7 @@
#define OPENXR_REFLECTION_PARENT_STRUCTS_H_ 1
/*
-** Copyright (c) 2017-2022, The Khronos Group Inc.
+** Copyright (c) 2017-2023, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -62,6 +62,8 @@ This file contains expansion macros (X Macros) for OpenXR structures that have a
_avail(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \
_avail(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \
_avail(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \
+ _avail(XrEventDataSpaceShareCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB) \
+ _avail(XrEventDataSpaceListSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB) \
@@ -75,6 +77,8 @@ This file contains expansion macros (X Macros) for OpenXR structures that have a
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader_CORE(_avail, _unavail) \
_avail(XrHapticVibration, XR_TYPE_HAPTIC_VIBRATION) \
+ _avail(XrHapticAmplitudeEnvelopeVibrationFB, XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB) \
+ _avail(XrHapticPcmVibrationFB, XR_TYPE_HAPTIC_PCM_VIBRATION_FB) \
diff --git a/thirdparty/openxr/include/openxr/openxr_reflection_structs.h b/thirdparty/openxr/include/openxr/openxr_reflection_structs.h
index 300bbbad6d..ec186390a3 100644
--- a/thirdparty/openxr/include/openxr/openxr_reflection_structs.h
+++ b/thirdparty/openxr/include/openxr/openxr_reflection_structs.h
@@ -2,7 +2,7 @@
#define OPENXR_REFLECTION_STRUCTS_H_ 1
/*
-** Copyright (c) 2017-2022, The Khronos Group Inc.
+** Copyright (c) 2017-2023, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -37,6 +37,7 @@ This file contains expansion macros (X Macros) for OpenXR structures.
_impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \
_impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \
_impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_avail, _unavail) \
+ _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_avail, _unavail) \
_impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_avail, _unavail) \
@@ -143,6 +144,11 @@ This file contains expansion macros (X Macros) for OpenXR structures.
_avail(XrCompositionLayerReprojectionInfoMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) \
_avail(XrCompositionLayerReprojectionPlaneOverrideMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) \
_avail(XrCompositionLayerSecureContentFB, XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) \
+ _avail(XrSystemBodyTrackingPropertiesFB, XR_TYPE_SYSTEM_BODY_TRACKING_PROPERTIES_FB) \
+ _avail(XrBodyTrackerCreateInfoFB, XR_TYPE_BODY_TRACKER_CREATE_INFO_FB) \
+ _avail(XrBodySkeletonFB, XR_TYPE_BODY_SKELETON_FB) \
+ _avail(XrBodyJointsLocateInfoFB, XR_TYPE_BODY_JOINTS_LOCATE_INFO_FB) \
+ _avail(XrBodyJointLocationsFB, XR_TYPE_BODY_JOINT_LOCATIONS_FB) \
_avail(XrInteractionProfileDpadBindingEXT, XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT) \
_avail(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \
_avail(XrHandJointsMotionRangeInfoEXT, XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) \
@@ -217,6 +223,8 @@ This file contains expansion macros (X Macros) for OpenXR structures.
_avail(XrSystemMarkerTrackingPropertiesVARJO, XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) \
_avail(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \
_avail(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \
+ _avail(XrFrameEndInfoML, XR_TYPE_FRAME_END_INFO_ML) \
+ _avail(XrGlobalDimmerFrameEndInfoML, XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML) \
_avail(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \
_avail(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \
_avail(XrSpaceQueryInfoFB, XR_TYPE_SPACE_QUERY_INFO_FB) \
@@ -230,18 +238,63 @@ This file contains expansion macros (X Macros) for OpenXR structures.
_avail(XrSpaceEraseInfoFB, XR_TYPE_SPACE_ERASE_INFO_FB) \
_avail(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \
_avail(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \
+ _avail(XrSpaceShareInfoFB, XR_TYPE_SPACE_SHARE_INFO_FB) \
+ _avail(XrEventDataSpaceShareCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB) \
_avail(XrCompositionLayerSpaceWarpInfoFB, XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) \
_avail(XrSystemSpaceWarpPropertiesFB, XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) \
+ _avail(XrHapticAmplitudeEnvelopeVibrationFB, XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB) \
_avail(XrSemanticLabelsFB, XR_TYPE_SEMANTIC_LABELS_FB) \
_avail(XrRoomLayoutFB, XR_TYPE_ROOM_LAYOUT_FB) \
_avail(XrBoundary2DFB, XR_TYPE_BOUNDARY_2D_FB) \
+ _avail(XrSemanticLabelsSupportInfoFB, XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB) \
_avail(XrDigitalLensControlALMALENCE, XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE) \
+ _avail(XrEventDataSceneCaptureCompleteFB, XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB) \
+ _avail(XrSceneCaptureRequestInfoFB, XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB) \
_avail(XrSpaceContainerFB, XR_TYPE_SPACE_CONTAINER_FB) \
+ _avail(XrFoveationEyeTrackedProfileCreateInfoMETA, XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META) \
+ _avail(XrFoveationEyeTrackedStateMETA, XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META) \
+ _avail(XrSystemFoveationEyeTrackedPropertiesMETA, XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META) \
+ _avail(XrSystemFaceTrackingPropertiesFB, XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_FB) \
+ _avail(XrFaceTrackerCreateInfoFB, XR_TYPE_FACE_TRACKER_CREATE_INFO_FB) \
+ _avail(XrFaceExpressionInfoFB, XR_TYPE_FACE_EXPRESSION_INFO_FB) \
+ _avail(XrFaceExpressionWeightsFB, XR_TYPE_FACE_EXPRESSION_WEIGHTS_FB) \
+ _avail(XrEyeTrackerCreateInfoFB, XR_TYPE_EYE_TRACKER_CREATE_INFO_FB) \
+ _avail(XrEyeGazesInfoFB, XR_TYPE_EYE_GAZES_INFO_FB) \
+ _avail(XrSystemEyeTrackingPropertiesFB, XR_TYPE_SYSTEM_EYE_TRACKING_PROPERTIES_FB) \
+ _avail(XrEyeGazesFB, XR_TYPE_EYE_GAZES_FB) \
_avail(XrPassthroughKeyboardHandsIntensityFB, XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB) \
_avail(XrCompositionLayerSettingsFB, XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB) \
+ _avail(XrHapticPcmVibrationFB, XR_TYPE_HAPTIC_PCM_VIBRATION_FB) \
+ _avail(XrDevicePcmSampleRateStateFB, XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB) \
+ _avail(XrCompositionLayerDepthTestFB, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_FB) \
+ _avail(XrLocalDimmingFrameEndInfoMETA, XR_TYPE_LOCAL_DIMMING_FRAME_END_INFO_META) \
+ _avail(XrSystemVirtualKeyboardPropertiesMETA, XR_TYPE_SYSTEM_VIRTUAL_KEYBOARD_PROPERTIES_META) \
+ _avail(XrVirtualKeyboardCreateInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_CREATE_INFO_META) \
+ _avail(XrVirtualKeyboardSpaceCreateInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_SPACE_CREATE_INFO_META) \
+ _avail(XrVirtualKeyboardLocationInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_LOCATION_INFO_META) \
+ _avail(XrVirtualKeyboardModelVisibilitySetInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_MODEL_VISIBILITY_SET_INFO_META) \
+ _avail(XrVirtualKeyboardAnimationStateMETA, XR_TYPE_VIRTUAL_KEYBOARD_ANIMATION_STATE_META) \
+ _avail(XrVirtualKeyboardModelAnimationStatesMETA, XR_TYPE_VIRTUAL_KEYBOARD_MODEL_ANIMATION_STATES_META) \
+ _avail(XrVirtualKeyboardTextureDataMETA, XR_TYPE_VIRTUAL_KEYBOARD_TEXTURE_DATA_META) \
+ _avail(XrVirtualKeyboardInputInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_INPUT_INFO_META) \
+ _avail(XrVirtualKeyboardTextContextChangeInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_TEXT_CONTEXT_CHANGE_INFO_META) \
+ _avail(XrEventDataVirtualKeyboardCommitTextMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_COMMIT_TEXT_META) \
+ _avail(XrEventDataVirtualKeyboardBackspaceMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_BACKSPACE_META) \
+ _avail(XrEventDataVirtualKeyboardEnterMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_ENTER_META) \
+ _avail(XrEventDataVirtualKeyboardShownMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_SHOWN_META) \
+ _avail(XrEventDataVirtualKeyboardHiddenMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_HIDDEN_META) \
+ _avail(XrExternalCameraOCULUS, XR_TYPE_EXTERNAL_CAMERA_OCULUS) \
_avail(XrPerformanceMetricsStateMETA, XR_TYPE_PERFORMANCE_METRICS_STATE_META) \
_avail(XrPerformanceMetricsCounterMETA, XR_TYPE_PERFORMANCE_METRICS_COUNTER_META) \
+ _avail(XrSpaceListSaveInfoFB, XR_TYPE_SPACE_LIST_SAVE_INFO_FB) \
+ _avail(XrEventDataSpaceListSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB) \
+ _avail(XrSpaceUserCreateInfoFB, XR_TYPE_SPACE_USER_CREATE_INFO_FB) \
_avail(XrSystemHeadsetIdPropertiesMETA, XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META) \
+ _avail(XrPassthroughColorLutCreateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META) \
+ _avail(XrPassthroughColorLutUpdateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META) \
+ _avail(XrPassthroughColorMapLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META) \
+ _avail(XrPassthroughColorMapInterpolatedLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META) \
+ _avail(XrSystemPassthroughColorLutPropertiesMETA, XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META) \
_avail(XrPassthroughCreateInfoHTC, XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC) \
_avail(XrPassthroughColorHTC, XR_TYPE_PASSTHROUGH_COLOR_HTC) \
_avail(XrPassthroughMeshTransformInfoHTC, XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC) \
@@ -250,6 +303,17 @@ This file contains expansion macros (X Macros) for OpenXR structures.
_avail(XrFoveationDynamicModeInfoHTC, XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC) \
_avail(XrFoveationCustomModeInfoHTC, XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC) \
_avail(XrActiveActionSetPrioritiesEXT, XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT) \
+ _avail(XrSystemForceFeedbackCurlPropertiesMNDX, XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX) \
+ _avail(XrForceFeedbackCurlApplyLocationsMNDX, XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX) \
+ _avail(XrHandTrackingDataSourceInfoEXT, XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT) \
+ _avail(XrHandTrackingDataSourceStateEXT, XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT) \
+ _avail(XrSystemPlaneDetectionPropertiesEXT, XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT) \
+ _avail(XrPlaneDetectorCreateInfoEXT, XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT) \
+ _avail(XrPlaneDetectorBeginInfoEXT, XR_TYPE_PLANE_DETECTOR_BEGIN_INFO_EXT) \
+ _avail(XrPlaneDetectorGetInfoEXT, XR_TYPE_PLANE_DETECTOR_GET_INFO_EXT) \
+ _avail(XrPlaneDetectorLocationEXT, XR_TYPE_PLANE_DETECTOR_LOCATION_EXT) \
+ _avail(XrPlaneDetectorLocationsEXT, XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT) \
+ _avail(XrPlaneDetectorPolygonBufferEXT, XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT) \
#if defined(XR_USE_GRAPHICS_API_D3D11)
@@ -410,6 +474,16 @@ This file contains expansion macros (X Macros) for OpenXR structures.
#endif
+#if defined(XR_USE_PLATFORM_ML)
+#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_avail, _unavail) \
+ _avail(XrCoordinateSpaceCreateInfoML, XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML) \
+
+#else
+#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_avail, _unavail) \
+ _unavail(XrCoordinateSpaceCreateInfoML, XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML) \
+
+#endif
+
#if defined(XR_USE_PLATFORM_WIN32)
#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_avail, _unavail) \
_avail(XrHolographicWindowAttachmentMSFT, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT) \
diff --git a/thirdparty/openxr/patches/fix-gcc13-stdint.patch b/thirdparty/openxr/patches/fix-gcc13-stdint.patch
deleted file mode 100644
index 9e659eb210..0000000000
--- a/thirdparty/openxr/patches/fix-gcc13-stdint.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/thirdparty/openxr/src/common/platform_utils.hpp b/thirdparty/openxr/src/common/platform_utils.hpp
-index 85d5cdab10..2d870cfea7 100644
---- a/thirdparty/openxr/src/common/platform_utils.hpp
-+++ b/thirdparty/openxr/src/common/platform_utils.hpp
-@@ -11,6 +11,7 @@
-
- #include "xr_dependencies.h"
- #include <string>
-+#include <stdint.h>
- #include <stdlib.h>
-
- // OpenXR paths and registry key locations
diff --git a/thirdparty/openxr/src/.clang-format b/thirdparty/openxr/src/.clang-format
deleted file mode 100644
index 36546cab92..0000000000
--- a/thirdparty/openxr/src/.clang-format
+++ /dev/null
@@ -1,10 +0,0 @@
----
-# Copyright (c) 2017-2022, The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-# Use defaults from the Google style with the following exceptions:
-BasedOnStyle: Google
-IndentWidth: 4
-ColumnLimit: 132
-SortIncludes: false
-...
diff --git a/thirdparty/openxr/src/common/extra_algorithms.h b/thirdparty/openxr/src/common/extra_algorithms.h
index 64af4d08ff..eec429e12a 100644
--- a/thirdparty/openxr/src/common/extra_algorithms.h
+++ b/thirdparty/openxr/src/common/extra_algorithms.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
diff --git a/thirdparty/openxr/src/common/filesystem_utils.cpp b/thirdparty/openxr/src/common/filesystem_utils.cpp
index d3d4182fb9..16e6ff3292 100644
--- a/thirdparty/openxr/src/common/filesystem_utils.cpp
+++ b/thirdparty/openxr/src/common/filesystem_utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/common/filesystem_utils.hpp b/thirdparty/openxr/src/common/filesystem_utils.hpp
index 4a5c987e7b..3dea1b2c3e 100644
--- a/thirdparty/openxr/src/common/filesystem_utils.hpp
+++ b/thirdparty/openxr/src/common/filesystem_utils.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/common/hex_and_handles.h b/thirdparty/openxr/src/common/hex_and_handles.h
index 341013d32b..300669033f 100644
--- a/thirdparty/openxr/src/common/hex_and_handles.h
+++ b/thirdparty/openxr/src/common/hex_and_handles.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
diff --git a/thirdparty/openxr/src/common/loader_interfaces.h b/thirdparty/openxr/src/common/loader_interfaces.h
index 9c74ed16f3..020c3456ea 100644
--- a/thirdparty/openxr/src/common/loader_interfaces.h
+++ b/thirdparty/openxr/src/common/loader_interfaces.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/common/object_info.cpp b/thirdparty/openxr/src/common/object_info.cpp
index 95b5aaf404..3f8f96bc6e 100644
--- a/thirdparty/openxr/src/common/object_info.cpp
+++ b/thirdparty/openxr/src/common/object_info.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
@@ -132,6 +132,8 @@ XrSdkSessionLabel::XrSdkSessionLabel(const XrDebugUtilsLabelEXT& label_info, boo
: label_name(label_info.labelName), debug_utils_label(label_info), is_individual_label(individual) {
// Update the c string pointer to the one we hold.
debug_utils_label.labelName = label_name.c_str();
+ // Zero out the next pointer to avoid a dangling pointer
+ debug_utils_label.next = nullptr;
}
XrSdkSessionLabelPtr XrSdkSessionLabel::make(const XrDebugUtilsLabelEXT& label_info, bool individual) {
@@ -143,7 +145,7 @@ void DebugUtilsData::AddObjectName(uint64_t object_handle, XrObjectType object_t
}
// We always want to remove the old individual label before we do anything else.
-// So, do that in it's own method
+// So, do that in its own method
void DebugUtilsData::RemoveIndividualLabel(XrSdkSessionLabelList& label_vec) {
if (!label_vec.empty() && label_vec.back()->is_individual_label) {
label_vec.pop_back();
diff --git a/thirdparty/openxr/src/common/object_info.h b/thirdparty/openxr/src/common/object_info.h
index 8e9742b605..247ede0dcc 100644
--- a/thirdparty/openxr/src/common/object_info.h
+++ b/thirdparty/openxr/src/common/object_info.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
diff --git a/thirdparty/openxr/src/common/platform_utils.hpp b/thirdparty/openxr/src/common/platform_utils.hpp
index 2d870cfea7..219d19789d 100644
--- a/thirdparty/openxr/src/common/platform_utils.hpp
+++ b/thirdparty/openxr/src/common/platform_utils.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -37,6 +37,10 @@
#include "common_config.h"
#endif // OPENXR_HAVE_COMMON_CONFIG
+// Consumers of this file must ensure this function is implemented. For example, the loader will implement this function so that it
+// can route messages through the loader's logging system.
+void LogPlatformUtilsError(const std::string& message);
+
// Environment variables
#if defined(XR_OS_LINUX) || defined(XR_OS_APPLE)
@@ -56,9 +60,11 @@ static inline char* ImplGetSecureEnv(const char* name) {
#elif defined(HAVE___SECURE_GETENV)
return __secure_getenv(name);
#else
+// clang-format off
#pragma message( \
"Warning: Falling back to non-secure getenv for environmental" \
"lookups! Consider updating to a different libc.")
+ // clang-format on
return ImplGetEnv(name);
#endif
@@ -79,6 +85,12 @@ static inline std::string PlatformUtilsGetEnv(const char* name) {
static inline std::string PlatformUtilsGetSecureEnv(const char* name) {
auto str = detail::ImplGetSecureEnv(name);
if (str == nullptr) {
+ str = detail::ImplGetEnv(name);
+ if (str != nullptr && !std::string(str).empty()) {
+ LogPlatformUtilsError(std::string("!!! WARNING !!! Environment variable ") + name +
+ " is being ignored due to running with secure execution. The value '" + str +
+ "' will NOT be used.");
+ }
return {};
}
return str;
@@ -131,12 +143,6 @@ static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std:
#elif defined(XR_OS_WINDOWS)
-#if !defined(NDEBUG)
-inline void LogError(const std::string& error) { OutputDebugStringA(error.c_str()); }
-#else
-#define LogError(x)
-#endif
-
inline std::wstring utf8_to_wide(const std::string& utf8Text) {
if (utf8Text.empty()) {
return {};
@@ -145,7 +151,7 @@ inline std::wstring utf8_to_wide(const std::string& utf8Text) {
std::wstring wideText;
const int wideLength = ::MultiByteToWideChar(CP_UTF8, 0, utf8Text.data(), (int)utf8Text.size(), nullptr, 0);
if (wideLength == 0) {
- LogError("utf8_to_wide get size error: " + std::to_string(::GetLastError()));
+ LogPlatformUtilsError("utf8_to_wide get size error: " + std::to_string(::GetLastError()));
return {};
}
@@ -154,7 +160,7 @@ inline std::wstring utf8_to_wide(const std::string& utf8Text) {
wchar_t* wideString = const_cast<wchar_t*>(wideText.data()); // mutable data() only exists in c++17
const int length = ::MultiByteToWideChar(CP_UTF8, 0, utf8Text.data(), (int)utf8Text.size(), wideString, wideLength);
if (length != wideLength) {
- LogError("utf8_to_wide convert string error: " + std::to_string(::GetLastError()));
+ LogPlatformUtilsError("utf8_to_wide convert string error: " + std::to_string(::GetLastError()));
return {};
}
@@ -169,7 +175,7 @@ inline std::string wide_to_utf8(const std::wstring& wideText) {
std::string narrowText;
int narrowLength = ::WideCharToMultiByte(CP_UTF8, 0, wideText.data(), (int)wideText.size(), nullptr, 0, nullptr, nullptr);
if (narrowLength == 0) {
- LogError("wide_to_utf8 get size error: " + std::to_string(::GetLastError()));
+ LogPlatformUtilsError("wide_to_utf8 get size error: " + std::to_string(::GetLastError()));
return {};
}
@@ -179,7 +185,7 @@ inline std::string wide_to_utf8(const std::wstring& wideText) {
const int length =
::WideCharToMultiByte(CP_UTF8, 0, wideText.data(), (int)wideText.size(), narrowString, narrowLength, nullptr, nullptr);
if (length != narrowLength) {
- LogError("wide_to_utf8 convert string error: " + std::to_string(::GetLastError()));
+ LogPlatformUtilsError("wide_to_utf8 convert string error: " + std::to_string(::GetLastError()));
return {};
}
@@ -245,7 +251,7 @@ static inline std::string PlatformUtilsGetEnv(const char* name) {
// call if there was enough capacity. Else it returns the required capacity (including null terminator).
const DWORD length = ::GetEnvironmentVariableW(wname.c_str(), wValueData, (DWORD)wValue.size());
if ((length == 0) || (length >= wValue.size())) { // If error or the variable increased length between calls...
- LogError("GetEnvironmentVariable get value error: " + std::to_string(::GetLastError()));
+ LogPlatformUtilsError("GetEnvironmentVariable get value error: " + std::to_string(::GetLastError()));
return {};
}
@@ -256,13 +262,20 @@ static inline std::string PlatformUtilsGetEnv(const char* name) {
// Acts the same as PlatformUtilsGetEnv except returns an empty string if IsHighIntegrityLevel.
static inline std::string PlatformUtilsGetSecureEnv(const char* name) {
+ // No secure version for Windows so the below integrity check is needed.
+ const std::string envValue = PlatformUtilsGetEnv(name);
+
// Do not allow high integrity processes to act on data that can be controlled by medium integrity processes.
if (IsHighIntegrityLevel()) {
+ if (!envValue.empty()) {
+ LogPlatformUtilsError(std::string("!!! WARNING !!! Environment variable ") + name +
+ " is being ignored due to running from an elevated context. The value '" + envValue +
+ "' will NOT be used.");
+ }
return {};
}
- // No secure version for Windows so the above integrity check is needed.
- return PlatformUtilsGetEnv(name);
+ return envValue;
}
// Sets an environment variable via UTF8 strings.
@@ -303,7 +316,7 @@ static inline bool PlatformUtilsSetEnv(const char* /* name */, const char* /* va
// Intended to be only used as a fallback on Android, with a more open, "native" technique used in most cases
static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string& file_name) {
// Prefix for the runtime JSON file name
- static const char* rt_dir_prefixes[] = {"/oem", "/vendor", "/system"};
+ static const char* rt_dir_prefixes[] = {"/product", "/odm", "/oem", "/vendor", "/system"};
static const std::string rt_filename = "/active_runtime.json";
static const std::string subdir = "/etc/openxr/";
for (const auto prefix : rt_dir_prefixes) {
diff --git a/thirdparty/openxr/src/common/stdfs_conditions.h b/thirdparty/openxr/src/common/stdfs_conditions.h
index 6dc18cc620..0a551f08cd 100644
--- a/thirdparty/openxr/src/common/stdfs_conditions.h
+++ b/thirdparty/openxr/src/common/stdfs_conditions.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/common/unique_asset.h b/thirdparty/openxr/src/common/unique_asset.h
index 4929039a03..a8ae8077bc 100644
--- a/thirdparty/openxr/src/common/unique_asset.h
+++ b/thirdparty/openxr/src/common/unique_asset.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
#pragma once
diff --git a/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp b/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp
new file mode 100644
index 0000000000..451219d20f
--- /dev/null
+++ b/thirdparty/openxr/src/common/vulkan_debug_object_namer.hpp
@@ -0,0 +1,63 @@
+// Copyright (c) 2017-2023, The Khronos Group Inc.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+
+#include <vulkan/vulkan_core.h>
+#include <stdexcept>
+
+/// Utility class for assigning debug names to Vulkan objects we create.
+class VulkanDebugObjectNamer {
+ public:
+ /// Construct without initializing
+ VulkanDebugObjectNamer() = default;
+
+ /// Construct and initialize
+ VulkanDebugObjectNamer(VkInstance instance, VkDevice device) : m_vkDevice{device} {
+ vkSetDebugUtilsObjectNameEXT =
+ (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT");
+ }
+ /// Copy constructor
+ VulkanDebugObjectNamer(const VulkanDebugObjectNamer&) = default;
+ /// Copy assignment operator
+ VulkanDebugObjectNamer& operator=(const VulkanDebugObjectNamer&) = default;
+
+ /// Destructor
+ ~VulkanDebugObjectNamer() { Reset(); }
+
+ /// (Re-) Initialize the namer: takes a valid `VkInstance` and `VkDevice`
+ void Init(VkInstance instance, VkDevice device) {
+ Reset();
+ *this = VulkanDebugObjectNamer(instance, device);
+ }
+
+ /// The main operation of the namer: actually set an object name.
+ ///
+ /// If the namer is not initialized, this exits silently.
+ VkResult SetName(VkObjectType objectType, uint64_t objectHandle, const char* pObjectName) const {
+ if (m_vkDevice == nullptr) {
+ return VK_SUCCESS;
+ }
+ if (vkSetDebugUtilsObjectNameEXT != nullptr) {
+ VkDebugUtilsObjectNameInfoEXT nameInfo{VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, nullptr, objectType,
+ objectHandle, pObjectName};
+ return vkSetDebugUtilsObjectNameEXT(m_vkDevice, &nameInfo);
+ }
+ return VK_SUCCESS;
+ }
+
+ /// De-initialize the namer, forgetting the device and the function pointer loaded from the instance.
+ void Reset() {
+ vkSetDebugUtilsObjectNameEXT = nullptr;
+ m_vkDevice = VK_NULL_HANDLE;
+ }
+
+ private:
+ VkDevice m_vkDevice{VK_NULL_HANDLE};
+ PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT{nullptr};
+};
+
+#endif
diff --git a/thirdparty/openxr/src/common/xr_dependencies.h b/thirdparty/openxr/src/common/xr_dependencies.h
index e34527abc3..5c7bd04774 100644
--- a/thirdparty/openxr/src/common/xr_dependencies.h
+++ b/thirdparty/openxr/src/common/xr_dependencies.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2022, The Khronos Group Inc.
+// Copyright (c) 2018-2023, The Khronos Group Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
@@ -46,18 +46,6 @@
#ifdef XR_USE_PLATFORM_XLIB
#include <X11/Xlib.h>
#include <X11/Xutil.h>
-
-#ifdef Success
-#undef Success
-#endif // Success
-
-#ifdef Always
-#undef Always
-#endif // Always
-
-#ifdef None
-#undef None
-#endif // None
#endif // XR_USE_PLATFORM_XLIB
#ifdef XR_USE_PLATFORM_XCB
@@ -72,7 +60,7 @@
#include <xcb/glx.h>
#endif // XR_USE_PLATFORM_XCB
#ifdef XR_USE_PLATFORM_MACOS
-#include <CL/cl_gl_ext.h>
+#include <OpenCL/cl_gl_ext.h>
#endif // XR_USE_PLATFORM_MACOS
#endif // XR_USE_GRAPHICS_API_OPENGL
@@ -87,3 +75,19 @@
#ifdef XR_USE_PLATFORM_WAYLAND
#include "wayland-client.h"
#endif // XR_USE_PLATFORM_WAYLAND
+
+#ifdef XR_USE_GRAPHICS_API_OPENGL
+#if defined(XR_USE_PLATFORM_XLIB) || defined(XR_USE_PLATFORM_XCB)
+#ifdef Success
+#undef Success
+#endif // Success
+
+#ifdef Always
+#undef Always
+#endif // Always
+
+#ifdef None
+#undef None
+#endif // None
+#endif // defined(XR_USE_PLATFORM_XLIB) || defined(XR_USE_PLATFORM_XCB)
+#endif // XR_USE_GRAPHICS_API_OPENGL
diff --git a/thirdparty/openxr/src/common/xr_linear.h b/thirdparty/openxr/src/common/xr_linear.h
index 1f0e803b7a..5b0da645ac 100644
--- a/thirdparty/openxr/src/common/xr_linear.h
+++ b/thirdparty/openxr/src/common/xr_linear.h
@@ -21,11 +21,6 @@
#ifndef XR_LINEAR_H_
#define XR_LINEAR_H_
-#if defined(OS_LINUX_XCB) || defined(OS_LINUX_XCB_GLX) || defined(OS_LINUX_WAYLAND)
-#pragma GCC diagnostic ignored "-Wunused-function"
-#pragma clang diagnostic ignored "-Wunused-function"
-#endif
-
#include <openxr/openxr.h>
/*
@@ -51,6 +46,7 @@ XrVector2f
XrVector3f
XrVector4f
XrQuaternionf
+XrPosef
XrMatrix4x4f
inline static void XrVector3f_Set(XrVector3f* v, const float value);
@@ -64,8 +60,18 @@ inline static void XrVector3f_Scale(XrVector3f* result, const XrVector3f* a, con
inline static void XrVector3f_Normalize(XrVector3f* v);
inline static float XrVector3f_Length(const XrVector3f* v);
+inline static void XrQuaternionf_CreateIdentity(XrQuaternionf* q);
+inline static void XrQuaternionf_CreateFromAxisAngle(XrQuaternionf* result, const XrVector3f* axis, const float angleInRadians);
inline static void XrQuaternionf_Lerp(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b, const float fraction);
-inline static void XrQuaternionf_Multiply(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b;
+inline static void XrQuaternionf_Multiply(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b);
+inline static void XrQuaternionf_Invert(XrQuaternionf* result, const XrQuaternionf* q);
+inline static void XrQuaternionf_Normalize(XrQuaternionf* q);
+inline static void XrQuaternionf_RotateVector3f(XrVector3f* result, const XrQuaternionf* a, const XrVector3f* v);
+
+inline static void XrPosef_CreateIdentity(XrPosef* result);
+inline static void XrPosef_TransformVector3f(XrVector3f* result, const XrPosef* a, const XrVector3f* v);
+inline static void XrPosef_Multiply(XrPosef* result, const XrPosef* a, const XrPosef* b);
+inline static void XrPosef_Invert(XrPosef* result, const XrPosef* a);
inline static void XrMatrix4x4f_CreateIdentity(XrMatrix4x4f* result);
inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const float x, const float y, const float z);
@@ -74,13 +80,13 @@ inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float
inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z);
inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* result, const XrVector3f* translation,
const XrQuaternionf* rotation, const XrVector3f* scale);
-inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, const float tanAngleLeft, const float tanAngleRight,
- const float tanAngleUp, float const tanAngleDown, const float nearZ,
- const float farZ);
-inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, const float fovDegreesLeft, const float fovDegreesRight,
- const float fovDegreeUp, const float fovDegreesDown, const float nearZ,
- const float farZ);
-inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* src);
+inline static void XrMatrix4x4f_CreateFromRigidTransform(XrMatrix4x4f* result, const XrPosef* s);
+inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const float tanAngleLeft,
+ const float tanAngleRight, const float tanAngleUp, float const tanAngleDown,
+ const float nearZ, const float farZ);
+inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const XrFovf fov,
+ const float nearZ, const float farZ);
+inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* quat);
inline static void XrMatrix4x4f_CreateOffsetScaleForBounds(XrMatrix4x4f* result, const XrMatrix4x4f* matrix, const XrVector3f* mins,
const XrVector3f* maxs);
@@ -207,6 +213,13 @@ inline static void XrVector3f_Normalize(XrVector3f* v) {
inline static float XrVector3f_Length(const XrVector3f* v) { return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z); }
+inline static void XrQuaternionf_CreateIdentity(XrQuaternionf* q) {
+ q->x = 0.0f;
+ q->y = 0.0f;
+ q->z = 0.0f;
+ q->w = 1.0f;
+}
+
inline static void XrQuaternionf_CreateFromAxisAngle(XrQuaternionf* result, const XrVector3f* axis, const float angleInRadians) {
float s = sinf(angleInRadians / 2.0f);
float lengthRcp = XrRcpSqrt(axis->x * axis->x + axis->y * axis->y + axis->z * axis->z);
@@ -238,6 +251,58 @@ inline static void XrQuaternionf_Multiply(XrQuaternionf* result, const XrQuatern
result->w = (b->w * a->w) - (b->x * a->x) - (b->y * a->y) - (b->z * a->z);
}
+inline static void XrQuaternionf_Invert(XrQuaternionf* result, const XrQuaternionf* q) {
+ result->x = -q->x;
+ result->y = -q->y;
+ result->z = -q->z;
+ result->w = q->w;
+}
+
+inline static void XrQuaternionf_Normalize(XrQuaternionf* q) {
+ const float lengthRcp = XrRcpSqrt(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
+ q->x *= lengthRcp;
+ q->y *= lengthRcp;
+ q->z *= lengthRcp;
+ q->w *= lengthRcp;
+}
+
+inline static void XrQuaternionf_RotateVector3f(XrVector3f* result, const XrQuaternionf* a, const XrVector3f* v) {
+ XrQuaternionf q = {v->x, v->y, v->z, 0.0f};
+ XrQuaternionf aq;
+ XrQuaternionf_Multiply(&aq, &q, a);
+ XrQuaternionf aInv;
+ XrQuaternionf_Invert(&aInv, a);
+ XrQuaternionf aqaInv;
+ XrQuaternionf_Multiply(&aqaInv, &aInv, &aq);
+
+ result->x = aqaInv.x;
+ result->y = aqaInv.y;
+ result->z = aqaInv.z;
+}
+
+inline static void XrPosef_CreateIdentity(XrPosef* result) {
+ XrQuaternionf_CreateIdentity(&result->orientation);
+ XrVector3f_Set(&result->position, 0);
+}
+
+inline static void XrPosef_TransformVector3f(XrVector3f* result, const XrPosef* a, const XrVector3f* v) {
+ XrVector3f r0;
+ XrQuaternionf_RotateVector3f(&r0, &a->orientation, v);
+ XrVector3f_Add(result, &r0, &a->position);
+}
+
+inline static void XrPosef_Multiply(XrPosef* result, const XrPosef* a, const XrPosef* b) {
+ XrQuaternionf_Multiply(&result->orientation, &b->orientation, &a->orientation);
+ XrPosef_TransformVector3f(&result->position, a, &b->position);
+}
+
+inline static void XrPosef_Invert(XrPosef* result, const XrPosef* a) {
+ XrQuaternionf_Invert(&result->orientation, &a->orientation);
+ XrVector3f aPosNeg;
+ XrVector3f_Scale(&aPosNeg, &a->position, -1.0f);
+ XrQuaternionf_RotateVector3f(&result->position, &result->orientation, &aPosNeg);
+}
+
// Use left-multiplication to accumulate transformations.
inline static void XrMatrix4x4f_Multiply(XrMatrix4x4f* result, const XrMatrix4x4f* a, const XrMatrix4x4f* b) {
result->m[0] = a->m[0] * b->m[0] + a->m[4] * b->m[1] + a->m[8] * b->m[2] + a->m[12] * b->m[3];
@@ -379,23 +444,31 @@ inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const fl
}
// Creates a rotation matrix.
-// If -Z=forward, +Y=up, +X=right, then degreesX=pitch, degreesY=yaw, degreesZ=roll.
-inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY,
- const float degreesZ) {
- const float sinX = sinf(degreesX * (MATH_PI / 180.0f));
- const float cosX = cosf(degreesX * (MATH_PI / 180.0f));
+// If -Z=forward, +Y=up, +X=right, then radiansX=pitch, radiansY=yaw, radiansZ=roll.
+inline static void XrMatrix4x4f_CreateRotationRadians(XrMatrix4x4f* result, const float radiansX, const float radiansY,
+ const float radiansZ) {
+ const float sinX = sinf(radiansX);
+ const float cosX = cosf(radiansX);
const XrMatrix4x4f rotationX = {{1, 0, 0, 0, 0, cosX, sinX, 0, 0, -sinX, cosX, 0, 0, 0, 0, 1}};
- const float sinY = sinf(degreesY * (MATH_PI / 180.0f));
- const float cosY = cosf(degreesY * (MATH_PI / 180.0f));
+ const float sinY = sinf(radiansY);
+ const float cosY = cosf(radiansY);
const XrMatrix4x4f rotationY = {{cosY, 0, -sinY, 0, 0, 1, 0, 0, sinY, 0, cosY, 0, 0, 0, 0, 1}};
- const float sinZ = sinf(degreesZ * (MATH_PI / 180.0f));
- const float cosZ = cosf(degreesZ * (MATH_PI / 180.0f));
+ const float sinZ = sinf(radiansZ);
+ const float cosZ = cosf(radiansZ);
const XrMatrix4x4f rotationZ = {{cosZ, sinZ, 0, 0, -sinZ, cosZ, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}};
XrMatrix4x4f rotationXY;
XrMatrix4x4f_Multiply(&rotationXY, &rotationY, &rotationX);
XrMatrix4x4f_Multiply(result, &rotationZ, &rotationXY);
}
+// Creates a rotation matrix.
+// If -Z=forward, +Y=up, +X=right, then degreesX=pitch, degreesY=yaw, degreesZ=roll.
+inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY,
+ const float degreesZ) {
+ XrMatrix4x4f_CreateRotationRadians(result, degreesX * (MATH_PI / 180.0f), degreesY * (MATH_PI / 180.0f),
+ degreesZ * (MATH_PI / 180.0f));
+}
+
// Creates a scale matrix.
inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z) {
result->m[0] = x;
@@ -471,6 +544,11 @@ inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* res
XrMatrix4x4f_Multiply(result, &translationMatrix, &combinedMatrix);
}
+inline static void XrMatrix4x4f_CreateFromRigidTransform(XrMatrix4x4f* result, const XrPosef* s) {
+ const XrVector3f identityScale = {1.0f, 1.0f, 1.0f};
+ XrMatrix4x4f_CreateTranslationRotationScale(result, &s->position, &s->orientation, &identityScale);
+}
+
// Creates a projection matrix based on the specified dimensions.
// The projection matrix transforms -Z=forward, +Y=up, +X=right to the appropriate clip space for the graphics API.
// The far plane is placed at infinity if farZ <= nearZ.
diff --git a/thirdparty/openxr/src/loader/android_utilities.cpp b/thirdparty/openxr/src/loader/android_utilities.cpp
index 59d9a99b74..9a3ad76ce0 100644
--- a/thirdparty/openxr/src/loader/android_utilities.cpp
+++ b/thirdparty/openxr/src/loader/android_utilities.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2022, The Khronos Group Inc.
+// Copyright (c) 2020-2023, The Khronos Group Inc.
// Copyright (c) 2020-2021, Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
@@ -19,10 +19,10 @@
#include <vector>
#include <android/log.h>
-#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "openxr_loader", __VA_ARGS__)
-#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, "openxr_loader", __VA_ARGS__)
-#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "openxr_loader", __VA_ARGS__)
-#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, "openxr_loader", __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "OpenXR-Loader", __VA_ARGS__)
+#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, "OpenXR-Loader", __VA_ARGS__)
+#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "OpenXR-Loader", __VA_ARGS__)
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, "OpenXR-Loader", __VA_ARGS__)
namespace openxr_android {
using wrap::android::content::ContentUris;
diff --git a/thirdparty/openxr/src/loader/android_utilities.h b/thirdparty/openxr/src/loader/android_utilities.h
index adb8abaf1f..f66c9bf1d0 100644
--- a/thirdparty/openxr/src/loader/android_utilities.h
+++ b/thirdparty/openxr/src/loader/android_utilities.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2020-2022, The Khronos Group Inc.
+// Copyright (c) 2020-2023, The Khronos Group Inc.
// Copyright (c) 2020-2021, Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
diff --git a/thirdparty/openxr/src/loader/api_layer_interface.cpp b/thirdparty/openxr/src/loader/api_layer_interface.cpp
index b946e09402..5560c31a52 100644
--- a/thirdparty/openxr/src/loader/api_layer_interface.cpp
+++ b/thirdparty/openxr/src/loader/api_layer_interface.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -82,6 +82,12 @@ XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_comm
return result;
}
+ // check for potential overflow before static_cast<uint32_t>
+ if (manifest_files.size() >= UINT32_MAX) {
+ LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::GetApiLayerProperties - too many API layers found");
+ return XR_ERROR_RUNTIME_FAILURE;
+ }
+
manifest_count = static_cast<uint32_t>(manifest_files.size());
if (nullptr == outgoing_count) {
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
@@ -131,8 +137,8 @@ XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& op
}
bool found = false;
- auto num_files = static_cast<uint32_t>(manifest_files.size());
- for (uint32_t man_file = 0; man_file < num_files; ++man_file) {
+ size_t num_files = manifest_files.size();
+ for (size_t man_file = 0; man_file < num_files; ++man_file) {
// If a layer with the provided name exists, get it's instance extension information.
if (manifest_files[man_file]->LayerName() == layer_name) {
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
@@ -172,8 +178,8 @@ XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& op
}
// Grab the layer instance extensions information
- auto num_files = static_cast<uint32_t>(manifest_files.size());
- for (uint32_t man_file = 0; man_file < num_files; ++man_file) {
+ size_t num_files = manifest_files.size();
+ for (size_t man_file = 0; man_file < num_files; ++man_file) {
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
}
}
diff --git a/thirdparty/openxr/src/loader/api_layer_interface.hpp b/thirdparty/openxr/src/loader/api_layer_interface.hpp
index b93e44584e..98685b0c32 100644
--- a/thirdparty/openxr/src/loader/api_layer_interface.hpp
+++ b/thirdparty/openxr/src/loader/api_layer_interface.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/exception_handling.hpp b/thirdparty/openxr/src/loader/exception_handling.hpp
index 428dd00279..bc0d9b65e3 100644
--- a/thirdparty/openxr/src/loader/exception_handling.hpp
+++ b/thirdparty/openxr/src/loader/exception_handling.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2022, The Khronos Group Inc.
+// Copyright (c) 2019-2023, The Khronos Group Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
diff --git a/thirdparty/openxr/src/loader/loader_core.cpp b/thirdparty/openxr/src/loader/loader_core.cpp
index f2bc87d1fa..98d3fa971a 100644
--- a/thirdparty/openxr/src/loader/loader_core.cpp
+++ b/thirdparty/openxr/src/loader/loader_core.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/loader_instance.cpp b/thirdparty/openxr/src/loader/loader_instance.cpp
index b24c8de53b..badd39193c 100644
--- a/thirdparty/openxr/src/loader/loader_instance.cpp
+++ b/thirdparty/openxr/src/loader/loader_instance.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -200,8 +200,8 @@ XrResult LoaderInstance::CreateInstance(PFN_xrGetInstanceProcAddr get_instance_p
if (!api_layer_interfaces.empty()) {
// Initialize an array of ApiLayerNextInfo structs
std::unique_ptr<XrApiLayerNextInfo[]> next_info_list(new XrApiLayerNextInfo[api_layer_interfaces.size()]);
- auto ni_index = static_cast<uint32_t>(api_layer_interfaces.size() - 1);
- for (uint32_t i = 0; i <= ni_index; i++) {
+ size_t ni_index = api_layer_interfaces.size() - 1;
+ for (size_t i = 0; i <= ni_index; i++) {
next_info_list[i].structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO;
next_info_list[i].structVersion = XR_API_LAYER_NEXT_INFO_STRUCT_VERSION;
next_info_list[i].structSize = sizeof(XrApiLayerNextInfo);
diff --git a/thirdparty/openxr/src/loader/loader_instance.hpp b/thirdparty/openxr/src/loader/loader_instance.hpp
index 1d43ed758d..a0268a855c 100644
--- a/thirdparty/openxr/src/loader/loader_instance.hpp
+++ b/thirdparty/openxr/src/loader/loader_instance.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/loader_logger.cpp b/thirdparty/openxr/src/loader/loader_logger.cpp
index dba46aa92d..1c8d64f394 100644
--- a/thirdparty/openxr/src/loader/loader_logger.cpp
+++ b/thirdparty/openxr/src/loader/loader_logger.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -26,6 +26,9 @@
#include <utility>
#include <vector>
+// For routing platform_utils.hpp messages into the LoaderLogger.
+void LogPlatformUtilsError(const std::string& message) { LoaderLogger::LogErrorMessage("platform_utils", message); }
+
bool LoaderLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT /*message_severity*/,
XrDebugUtilsMessageTypeFlagsEXT /*message_type*/,
const XrDebugUtilsMessengerCallbackDataEXT* /*callback_data*/) {
diff --git a/thirdparty/openxr/src/loader/loader_logger.hpp b/thirdparty/openxr/src/loader/loader_logger.hpp
index 260ebe354a..d31fac093a 100644
--- a/thirdparty/openxr/src/loader/loader_logger.hpp
+++ b/thirdparty/openxr/src/loader/loader_logger.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/loader_logger_recorders.cpp b/thirdparty/openxr/src/loader/loader_logger_recorders.cpp
index 7673678c60..32e4687b2f 100644
--- a/thirdparty/openxr/src/loader/loader_logger_recorders.cpp
+++ b/thirdparty/openxr/src/loader/loader_logger_recorders.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -160,16 +160,16 @@ bool DebugUtilsLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits messag
XrDebugUtilsMessageTypeFlagsEXT utils_type = LoaderLogMessageTypesToDebugUtilsMessageTypes(message_type);
// Convert the loader log message into the debug utils log message information
- XrDebugUtilsMessengerCallbackDataEXT utils_callback_data = {};
+ XrDebugUtilsMessengerCallbackDataEXT utils_callback_data{};
utils_callback_data.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
utils_callback_data.messageId = callback_data->message_id;
utils_callback_data.functionName = callback_data->command_name;
utils_callback_data.message = callback_data->message;
- std::vector<XrDebugUtilsObjectNameInfoEXT> utils_objects;
- utils_objects.resize(callback_data->object_count);
+
+ XrDebugUtilsObjectNameInfoEXT example_utils_info{};
+ example_utils_info.type = XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
+ std::vector<XrDebugUtilsObjectNameInfoEXT> utils_objects(callback_data->object_count, example_utils_info);
for (uint8_t object = 0; object < callback_data->object_count; ++object) {
- utils_objects[object].type = XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
- utils_objects[object].next = nullptr;
utils_objects[object].objectHandle = callback_data->objects[object].handle;
utils_objects[object].objectType = callback_data->objects[object].type;
utils_objects[object].objectName = callback_data->objects[object].name.c_str();
diff --git a/thirdparty/openxr/src/loader/loader_logger_recorders.hpp b/thirdparty/openxr/src/loader/loader_logger_recorders.hpp
index 31e5243c45..7b934202d5 100644
--- a/thirdparty/openxr/src/loader/loader_logger_recorders.hpp
+++ b/thirdparty/openxr/src/loader/loader_logger_recorders.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/loader_platform.hpp b/thirdparty/openxr/src/loader/loader_platform.hpp
index e2757fffb9..0ea80c05b8 100644
--- a/thirdparty/openxr/src/loader/loader_platform.hpp
+++ b/thirdparty/openxr/src/loader/loader_platform.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/manifest_file.cpp b/thirdparty/openxr/src/loader/manifest_file.cpp
index 1b0ef07848..99f4e84104 100644
--- a/thirdparty/openxr/src/loader/manifest_file.cpp
+++ b/thirdparty/openxr/src/loader/manifest_file.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -27,13 +27,13 @@
#include <openxr/openxr.h>
#include <algorithm>
+#include <cstdlib>
+#include <cstdio>
#include <cstring>
#include <fstream>
#include <memory>
#include <sstream>
#include <stdexcept>
-#include <stdio.h>
-#include <stdlib.h>
#include <string>
#include <unordered_map>
#include <utility>
@@ -233,6 +233,12 @@ static void ReadDataFilesInSearchPaths(const std::string &override_env_var, cons
relative_home_path += relative_path;
CopyIncludedPaths(true, home, relative_home_path, search_path);
}
+#elif defined(XR_OS_ANDROID)
+ CopyIncludedPaths(true, "/product/etc", relative_path, search_path);
+ CopyIncludedPaths(true, "/odm/etc", relative_path, search_path);
+ CopyIncludedPaths(true, "/oem/etc", relative_path, search_path);
+ CopyIncludedPaths(true, "/vendor/etc", relative_path, search_path);
+ CopyIncludedPaths(true, "/system/etc", relative_path, search_path);
#else
(void)relative_path;
#endif
@@ -447,9 +453,8 @@ static void GetExtensionProperties(const std::vector<ExtensionListing> &extensio
if (it != props.end()) {
it->extensionVersion = std::max(it->extensionVersion, ext.extension_version);
} else {
- XrExtensionProperties prop = {};
+ XrExtensionProperties prop{};
prop.type = XR_TYPE_EXTENSION_PROPERTIES;
- prop.next = nullptr;
strncpy(prop.extensionName, ext.name.c_str(), XR_MAX_EXTENSION_NAME_SIZE - 1);
prop.extensionName[XR_MAX_EXTENSION_NAME_SIZE - 1] = '\0';
prop.extensionVersion = ext.extension_version;
diff --git a/thirdparty/openxr/src/loader/manifest_file.hpp b/thirdparty/openxr/src/loader/manifest_file.hpp
index de0aab65c2..46b842c663 100644
--- a/thirdparty/openxr/src/loader/manifest_file.hpp
+++ b/thirdparty/openxr/src/loader/manifest_file.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/runtime_interface.cpp b/thirdparty/openxr/src/loader/runtime_interface.cpp
index 0f081ff9b2..d9ab86bb58 100644
--- a/thirdparty/openxr/src/loader/runtime_interface.cpp
+++ b/thirdparty/openxr/src/loader/runtime_interface.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -430,12 +430,10 @@ void RuntimeInterface::GetInstanceExtensionProperties(std::vector<XrExtensionPro
// Get the count from the runtime
rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, nullptr);
if (count_output > 0) {
- runtime_extension_properties.resize(count_output);
+ XrExtensionProperties example_properties{};
+ example_properties.type = XR_TYPE_EXTENSION_PROPERTIES;
+ runtime_extension_properties.resize(count_output, example_properties);
count = count_output;
- for (XrExtensionProperties& ext_prop : runtime_extension_properties) {
- ext_prop.type = XR_TYPE_EXTENSION_PROPERTIES;
- ext_prop.next = nullptr;
- }
rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, runtime_extension_properties.data());
}
size_t ext_count = runtime_extension_properties.size();
diff --git a/thirdparty/openxr/src/loader/runtime_interface.hpp b/thirdparty/openxr/src/loader/runtime_interface.hpp
index fa53ee03f2..8d55ec674a 100644
--- a/thirdparty/openxr/src/loader/runtime_interface.hpp
+++ b/thirdparty/openxr/src/loader/runtime_interface.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/xr_generated_loader.cpp b/thirdparty/openxr/src/loader/xr_generated_loader.cpp
index 2ce323e51f..e7767fd30a 100644
--- a/thirdparty/openxr/src/loader/xr_generated_loader.cpp
+++ b/thirdparty/openxr/src/loader/xr_generated_loader.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
@@ -6,7 +6,7 @@
// See loader_source_generator.py for modifications
// ************************************************************
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/loader/xr_generated_loader.hpp b/thirdparty/openxr/src/loader/xr_generated_loader.hpp
index 482cf1e83e..e28e35bbcf 100644
--- a/thirdparty/openxr/src/loader/xr_generated_loader.hpp
+++ b/thirdparty/openxr/src/loader/xr_generated_loader.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
@@ -6,7 +6,7 @@
// See loader_source_generator.py for modifications
// ************************************************************
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
diff --git a/thirdparty/openxr/src/xr_generated_dispatch_table.c b/thirdparty/openxr/src/xr_generated_dispatch_table.c
index 094f9fbbda..302bed31f5 100644
--- a/thirdparty/openxr/src/xr_generated_dispatch_table.c
+++ b/thirdparty/openxr/src/xr_generated_dispatch_table.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
@@ -6,7 +6,7 @@
// See utility_source_generator.py for modifications
// ************************************************************
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -27,6 +27,7 @@
// Author: Mark Young <marky@lunarg.com>
//
+#include <time.h>
#include "xr_generated_dispatch_table.h"
#include "xr_dependencies.h"
#include <openxr/openxr.h>
@@ -236,6 +237,12 @@ void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table,
(get_inst_proc_addr(instance, "xrUpdateSwapchainFB", (PFN_xrVoidFunction*)&table->UpdateSwapchainFB));
(get_inst_proc_addr(instance, "xrGetSwapchainStateFB", (PFN_xrVoidFunction*)&table->GetSwapchainStateFB));
+ // ---- XR_FB_body_tracking extension commands
+ (get_inst_proc_addr(instance, "xrCreateBodyTrackerFB", (PFN_xrVoidFunction*)&table->CreateBodyTrackerFB));
+ (get_inst_proc_addr(instance, "xrDestroyBodyTrackerFB", (PFN_xrVoidFunction*)&table->DestroyBodyTrackerFB));
+ (get_inst_proc_addr(instance, "xrLocateBodyJointsFB", (PFN_xrVoidFunction*)&table->LocateBodyJointsFB));
+ (get_inst_proc_addr(instance, "xrGetBodySkeletonFB", (PFN_xrVoidFunction*)&table->GetBodySkeletonFB));
+
// ---- XR_MSFT_scene_understanding extension commands
(get_inst_proc_addr(instance, "xrEnumerateSceneComputeFeaturesMSFT", (PFN_xrVoidFunction*)&table->EnumerateSceneComputeFeaturesMSFT));
(get_inst_proc_addr(instance, "xrCreateSceneObserverMSFT", (PFN_xrVoidFunction*)&table->CreateSceneObserverMSFT));
@@ -329,6 +336,11 @@ void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table,
// ---- XR_VARJO_view_offset extension commands
(get_inst_proc_addr(instance, "xrSetViewOffsetVARJO", (PFN_xrVoidFunction*)&table->SetViewOffsetVARJO));
+ // ---- XR_ML_compat extension commands
+#if defined(XR_USE_PLATFORM_ML)
+ (get_inst_proc_addr(instance, "xrCreateSpaceFromCoordinateFrameUIDML", (PFN_xrVoidFunction*)&table->CreateSpaceFromCoordinateFrameUIDML));
+#endif // defined(XR_USE_PLATFORM_ML)
+
// ---- XR_MSFT_spatial_anchor_persistence extension commands
(get_inst_proc_addr(instance, "xrCreateSpatialAnchorStoreConnectionMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorStoreConnectionMSFT));
(get_inst_proc_addr(instance, "xrDestroySpatialAnchorStoreConnectionMSFT", (PFN_xrVoidFunction*)&table->DestroySpatialAnchorStoreConnectionMSFT));
@@ -354,6 +366,9 @@ void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table,
(get_inst_proc_addr(instance, "xrGetAudioInputDeviceGuidOculus", (PFN_xrVoidFunction*)&table->GetAudioInputDeviceGuidOculus));
#endif // defined(XR_USE_PLATFORM_WIN32)
+ // ---- XR_FB_spatial_entity_sharing extension commands
+ (get_inst_proc_addr(instance, "xrShareSpacesFB", (PFN_xrVoidFunction*)&table->ShareSpacesFB));
+
// ---- XR_FB_scene extension commands
(get_inst_proc_addr(instance, "xrGetSpaceBoundingBox2DFB", (PFN_xrVoidFunction*)&table->GetSpaceBoundingBox2DFB));
(get_inst_proc_addr(instance, "xrGetSpaceBoundingBox3DFB", (PFN_xrVoidFunction*)&table->GetSpaceBoundingBox3DFB));
@@ -364,24 +379,86 @@ void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table,
// ---- XR_ALMALENCE_digital_lens_control extension commands
(get_inst_proc_addr(instance, "xrSetDigitalLensControlALMALENCE", (PFN_xrVoidFunction*)&table->SetDigitalLensControlALMALENCE));
+ // ---- XR_FB_scene_capture extension commands
+ (get_inst_proc_addr(instance, "xrRequestSceneCaptureFB", (PFN_xrVoidFunction*)&table->RequestSceneCaptureFB));
+
// ---- XR_FB_spatial_entity_container extension commands
(get_inst_proc_addr(instance, "xrGetSpaceContainerFB", (PFN_xrVoidFunction*)&table->GetSpaceContainerFB));
+ // ---- XR_META_foveation_eye_tracked extension commands
+ (get_inst_proc_addr(instance, "xrGetFoveationEyeTrackedStateMETA", (PFN_xrVoidFunction*)&table->GetFoveationEyeTrackedStateMETA));
+
+ // ---- XR_FB_face_tracking extension commands
+ (get_inst_proc_addr(instance, "xrCreateFaceTrackerFB", (PFN_xrVoidFunction*)&table->CreateFaceTrackerFB));
+ (get_inst_proc_addr(instance, "xrDestroyFaceTrackerFB", (PFN_xrVoidFunction*)&table->DestroyFaceTrackerFB));
+ (get_inst_proc_addr(instance, "xrGetFaceExpressionWeightsFB", (PFN_xrVoidFunction*)&table->GetFaceExpressionWeightsFB));
+
+ // ---- XR_FB_eye_tracking_social extension commands
+ (get_inst_proc_addr(instance, "xrCreateEyeTrackerFB", (PFN_xrVoidFunction*)&table->CreateEyeTrackerFB));
+ (get_inst_proc_addr(instance, "xrDestroyEyeTrackerFB", (PFN_xrVoidFunction*)&table->DestroyEyeTrackerFB));
+ (get_inst_proc_addr(instance, "xrGetEyeGazesFB", (PFN_xrVoidFunction*)&table->GetEyeGazesFB));
+
// ---- XR_FB_passthrough_keyboard_hands extension commands
(get_inst_proc_addr(instance, "xrPassthroughLayerSetKeyboardHandsIntensityFB", (PFN_xrVoidFunction*)&table->PassthroughLayerSetKeyboardHandsIntensityFB));
+ // ---- XR_FB_haptic_pcm extension commands
+ (get_inst_proc_addr(instance, "xrGetDeviceSampleRateFB", (PFN_xrVoidFunction*)&table->GetDeviceSampleRateFB));
+
+ // ---- XR_META_virtual_keyboard extension commands
+ (get_inst_proc_addr(instance, "xrCreateVirtualKeyboardMETA", (PFN_xrVoidFunction*)&table->CreateVirtualKeyboardMETA));
+ (get_inst_proc_addr(instance, "xrDestroyVirtualKeyboardMETA", (PFN_xrVoidFunction*)&table->DestroyVirtualKeyboardMETA));
+ (get_inst_proc_addr(instance, "xrCreateVirtualKeyboardSpaceMETA", (PFN_xrVoidFunction*)&table->CreateVirtualKeyboardSpaceMETA));
+ (get_inst_proc_addr(instance, "xrSuggestVirtualKeyboardLocationMETA", (PFN_xrVoidFunction*)&table->SuggestVirtualKeyboardLocationMETA));
+ (get_inst_proc_addr(instance, "xrGetVirtualKeyboardScaleMETA", (PFN_xrVoidFunction*)&table->GetVirtualKeyboardScaleMETA));
+ (get_inst_proc_addr(instance, "xrSetVirtualKeyboardModelVisibilityMETA", (PFN_xrVoidFunction*)&table->SetVirtualKeyboardModelVisibilityMETA));
+ (get_inst_proc_addr(instance, "xrGetVirtualKeyboardModelAnimationStatesMETA", (PFN_xrVoidFunction*)&table->GetVirtualKeyboardModelAnimationStatesMETA));
+ (get_inst_proc_addr(instance, "xrGetVirtualKeyboardDirtyTexturesMETA", (PFN_xrVoidFunction*)&table->GetVirtualKeyboardDirtyTexturesMETA));
+ (get_inst_proc_addr(instance, "xrGetVirtualKeyboardTextureDataMETA", (PFN_xrVoidFunction*)&table->GetVirtualKeyboardTextureDataMETA));
+ (get_inst_proc_addr(instance, "xrSendVirtualKeyboardInputMETA", (PFN_xrVoidFunction*)&table->SendVirtualKeyboardInputMETA));
+ (get_inst_proc_addr(instance, "xrChangeVirtualKeyboardTextContextMETA", (PFN_xrVoidFunction*)&table->ChangeVirtualKeyboardTextContextMETA));
+
+ // ---- XR_OCULUS_external_camera extension commands
+ (get_inst_proc_addr(instance, "xrEnumerateExternalCamerasOCULUS", (PFN_xrVoidFunction*)&table->EnumerateExternalCamerasOCULUS));
+
// ---- XR_META_performance_metrics extension commands
(get_inst_proc_addr(instance, "xrEnumeratePerformanceMetricsCounterPathsMETA", (PFN_xrVoidFunction*)&table->EnumeratePerformanceMetricsCounterPathsMETA));
(get_inst_proc_addr(instance, "xrSetPerformanceMetricsStateMETA", (PFN_xrVoidFunction*)&table->SetPerformanceMetricsStateMETA));
(get_inst_proc_addr(instance, "xrGetPerformanceMetricsStateMETA", (PFN_xrVoidFunction*)&table->GetPerformanceMetricsStateMETA));
(get_inst_proc_addr(instance, "xrQueryPerformanceMetricsCounterMETA", (PFN_xrVoidFunction*)&table->QueryPerformanceMetricsCounterMETA));
+ // ---- XR_FB_spatial_entity_storage_batch extension commands
+ (get_inst_proc_addr(instance, "xrSaveSpaceListFB", (PFN_xrVoidFunction*)&table->SaveSpaceListFB));
+
+ // ---- XR_FB_spatial_entity_user extension commands
+ (get_inst_proc_addr(instance, "xrCreateSpaceUserFB", (PFN_xrVoidFunction*)&table->CreateSpaceUserFB));
+ (get_inst_proc_addr(instance, "xrGetSpaceUserIdFB", (PFN_xrVoidFunction*)&table->GetSpaceUserIdFB));
+ (get_inst_proc_addr(instance, "xrDestroySpaceUserFB", (PFN_xrVoidFunction*)&table->DestroySpaceUserFB));
+
+ // ---- XR_META_passthrough_color_lut extension commands
+ (get_inst_proc_addr(instance, "xrCreatePassthroughColorLutMETA", (PFN_xrVoidFunction*)&table->CreatePassthroughColorLutMETA));
+ (get_inst_proc_addr(instance, "xrDestroyPassthroughColorLutMETA", (PFN_xrVoidFunction*)&table->DestroyPassthroughColorLutMETA));
+ (get_inst_proc_addr(instance, "xrUpdatePassthroughColorLutMETA", (PFN_xrVoidFunction*)&table->UpdatePassthroughColorLutMETA));
+
+ // ---- XR_QCOM_tracking_optimization_settings extension commands
+ (get_inst_proc_addr(instance, "xrSetTrackingOptimizationSettingsHintQCOM", (PFN_xrVoidFunction*)&table->SetTrackingOptimizationSettingsHintQCOM));
+
// ---- XR_HTC_passthrough extension commands
(get_inst_proc_addr(instance, "xrCreatePassthroughHTC", (PFN_xrVoidFunction*)&table->CreatePassthroughHTC));
(get_inst_proc_addr(instance, "xrDestroyPassthroughHTC", (PFN_xrVoidFunction*)&table->DestroyPassthroughHTC));
// ---- XR_HTC_foveation extension commands
(get_inst_proc_addr(instance, "xrApplyFoveationHTC", (PFN_xrVoidFunction*)&table->ApplyFoveationHTC));
+
+ // ---- XR_MNDX_force_feedback_curl extension commands
+ (get_inst_proc_addr(instance, "xrApplyForceFeedbackCurlMNDX", (PFN_xrVoidFunction*)&table->ApplyForceFeedbackCurlMNDX));
+
+ // ---- XR_EXT_plane_detection extension commands
+ (get_inst_proc_addr(instance, "xrCreatePlaneDetectorEXT", (PFN_xrVoidFunction*)&table->CreatePlaneDetectorEXT));
+ (get_inst_proc_addr(instance, "xrDestroyPlaneDetectorEXT", (PFN_xrVoidFunction*)&table->DestroyPlaneDetectorEXT));
+ (get_inst_proc_addr(instance, "xrBeginPlaneDetectionEXT", (PFN_xrVoidFunction*)&table->BeginPlaneDetectionEXT));
+ (get_inst_proc_addr(instance, "xrGetPlaneDetectionStateEXT", (PFN_xrVoidFunction*)&table->GetPlaneDetectionStateEXT));
+ (get_inst_proc_addr(instance, "xrGetPlaneDetectionsEXT", (PFN_xrVoidFunction*)&table->GetPlaneDetectionsEXT));
+ (get_inst_proc_addr(instance, "xrGetPlanePolygonBufferEXT", (PFN_xrVoidFunction*)&table->GetPlanePolygonBufferEXT));
}
diff --git a/thirdparty/openxr/src/xr_generated_dispatch_table.h b/thirdparty/openxr/src/xr_generated_dispatch_table.h
index 93d07a149e..b6e17f98d4 100644
--- a/thirdparty/openxr/src/xr_generated_dispatch_table.h
+++ b/thirdparty/openxr/src/xr_generated_dispatch_table.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
@@ -6,7 +6,7 @@
// See utility_source_generator.py for modifications
// ************************************************************
-// Copyright (c) 2017-2022, The Khronos Group Inc.
+// Copyright (c) 2017-2023, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
@@ -239,6 +239,12 @@ struct XrGeneratedDispatchTable {
PFN_xrUpdateSwapchainFB UpdateSwapchainFB;
PFN_xrGetSwapchainStateFB GetSwapchainStateFB;
+ // ---- XR_FB_body_tracking extension commands
+ PFN_xrCreateBodyTrackerFB CreateBodyTrackerFB;
+ PFN_xrDestroyBodyTrackerFB DestroyBodyTrackerFB;
+ PFN_xrLocateBodyJointsFB LocateBodyJointsFB;
+ PFN_xrGetBodySkeletonFB GetBodySkeletonFB;
+
// ---- XR_MSFT_scene_understanding extension commands
PFN_xrEnumerateSceneComputeFeaturesMSFT EnumerateSceneComputeFeaturesMSFT;
PFN_xrCreateSceneObserverMSFT CreateSceneObserverMSFT;
@@ -332,6 +338,11 @@ struct XrGeneratedDispatchTable {
// ---- XR_VARJO_view_offset extension commands
PFN_xrSetViewOffsetVARJO SetViewOffsetVARJO;
+ // ---- XR_ML_compat extension commands
+#if defined(XR_USE_PLATFORM_ML)
+ PFN_xrCreateSpaceFromCoordinateFrameUIDML CreateSpaceFromCoordinateFrameUIDML;
+#endif // defined(XR_USE_PLATFORM_ML)
+
// ---- XR_MSFT_spatial_anchor_persistence extension commands
PFN_xrCreateSpatialAnchorStoreConnectionMSFT CreateSpatialAnchorStoreConnectionMSFT;
PFN_xrDestroySpatialAnchorStoreConnectionMSFT DestroySpatialAnchorStoreConnectionMSFT;
@@ -357,6 +368,9 @@ struct XrGeneratedDispatchTable {
PFN_xrGetAudioInputDeviceGuidOculus GetAudioInputDeviceGuidOculus;
#endif // defined(XR_USE_PLATFORM_WIN32)
+ // ---- XR_FB_spatial_entity_sharing extension commands
+ PFN_xrShareSpacesFB ShareSpacesFB;
+
// ---- XR_FB_scene extension commands
PFN_xrGetSpaceBoundingBox2DFB GetSpaceBoundingBox2DFB;
PFN_xrGetSpaceBoundingBox3DFB GetSpaceBoundingBox3DFB;
@@ -367,24 +381,86 @@ struct XrGeneratedDispatchTable {
// ---- XR_ALMALENCE_digital_lens_control extension commands
PFN_xrSetDigitalLensControlALMALENCE SetDigitalLensControlALMALENCE;
+ // ---- XR_FB_scene_capture extension commands
+ PFN_xrRequestSceneCaptureFB RequestSceneCaptureFB;
+
// ---- XR_FB_spatial_entity_container extension commands
PFN_xrGetSpaceContainerFB GetSpaceContainerFB;
+ // ---- XR_META_foveation_eye_tracked extension commands
+ PFN_xrGetFoveationEyeTrackedStateMETA GetFoveationEyeTrackedStateMETA;
+
+ // ---- XR_FB_face_tracking extension commands
+ PFN_xrCreateFaceTrackerFB CreateFaceTrackerFB;
+ PFN_xrDestroyFaceTrackerFB DestroyFaceTrackerFB;
+ PFN_xrGetFaceExpressionWeightsFB GetFaceExpressionWeightsFB;
+
+ // ---- XR_FB_eye_tracking_social extension commands
+ PFN_xrCreateEyeTrackerFB CreateEyeTrackerFB;
+ PFN_xrDestroyEyeTrackerFB DestroyEyeTrackerFB;
+ PFN_xrGetEyeGazesFB GetEyeGazesFB;
+
// ---- XR_FB_passthrough_keyboard_hands extension commands
PFN_xrPassthroughLayerSetKeyboardHandsIntensityFB PassthroughLayerSetKeyboardHandsIntensityFB;
+ // ---- XR_FB_haptic_pcm extension commands
+ PFN_xrGetDeviceSampleRateFB GetDeviceSampleRateFB;
+
+ // ---- XR_META_virtual_keyboard extension commands
+ PFN_xrCreateVirtualKeyboardMETA CreateVirtualKeyboardMETA;
+ PFN_xrDestroyVirtualKeyboardMETA DestroyVirtualKeyboardMETA;
+ PFN_xrCreateVirtualKeyboardSpaceMETA CreateVirtualKeyboardSpaceMETA;
+ PFN_xrSuggestVirtualKeyboardLocationMETA SuggestVirtualKeyboardLocationMETA;
+ PFN_xrGetVirtualKeyboardScaleMETA GetVirtualKeyboardScaleMETA;
+ PFN_xrSetVirtualKeyboardModelVisibilityMETA SetVirtualKeyboardModelVisibilityMETA;
+ PFN_xrGetVirtualKeyboardModelAnimationStatesMETA GetVirtualKeyboardModelAnimationStatesMETA;
+ PFN_xrGetVirtualKeyboardDirtyTexturesMETA GetVirtualKeyboardDirtyTexturesMETA;
+ PFN_xrGetVirtualKeyboardTextureDataMETA GetVirtualKeyboardTextureDataMETA;
+ PFN_xrSendVirtualKeyboardInputMETA SendVirtualKeyboardInputMETA;
+ PFN_xrChangeVirtualKeyboardTextContextMETA ChangeVirtualKeyboardTextContextMETA;
+
+ // ---- XR_OCULUS_external_camera extension commands
+ PFN_xrEnumerateExternalCamerasOCULUS EnumerateExternalCamerasOCULUS;
+
// ---- XR_META_performance_metrics extension commands
PFN_xrEnumeratePerformanceMetricsCounterPathsMETA EnumeratePerformanceMetricsCounterPathsMETA;
PFN_xrSetPerformanceMetricsStateMETA SetPerformanceMetricsStateMETA;
PFN_xrGetPerformanceMetricsStateMETA GetPerformanceMetricsStateMETA;
PFN_xrQueryPerformanceMetricsCounterMETA QueryPerformanceMetricsCounterMETA;
+ // ---- XR_FB_spatial_entity_storage_batch extension commands
+ PFN_xrSaveSpaceListFB SaveSpaceListFB;
+
+ // ---- XR_FB_spatial_entity_user extension commands
+ PFN_xrCreateSpaceUserFB CreateSpaceUserFB;
+ PFN_xrGetSpaceUserIdFB GetSpaceUserIdFB;
+ PFN_xrDestroySpaceUserFB DestroySpaceUserFB;
+
+ // ---- XR_META_passthrough_color_lut extension commands
+ PFN_xrCreatePassthroughColorLutMETA CreatePassthroughColorLutMETA;
+ PFN_xrDestroyPassthroughColorLutMETA DestroyPassthroughColorLutMETA;
+ PFN_xrUpdatePassthroughColorLutMETA UpdatePassthroughColorLutMETA;
+
+ // ---- XR_QCOM_tracking_optimization_settings extension commands
+ PFN_xrSetTrackingOptimizationSettingsHintQCOM SetTrackingOptimizationSettingsHintQCOM;
+
// ---- XR_HTC_passthrough extension commands
PFN_xrCreatePassthroughHTC CreatePassthroughHTC;
PFN_xrDestroyPassthroughHTC DestroyPassthroughHTC;
// ---- XR_HTC_foveation extension commands
PFN_xrApplyFoveationHTC ApplyFoveationHTC;
+
+ // ---- XR_MNDX_force_feedback_curl extension commands
+ PFN_xrApplyForceFeedbackCurlMNDX ApplyForceFeedbackCurlMNDX;
+
+ // ---- XR_EXT_plane_detection extension commands
+ PFN_xrCreatePlaneDetectorEXT CreatePlaneDetectorEXT;
+ PFN_xrDestroyPlaneDetectorEXT DestroyPlaneDetectorEXT;
+ PFN_xrBeginPlaneDetectionEXT BeginPlaneDetectionEXT;
+ PFN_xrGetPlaneDetectionStateEXT GetPlaneDetectionStateEXT;
+ PFN_xrGetPlaneDetectionsEXT GetPlaneDetectionsEXT;
+ PFN_xrGetPlanePolygonBufferEXT GetPlanePolygonBufferEXT;
};
diff --git a/thirdparty/rvo2/rvo2_2d/Agent2d.cc b/thirdparty/rvo2/rvo2_2d/Agent2d.cc
deleted file mode 100644
index 63471d52a0..0000000000
--- a/thirdparty/rvo2/rvo2_2d/Agent2d.cc
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * Agent2d.cpp
- * RVO2 Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-/**
- * @file Agent2d.cpp
- * @brief Defines the Agent2D class.
- */
-
-#include "Agent2d.h"
-
-#include <algorithm>
-#include <cmath>
-#include <limits>
-
-#include "KdTree2d.h"
-#include "Obstacle2d.h"
-
-namespace RVO2D {
-namespace {
-/**
- * @relates Agent2D
- * @brief Solves a one-dimensional linear program on a specified line
- * subject to linear constraints defined by lines and a circular
- * constraint.
- * @param[in] lines Lines defining the linear constraints.
- * @param[in] lineNo The specified line constraint.
- * @param[in] radius The radius of the circular constraint.
- * @param[in] optVelocity The optimization velocity.
- * @param[in] directionOpt True if the direction should be optimized.
- * @param[in, out] result A reference to the result of the linear program.
- * @return True if successful.
- */
-bool linearProgram1(const std::vector<Line> &lines, std::size_t lineNo,
- float radius, const Vector2 &optVelocity, bool directionOpt,
- Vector2 &result) { /* NOLINT(runtime/references) */
- const float dotProduct = lines[lineNo].point * lines[lineNo].direction;
- const float discriminant =
- dotProduct * dotProduct + radius * radius - absSq(lines[lineNo].point);
-
- if (discriminant < 0.0F) {
- /* Max speed circle fully invalidates line lineNo. */
- return false;
- }
-
- const float sqrtDiscriminant = std::sqrt(discriminant);
- float tLeft = -dotProduct - sqrtDiscriminant;
- float tRight = -dotProduct + sqrtDiscriminant;
-
- for (std::size_t i = 0U; i < lineNo; ++i) {
- const float denominator = det(lines[lineNo].direction, lines[i].direction);
- const float numerator =
- det(lines[i].direction, lines[lineNo].point - lines[i].point);
-
- if (std::fabs(denominator) <= RVO2D_EPSILON) {
- /* Lines lineNo and i are (almost) parallel. */
- if (numerator < 0.0F) {
- return false;
- }
-
- continue;
- }
-
- const float t = numerator / denominator;
-
- if (denominator >= 0.0F) {
- /* Line i bounds line lineNo on the right. */
- tRight = std::min(tRight, t);
- } else {
- /* Line i bounds line lineNo on the left. */
- tLeft = std::max(tLeft, t);
- }
-
- if (tLeft > tRight) {
- return false;
- }
- }
-
- if (directionOpt) {
- /* Optimize direction. */
- if (optVelocity * lines[lineNo].direction > 0.0F) {
- /* Take right extreme. */
- result = lines[lineNo].point + tRight * lines[lineNo].direction;
- } else {
- /* Take left extreme. */
- result = lines[lineNo].point + tLeft * lines[lineNo].direction;
- }
- } else {
- /* Optimize closest point. */
- const float t =
- lines[lineNo].direction * (optVelocity - lines[lineNo].point);
-
- if (t < tLeft) {
- result = lines[lineNo].point + tLeft * lines[lineNo].direction;
- } else if (t > tRight) {
- result = lines[lineNo].point + tRight * lines[lineNo].direction;
- } else {
- result = lines[lineNo].point + t * lines[lineNo].direction;
- }
- }
-
- return true;
-}
-
-/**
- * @relates Agent2D
- * @brief Solves a two-dimensional linear program subject to linear
- * constraints defined by lines and a circular constraint.
- * @param[in] lines Lines defining the linear constraints.
- * @param[in] radius The radius of the circular constraint.
- * @param[in] optVelocity The optimization velocity.
- * @param[in] directionOpt True if the direction should be optimized.
- * @param[in, out] result A reference to the result of the linear program.
- * @return The number of the line it fails on, and the number of lines
- * if successful.
- */
-std::size_t linearProgram2(const std::vector<Line> &lines, float radius,
- const Vector2 &optVelocity, bool directionOpt,
- Vector2 &result) { /* NOLINT(runtime/references) */
- if (directionOpt) {
- /* Optimize direction. Note that the optimization velocity is of unit length
- * in this case.
- */
- result = optVelocity * radius;
- } else if (absSq(optVelocity) > radius * radius) {
- /* Optimize closest point and outside circle. */
- result = normalize(optVelocity) * radius;
- } else {
- /* Optimize closest point and inside circle. */
- result = optVelocity;
- }
-
- for (std::size_t i = 0U; i < lines.size(); ++i) {
- if (det(lines[i].direction, lines[i].point - result) > 0.0F) {
- /* Result does not satisfy constraint i. Compute new optimal result. */
- const Vector2 tempResult = result;
-
- if (!linearProgram1(lines, i, radius, optVelocity, directionOpt,
- result)) {
- result = tempResult;
-
- return i;
- }
- }
- }
-
- return lines.size();
-}
-
-/**
- * @relates Agent2D
- * @brief Solves a two-dimensional linear program subject to linear
- * constraints defined by lines and a circular constraint.
- * @param[in] lines Lines defining the linear constraints.
- * @param[in] numObstLines Count of obstacle lines.
- * @param[in] beginLine The line on which the 2-d linear program failed.
- * @param[in] radius The radius of the circular constraint.
- * @param[in, out] result A reference to the result of the linear program.
- */
-void linearProgram3(const std::vector<Line> &lines, std::size_t numObstLines,
- std::size_t beginLine, float radius,
- Vector2 &result) { /* NOLINT(runtime/references) */
- float distance = 0.0F;
-
- for (std::size_t i = beginLine; i < lines.size(); ++i) {
- if (det(lines[i].direction, lines[i].point - result) > distance) {
- /* Result does not satisfy constraint of line i. */
- std::vector<Line> projLines(
- lines.begin(),
- lines.begin() + static_cast<std::ptrdiff_t>(numObstLines));
-
- for (std::size_t j = numObstLines; j < i; ++j) {
- Line line;
-
- const float determinant = det(lines[i].direction, lines[j].direction);
-
- if (std::fabs(determinant) <= RVO2D_EPSILON) {
- /* Line i and line j are parallel. */
- if (lines[i].direction * lines[j].direction > 0.0F) {
- /* Line i and line j point in the same direction. */
- continue;
- }
-
- /* Line i and line j point in opposite direction. */
- line.point = 0.5F * (lines[i].point + lines[j].point);
- } else {
- line.point = lines[i].point + (det(lines[j].direction,
- lines[i].point - lines[j].point) /
- determinant) *
- lines[i].direction;
- }
-
- line.direction = normalize(lines[j].direction - lines[i].direction);
- projLines.push_back(line);
- }
-
- const Vector2 tempResult = result;
-
- if (linearProgram2(
- projLines, radius,
- Vector2(-lines[i].direction.y(), lines[i].direction.x()), true,
- result) < projLines.size()) {
- /* This should in principle not happen. The result is by definition
- * already in the feasible region of this linear program. If it fails,
- * it is due to small floating point error, and the current result is
- * kept. */
- result = tempResult;
- }
-
- distance = det(lines[i].direction, lines[i].point - result);
- }
- }
-}
-} /* namespace */
-
-Agent2D::Agent2D()
- : id_(0U),
- maxNeighbors_(0U),
- maxSpeed_(0.0F),
- neighborDist_(0.0F),
- radius_(0.0F),
- timeHorizon_(0.0F),
- timeHorizonObst_(0.0F) {}
-
-Agent2D::~Agent2D() {}
-
-void Agent2D::computeNeighbors(const KdTree2D *kdTree) {
- obstacleNeighbors_.clear();
- const float range = timeHorizonObst_ * maxSpeed_ + radius_;
- kdTree->computeObstacleNeighbors(this, range * range);
-
- agentNeighbors_.clear();
-
- if (maxNeighbors_ > 0U) {
- float rangeSq = neighborDist_ * neighborDist_;
- kdTree->computeAgentNeighbors(this, rangeSq);
- }
-}
-
-/* Search for the best new velocity. */
-void Agent2D::computeNewVelocity(float timeStep) {
- orcaLines_.clear();
-
- const float invTimeHorizonObst = 1.0F / timeHorizonObst_;
-
- /* Create obstacle ORCA lines. */
- for (std::size_t i = 0U; i < obstacleNeighbors_.size(); ++i) {
- const Obstacle2D *obstacle1 = obstacleNeighbors_[i].second;
- const Obstacle2D *obstacle2 = obstacle1->next_;
-
- const Vector2 relativePosition1 = obstacle1->point_ - position_;
- const Vector2 relativePosition2 = obstacle2->point_ - position_;
-
- /* Check if velocity obstacle of obstacle is already taken care of by
- * previously constructed obstacle ORCA lines. */
- bool alreadyCovered = false;
-
- for (std::size_t j = 0U; j < orcaLines_.size(); ++j) {
- if (det(invTimeHorizonObst * relativePosition1 - orcaLines_[j].point,
- orcaLines_[j].direction) -
- invTimeHorizonObst * radius_ >=
- -RVO2D_EPSILON &&
- det(invTimeHorizonObst * relativePosition2 - orcaLines_[j].point,
- orcaLines_[j].direction) -
- invTimeHorizonObst * radius_ >=
- -RVO2D_EPSILON) {
- alreadyCovered = true;
- break;
- }
- }
-
- if (alreadyCovered) {
- continue;
- }
-
- /* Not yet covered. Check for collisions. */
- const float distSq1 = absSq(relativePosition1);
- const float distSq2 = absSq(relativePosition2);
-
- const float radiusSq = radius_ * radius_;
-
- const Vector2 obstacleVector = obstacle2->point_ - obstacle1->point_;
- const float s =
- (-relativePosition1 * obstacleVector) / absSq(obstacleVector);
- const float distSqLine = absSq(-relativePosition1 - s * obstacleVector);
-
- Line line;
-
- if (s < 0.0F && distSq1 <= radiusSq) {
- /* Collision with left vertex. Ignore if non-convex. */
- if (obstacle1->isConvex_) {
- line.point = Vector2(0.0F, 0.0F);
- line.direction =
- normalize(Vector2(-relativePosition1.y(), relativePosition1.x()));
- orcaLines_.push_back(line);
- }
-
- continue;
- }
-
- if (s > 1.0F && distSq2 <= radiusSq) {
- /* Collision with right vertex. Ignore if non-convex or if it will be
- * taken care of by neighoring obstace */
- if (obstacle2->isConvex_ &&
- det(relativePosition2, obstacle2->direction_) >= 0.0F) {
- line.point = Vector2(0.0F, 0.0F);
- line.direction =
- normalize(Vector2(-relativePosition2.y(), relativePosition2.x()));
- orcaLines_.push_back(line);
- }
-
- continue;
- }
-
- if (s >= 0.0F && s <= 1.0F && distSqLine <= radiusSq) {
- /* Collision with obstacle segment. */
- line.point = Vector2(0.0F, 0.0F);
- line.direction = -obstacle1->direction_;
- orcaLines_.push_back(line);
- continue;
- }
-
- /* No collision. Compute legs. When obliquely viewed, both legs can come
- * from a single vertex. Legs extend cut-off line when nonconvex vertex. */
- Vector2 leftLegDirection;
- Vector2 rightLegDirection;
-
- if (s < 0.0F && distSqLine <= radiusSq) {
- /* Obstacle2D viewed obliquely so that left vertex defines velocity
- * obstacle. */
- if (!obstacle1->isConvex_) {
- /* Ignore obstacle. */
- continue;
- }
-
- obstacle2 = obstacle1;
-
- const float leg1 = std::sqrt(distSq1 - radiusSq);
- leftLegDirection =
- Vector2(
- relativePosition1.x() * leg1 - relativePosition1.y() * radius_,
- relativePosition1.x() * radius_ + relativePosition1.y() * leg1) /
- distSq1;
- rightLegDirection =
- Vector2(
- relativePosition1.x() * leg1 + relativePosition1.y() * radius_,
- -relativePosition1.x() * radius_ + relativePosition1.y() * leg1) /
- distSq1;
- } else if (s > 1.0F && distSqLine <= radiusSq) {
- /* Obstacle2D viewed obliquely so that right vertex defines velocity
- * obstacle. */
- if (!obstacle2->isConvex_) {
- /* Ignore obstacle. */
- continue;
- }
-
- obstacle1 = obstacle2;
-
- const float leg2 = std::sqrt(distSq2 - radiusSq);
- leftLegDirection =
- Vector2(
- relativePosition2.x() * leg2 - relativePosition2.y() * radius_,
- relativePosition2.x() * radius_ + relativePosition2.y() * leg2) /
- distSq2;
- rightLegDirection =
- Vector2(
- relativePosition2.x() * leg2 + relativePosition2.y() * radius_,
- -relativePosition2.x() * radius_ + relativePosition2.y() * leg2) /
- distSq2;
- } else {
- /* Usual situation. */
- if (obstacle1->isConvex_) {
- const float leg1 = std::sqrt(distSq1 - radiusSq);
- leftLegDirection = Vector2(relativePosition1.x() * leg1 -
- relativePosition1.y() * radius_,
- relativePosition1.x() * radius_ +
- relativePosition1.y() * leg1) /
- distSq1;
- } else {
- /* Left vertex non-convex; left leg extends cut-off line. */
- leftLegDirection = -obstacle1->direction_;
- }
-
- if (obstacle2->isConvex_) {
- const float leg2 = std::sqrt(distSq2 - radiusSq);
- rightLegDirection = Vector2(relativePosition2.x() * leg2 +
- relativePosition2.y() * radius_,
- -relativePosition2.x() * radius_ +
- relativePosition2.y() * leg2) /
- distSq2;
- } else {
- /* Right vertex non-convex; right leg extends cut-off line. */
- rightLegDirection = obstacle1->direction_;
- }
- }
-
- /* Legs can never point into neighboring edge when convex vertex, take
- * cutoff-line of neighboring edge instead. If velocity projected on
- * "foreign" leg, no constraint is added. */
- const Obstacle2D *const leftNeighbor = obstacle1->previous_;
-
- bool isLeftLegForeign = false;
- bool isRightLegForeign = false;
-
- if (obstacle1->isConvex_ &&
- det(leftLegDirection, -leftNeighbor->direction_) >= 0.0F) {
- /* Left leg points into obstacle. */
- leftLegDirection = -leftNeighbor->direction_;
- isLeftLegForeign = true;
- }
-
- if (obstacle2->isConvex_ &&
- det(rightLegDirection, obstacle2->direction_) <= 0.0F) {
- /* Right leg points into obstacle. */
- rightLegDirection = obstacle2->direction_;
- isRightLegForeign = true;
- }
-
- /* Compute cut-off centers. */
- const Vector2 leftCutoff =
- invTimeHorizonObst * (obstacle1->point_ - position_);
- const Vector2 rightCutoff =
- invTimeHorizonObst * (obstacle2->point_ - position_);
- const Vector2 cutoffVector = rightCutoff - leftCutoff;
-
- /* Project current velocity on velocity obstacle. */
-
- /* Check if current velocity is projected on cutoff circles. */
- const float t =
- obstacle1 == obstacle2
- ? 0.5F
- : (velocity_ - leftCutoff) * cutoffVector / absSq(cutoffVector);
- const float tLeft = (velocity_ - leftCutoff) * leftLegDirection;
- const float tRight = (velocity_ - rightCutoff) * rightLegDirection;
-
- if ((t < 0.0F && tLeft < 0.0F) ||
- (obstacle1 == obstacle2 && tLeft < 0.0F && tRight < 0.0F)) {
- /* Project on left cut-off circle. */
- const Vector2 unitW = normalize(velocity_ - leftCutoff);
-
- line.direction = Vector2(unitW.y(), -unitW.x());
- line.point = leftCutoff + radius_ * invTimeHorizonObst * unitW;
- orcaLines_.push_back(line);
- continue;
- }
-
- if (t > 1.0F && tRight < 0.0F) {
- /* Project on right cut-off circle. */
- const Vector2 unitW = normalize(velocity_ - rightCutoff);
-
- line.direction = Vector2(unitW.y(), -unitW.x());
- line.point = rightCutoff + radius_ * invTimeHorizonObst * unitW;
- orcaLines_.push_back(line);
- continue;
- }
-
- /* Project on left leg, right leg, or cut-off line, whichever is closest to
- * velocity. */
- const float distSqCutoff =
- (t < 0.0F || t > 1.0F || obstacle1 == obstacle2)
- ? std::numeric_limits<float>::infinity()
- : absSq(velocity_ - (leftCutoff + t * cutoffVector));
- const float distSqLeft =
- tLeft < 0.0F
- ? std::numeric_limits<float>::infinity()
- : absSq(velocity_ - (leftCutoff + tLeft * leftLegDirection));
- const float distSqRight =
- tRight < 0.0F
- ? std::numeric_limits<float>::infinity()
- : absSq(velocity_ - (rightCutoff + tRight * rightLegDirection));
-
- if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight) {
- /* Project on cut-off line. */
- line.direction = -obstacle1->direction_;
- line.point =
- leftCutoff + radius_ * invTimeHorizonObst *
- Vector2(-line.direction.y(), line.direction.x());
- orcaLines_.push_back(line);
- continue;
- }
-
- if (distSqLeft <= distSqRight) {
- /* Project on left leg. */
- if (isLeftLegForeign) {
- continue;
- }
-
- line.direction = leftLegDirection;
- line.point =
- leftCutoff + radius_ * invTimeHorizonObst *
- Vector2(-line.direction.y(), line.direction.x());
- orcaLines_.push_back(line);
- continue;
- }
-
- /* Project on right leg. */
- if (isRightLegForeign) {
- continue;
- }
-
- line.direction = -rightLegDirection;
- line.point =
- rightCutoff + radius_ * invTimeHorizonObst *
- Vector2(-line.direction.y(), line.direction.x());
- orcaLines_.push_back(line);
- }
-
- const std::size_t numObstLines = orcaLines_.size();
-
- const float invTimeHorizon = 1.0F / timeHorizon_;
-
- /* Create agent ORCA lines. */
- for (std::size_t i = 0U; i < agentNeighbors_.size(); ++i) {
- const Agent2D *const other = agentNeighbors_[i].second;
-
- const Vector2 relativePosition = other->position_ - position_;
- const Vector2 relativeVelocity = velocity_ - other->velocity_;
- const float distSq = absSq(relativePosition);
- const float combinedRadius = radius_ + other->radius_;
- const float combinedRadiusSq = combinedRadius * combinedRadius;
-
- Line line;
- Vector2 u;
-
- if (distSq > combinedRadiusSq) {
- /* No collision. */
- const Vector2 w = relativeVelocity - invTimeHorizon * relativePosition;
- /* Vector from cutoff center to relative velocity. */
- const float wLengthSq = absSq(w);
-
- const float dotProduct = w * relativePosition;
-
- if (dotProduct < 0.0F &&
- dotProduct * dotProduct > combinedRadiusSq * wLengthSq) {
- /* Project on cut-off circle. */
- const float wLength = std::sqrt(wLengthSq);
- const Vector2 unitW = w / wLength;
-
- line.direction = Vector2(unitW.y(), -unitW.x());
- u = (combinedRadius * invTimeHorizon - wLength) * unitW;
- } else {
- /* Project on legs. */
- const float leg = std::sqrt(distSq - combinedRadiusSq);
-
- if (det(relativePosition, w) > 0.0F) {
- /* Project on left leg. */
- line.direction = Vector2(relativePosition.x() * leg -
- relativePosition.y() * combinedRadius,
- relativePosition.x() * combinedRadius +
- relativePosition.y() * leg) /
- distSq;
- } else {
- /* Project on right leg. */
- line.direction = -Vector2(relativePosition.x() * leg +
- relativePosition.y() * combinedRadius,
- -relativePosition.x() * combinedRadius +
- relativePosition.y() * leg) /
- distSq;
- }
-
- u = (relativeVelocity * line.direction) * line.direction -
- relativeVelocity;
- }
- } else {
- /* Collision. Project on cut-off circle of time timeStep. */
- const float invTimeStep = 1.0F / timeStep;
-
- /* Vector from cutoff center to relative velocity. */
- const Vector2 w = relativeVelocity - invTimeStep * relativePosition;
-
- const float wLength = abs(w);
- const Vector2 unitW = w / wLength;
-
- line.direction = Vector2(unitW.y(), -unitW.x());
- u = (combinedRadius * invTimeStep - wLength) * unitW;
- }
-
- line.point = velocity_ + 0.5F * u;
- orcaLines_.push_back(line);
- }
-
- const std::size_t lineFail =
- linearProgram2(orcaLines_, maxSpeed_, prefVelocity_, false, newVelocity_);
-
- if (lineFail < orcaLines_.size()) {
- linearProgram3(orcaLines_, numObstLines, lineFail, maxSpeed_, newVelocity_);
- }
-}
-
-void Agent2D::insertAgentNeighbor(const Agent2D *agent, float &rangeSq) {
- // no point processing same agent
- if (this == agent) {
- return;
- }
- // ignore other agent if layers/mask bitmasks have no matching bit
- if ((avoidance_mask_ & agent->avoidance_layers_) == 0) {
- return;
- }
- // ignore other agent if this agent is below or above
- if ((elevation_ > agent->elevation_ + agent->height_) || (elevation_ + height_ < agent->elevation_)) {
- return;
- }
-
- if (avoidance_priority_ > agent->avoidance_priority_) {
- return;
- }
- const float distSq = absSq(position_ - agent->position_);
-
- if (distSq < rangeSq) {
- if (agentNeighbors_.size() < maxNeighbors_) {
- agentNeighbors_.push_back(std::make_pair(distSq, agent));
- }
-
- std::size_t i = agentNeighbors_.size() - 1U;
-
- while (i != 0U && distSq < agentNeighbors_[i - 1U].first) {
- agentNeighbors_[i] = agentNeighbors_[i - 1U];
- --i;
- }
-
- agentNeighbors_[i] = std::make_pair(distSq, agent);
-
- if (agentNeighbors_.size() == maxNeighbors_) {
- rangeSq = agentNeighbors_.back().first;
- }
- }
-}
-
-void Agent2D::insertObstacleNeighbor(const Obstacle2D *obstacle, float rangeSq) {
- const Obstacle2D *const nextObstacle = obstacle->next_;
-
- float distSq = 0.0F;
- const float r = ((position_ - obstacle->point_) *
- (nextObstacle->point_ - obstacle->point_)) /
- absSq(nextObstacle->point_ - obstacle->point_);
-
- if (r < 0.0F) {
- distSq = absSq(position_ - obstacle->point_);
- } else if (r > 1.0F) {
- distSq = absSq(position_ - nextObstacle->point_);
- } else {
- distSq = absSq(position_ - (obstacle->point_ +
- r * (nextObstacle->point_ - obstacle->point_)));
- }
-
- if (distSq < rangeSq) {
- obstacleNeighbors_.push_back(std::make_pair(distSq, obstacle));
-
- std::size_t i = obstacleNeighbors_.size() - 1U;
-
- while (i != 0U && distSq < obstacleNeighbors_[i - 1U].first) {
- obstacleNeighbors_[i] = obstacleNeighbors_[i - 1U];
- --i;
- }
-
- obstacleNeighbors_[i] = std::make_pair(distSq, obstacle);
- }
-}
-
-void Agent2D::update(float timeStep) {
- velocity_ = newVelocity_;
- position_ += velocity_ * timeStep;
-}
-} /* namespace RVO2D */
diff --git a/thirdparty/rvo2/rvo2_2d/Agent2d.cpp b/thirdparty/rvo2/rvo2_2d/Agent2d.cpp
new file mode 100644
index 0000000000..3ff95a4922
--- /dev/null
+++ b/thirdparty/rvo2/rvo2_2d/Agent2d.cpp
@@ -0,0 +1,594 @@
+/*
+ * Agent2d.cpp
+ * RVO2 Library
+ *
+ * Copyright 2008 University of North Carolina at Chapel Hill
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to <geom@cs.unc.edu>.
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ * <http://gamma.cs.unc.edu/RVO2/>
+ */
+
+#include "Agent2d.h"
+
+#include "KdTree2d.h"
+#include "Obstacle2d.h"
+
+namespace RVO2D {
+ Agent2D::Agent2D() : maxNeighbors_(0), maxSpeed_(0.0f), neighborDist_(0.0f), radius_(0.0f), timeHorizon_(0.0f), timeHorizonObst_(0.0f), id_(0) { }
+
+ void Agent2D::computeNeighbors(RVOSimulator2D *sim_)
+ {
+ obstacleNeighbors_.clear();
+ float rangeSq = sqr(timeHorizonObst_ * maxSpeed_ + radius_);
+ sim_->kdTree_->computeObstacleNeighbors(this, rangeSq);
+
+ agentNeighbors_.clear();
+
+ if (maxNeighbors_ > 0) {
+ rangeSq = sqr(neighborDist_);
+ sim_->kdTree_->computeAgentNeighbors(this, rangeSq);
+ }
+ }
+
+ /* Search for the best new velocity. */
+ void Agent2D::computeNewVelocity(RVOSimulator2D *sim_)
+ {
+ orcaLines_.clear();
+
+ const float invTimeHorizonObst = 1.0f / timeHorizonObst_;
+
+ /* Create obstacle ORCA lines. */
+ for (size_t i = 0; i < obstacleNeighbors_.size(); ++i) {
+
+ const Obstacle2D *obstacle1 = obstacleNeighbors_[i].second;
+ const Obstacle2D *obstacle2 = obstacle1->nextObstacle_;
+
+ const Vector2 relativePosition1 = obstacle1->point_ - position_;
+ const Vector2 relativePosition2 = obstacle2->point_ - position_;
+
+ /*
+ * Check if velocity obstacle of obstacle is already taken care of by
+ * previously constructed obstacle ORCA lines.
+ */
+ bool alreadyCovered = false;
+
+ for (size_t j = 0; j < orcaLines_.size(); ++j) {
+ if (det(invTimeHorizonObst * relativePosition1 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVO_EPSILON && det(invTimeHorizonObst * relativePosition2 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVO_EPSILON) {
+ alreadyCovered = true;
+ break;
+ }
+ }
+
+ if (alreadyCovered) {
+ continue;
+ }
+
+ /* Not yet covered. Check for collisions. */
+
+ const float distSq1 = absSq(relativePosition1);
+ const float distSq2 = absSq(relativePosition2);
+
+ const float radiusSq = sqr(radius_);
+
+ const Vector2 obstacleVector = obstacle2->point_ - obstacle1->point_;
+ const float s = (-relativePosition1 * obstacleVector) / absSq(obstacleVector);
+ const float distSqLine = absSq(-relativePosition1 - s * obstacleVector);
+
+ Line line;
+
+ if (s < 0.0f && distSq1 <= radiusSq) {
+ /* Collision with left vertex. Ignore if non-convex. */
+ if (obstacle1->isConvex_) {
+ line.point = Vector2(0.0f, 0.0f);
+ line.direction = normalize(Vector2(-relativePosition1.y(), relativePosition1.x()));
+ orcaLines_.push_back(line);
+ }
+
+ continue;
+ }
+ else if (s > 1.0f && distSq2 <= radiusSq) {
+ /* Collision with right vertex. Ignore if non-convex
+ * or if it will be taken care of by neighoring obstace */
+ if (obstacle2->isConvex_ && det(relativePosition2, obstacle2->unitDir_) >= 0.0f) {
+ line.point = Vector2(0.0f, 0.0f);
+ line.direction = normalize(Vector2(-relativePosition2.y(), relativePosition2.x()));
+ orcaLines_.push_back(line);
+ }
+
+ continue;
+ }
+ else if (s >= 0.0f && s < 1.0f && distSqLine <= radiusSq) {
+ /* Collision with obstacle segment. */
+ line.point = Vector2(0.0f, 0.0f);
+ line.direction = -obstacle1->unitDir_;
+ orcaLines_.push_back(line);
+ continue;
+ }
+
+ /*
+ * No collision.
+ * Compute legs. When obliquely viewed, both legs can come from a single
+ * vertex. Legs extend cut-off line when nonconvex vertex.
+ */
+
+ Vector2 leftLegDirection, rightLegDirection;
+
+ if (s < 0.0f && distSqLine <= radiusSq) {
+ /*
+ * Obstacle viewed obliquely so that left vertex
+ * defines velocity obstacle.
+ */
+ if (!obstacle1->isConvex_) {
+ /* Ignore obstacle. */
+ continue;
+ }
+
+ obstacle2 = obstacle1;
+
+ const float leg1 = std::sqrt(distSq1 - radiusSq);
+ leftLegDirection = Vector2(relativePosition1.x() * leg1 - relativePosition1.y() * radius_, relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
+ rightLegDirection = Vector2(relativePosition1.x() * leg1 + relativePosition1.y() * radius_, -relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
+ }
+ else if (s > 1.0f && distSqLine <= radiusSq) {
+ /*
+ * Obstacle viewed obliquely so that
+ * right vertex defines velocity obstacle.
+ */
+ if (!obstacle2->isConvex_) {
+ /* Ignore obstacle. */
+ continue;
+ }
+
+ obstacle1 = obstacle2;
+
+ const float leg2 = std::sqrt(distSq2 - radiusSq);
+ leftLegDirection = Vector2(relativePosition2.x() * leg2 - relativePosition2.y() * radius_, relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
+ rightLegDirection = Vector2(relativePosition2.x() * leg2 + relativePosition2.y() * radius_, -relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
+ }
+ else {
+ /* Usual situation. */
+ if (obstacle1->isConvex_) {
+ const float leg1 = std::sqrt(distSq1 - radiusSq);
+ leftLegDirection = Vector2(relativePosition1.x() * leg1 - relativePosition1.y() * radius_, relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
+ }
+ else {
+ /* Left vertex non-convex; left leg extends cut-off line. */
+ leftLegDirection = -obstacle1->unitDir_;
+ }
+
+ if (obstacle2->isConvex_) {
+ const float leg2 = std::sqrt(distSq2 - radiusSq);
+ rightLegDirection = Vector2(relativePosition2.x() * leg2 + relativePosition2.y() * radius_, -relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
+ }
+ else {
+ /* Right vertex non-convex; right leg extends cut-off line. */
+ rightLegDirection = obstacle1->unitDir_;
+ }
+ }
+
+ /*
+ * Legs can never point into neighboring edge when convex vertex,
+ * take cutoff-line of neighboring edge instead. If velocity projected on
+ * "foreign" leg, no constraint is added.
+ */
+
+ const Obstacle2D *const leftNeighbor = obstacle1->prevObstacle_;
+
+ bool isLeftLegForeign = false;
+ bool isRightLegForeign = false;
+
+ if (obstacle1->isConvex_ && det(leftLegDirection, -leftNeighbor->unitDir_) >= 0.0f) {
+ /* Left leg points into obstacle. */
+ leftLegDirection = -leftNeighbor->unitDir_;
+ isLeftLegForeign = true;
+ }
+
+ if (obstacle2->isConvex_ && det(rightLegDirection, obstacle2->unitDir_) <= 0.0f) {
+ /* Right leg points into obstacle. */
+ rightLegDirection = obstacle2->unitDir_;
+ isRightLegForeign = true;
+ }
+
+ /* Compute cut-off centers. */
+ const Vector2 leftCutoff = invTimeHorizonObst * (obstacle1->point_ - position_);
+ const Vector2 rightCutoff = invTimeHorizonObst * (obstacle2->point_ - position_);
+ const Vector2 cutoffVec = rightCutoff - leftCutoff;
+
+ /* Project current velocity on velocity obstacle. */
+
+ /* Check if current velocity is projected on cutoff circles. */
+ const float t = (obstacle1 == obstacle2 ? 0.5f : ((velocity_ - leftCutoff) * cutoffVec) / absSq(cutoffVec));
+ const float tLeft = ((velocity_ - leftCutoff) * leftLegDirection);
+ const float tRight = ((velocity_ - rightCutoff) * rightLegDirection);
+
+ if ((t < 0.0f && tLeft < 0.0f) || (obstacle1 == obstacle2 && tLeft < 0.0f && tRight < 0.0f)) {
+ /* Project on left cut-off circle. */
+ const Vector2 unitW = normalize(velocity_ - leftCutoff);
+
+ line.direction = Vector2(unitW.y(), -unitW.x());
+ line.point = leftCutoff + radius_ * invTimeHorizonObst * unitW;
+ orcaLines_.push_back(line);
+ continue;
+ }
+ else if (t > 1.0f && tRight < 0.0f) {
+ /* Project on right cut-off circle. */
+ const Vector2 unitW = normalize(velocity_ - rightCutoff);
+
+ line.direction = Vector2(unitW.y(), -unitW.x());
+ line.point = rightCutoff + radius_ * invTimeHorizonObst * unitW;
+ orcaLines_.push_back(line);
+ continue;
+ }
+
+ /*
+ * Project on left leg, right leg, or cut-off line, whichever is closest
+ * to velocity.
+ */
+ const float distSqCutoff = ((t < 0.0f || t > 1.0f || obstacle1 == obstacle2) ? std::numeric_limits<float>::infinity() : absSq(velocity_ - (leftCutoff + t * cutoffVec)));
+ const float distSqLeft = ((tLeft < 0.0f) ? std::numeric_limits<float>::infinity() : absSq(velocity_ - (leftCutoff + tLeft * leftLegDirection)));
+ const float distSqRight = ((tRight < 0.0f) ? std::numeric_limits<float>::infinity() : absSq(velocity_ - (rightCutoff + tRight * rightLegDirection)));
+
+ if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight) {
+ /* Project on cut-off line. */
+ line.direction = -obstacle1->unitDir_;
+ line.point = leftCutoff + radius_ * invTimeHorizonObst * Vector2(-line.direction.y(), line.direction.x());
+ orcaLines_.push_back(line);
+ continue;
+ }
+ else if (distSqLeft <= distSqRight) {
+ /* Project on left leg. */
+ if (isLeftLegForeign) {
+ continue;
+ }
+
+ line.direction = leftLegDirection;
+ line.point = leftCutoff + radius_ * invTimeHorizonObst * Vector2(-line.direction.y(), line.direction.x());
+ orcaLines_.push_back(line);
+ continue;
+ }
+ else {
+ /* Project on right leg. */
+ if (isRightLegForeign) {
+ continue;
+ }
+
+ line.direction = -rightLegDirection;
+ line.point = rightCutoff + radius_ * invTimeHorizonObst * Vector2(-line.direction.y(), line.direction.x());
+ orcaLines_.push_back(line);
+ continue;
+ }
+ }
+
+ const size_t numObstLines = orcaLines_.size();
+
+ const float invTimeHorizon = 1.0f / timeHorizon_;
+
+ /* Create agent ORCA lines. */
+ for (size_t i = 0; i < agentNeighbors_.size(); ++i) {
+ const Agent2D *const other = agentNeighbors_[i].second;
+
+ //const float timeHorizon_mod = (avoidance_priority_ - other->avoidance_priority_ + 1.0f) * 0.5f;
+ //const float invTimeHorizon = (1.0f / timeHorizon_) * timeHorizon_mod;
+
+ const Vector2 relativePosition = other->position_ - position_;
+ const Vector2 relativeVelocity = velocity_ - other->velocity_;
+ const float distSq = absSq(relativePosition);
+ const float combinedRadius = radius_ + other->radius_;
+ const float combinedRadiusSq = sqr(combinedRadius);
+
+ Line line;
+ Vector2 u;
+
+ if (distSq > combinedRadiusSq) {
+ /* No collision. */
+ const Vector2 w = relativeVelocity - invTimeHorizon * relativePosition;
+ /* Vector from cutoff center to relative velocity. */
+ const float wLengthSq = absSq(w);
+
+ const float dotProduct1 = w * relativePosition;
+
+ if (dotProduct1 < 0.0f && sqr(dotProduct1) > combinedRadiusSq * wLengthSq) {
+ /* Project on cut-off circle. */
+ const float wLength = std::sqrt(wLengthSq);
+ const Vector2 unitW = w / wLength;
+
+ line.direction = Vector2(unitW.y(), -unitW.x());
+ u = (combinedRadius * invTimeHorizon - wLength) * unitW;
+ }
+ else {
+ /* Project on legs. */
+ const float leg = std::sqrt(distSq - combinedRadiusSq);
+
+ if (det(relativePosition, w) > 0.0f) {
+ /* Project on left leg. */
+ line.direction = Vector2(relativePosition.x() * leg - relativePosition.y() * combinedRadius, relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
+ }
+ else {
+ /* Project on right leg. */
+ line.direction = -Vector2(relativePosition.x() * leg + relativePosition.y() * combinedRadius, -relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
+ }
+
+ const float dotProduct2 = relativeVelocity * line.direction;
+
+ u = dotProduct2 * line.direction - relativeVelocity;
+ }
+ }
+ else {
+ /* Collision. Project on cut-off circle of time timeStep. */
+ const float invTimeStep = 1.0f / sim_->timeStep_;
+
+ /* Vector from cutoff center to relative velocity. */
+ const Vector2 w = relativeVelocity - invTimeStep * relativePosition;
+
+ const float wLength = abs(w);
+ const Vector2 unitW = w / wLength;
+
+ line.direction = Vector2(unitW.y(), -unitW.x());
+ u = (combinedRadius * invTimeStep - wLength) * unitW;
+ }
+
+ line.point = velocity_ + 0.5f * u;
+ orcaLines_.push_back(line);
+ }
+
+ size_t lineFail = linearProgram2(orcaLines_, maxSpeed_, prefVelocity_, false, newVelocity_);
+
+ if (lineFail < orcaLines_.size()) {
+ linearProgram3(orcaLines_, numObstLines, lineFail, maxSpeed_, newVelocity_);
+ }
+ }
+
+ void Agent2D::insertAgentNeighbor(const Agent2D *agent, float &rangeSq)
+ {
+ // no point processing same agent
+ if (this == agent) {
+ return;
+ }
+ // ignore other agent if layers/mask bitmasks have no matching bit
+ if ((avoidance_mask_ & agent->avoidance_layers_) == 0) {
+ return;
+ }
+ // ignore other agent if this agent is below or above
+ if ((elevation_ > agent->elevation_ + agent->height_) || (elevation_ + height_ < agent->elevation_)) {
+ return;
+ }
+
+ if (avoidance_priority_ > agent->avoidance_priority_) {
+ return;
+ }
+
+ const float distSq = absSq(position_ - agent->position_);
+
+ if (distSq < rangeSq) {
+ if (agentNeighbors_.size() < maxNeighbors_) {
+ agentNeighbors_.push_back(std::make_pair(distSq, agent));
+ }
+
+ size_t i = agentNeighbors_.size() - 1;
+
+ while (i != 0 && distSq < agentNeighbors_[i - 1].first) {
+ agentNeighbors_[i] = agentNeighbors_[i - 1];
+ --i;
+ }
+
+ agentNeighbors_[i] = std::make_pair(distSq, agent);
+
+ if (agentNeighbors_.size() == maxNeighbors_) {
+ rangeSq = agentNeighbors_.back().first;
+ }
+ }
+ }
+
+ void Agent2D::insertObstacleNeighbor(const Obstacle2D *obstacle, float rangeSq)
+ {
+ const Obstacle2D *const nextObstacle = obstacle->nextObstacle_;
+
+ // ignore obstacle if no matching layer/mask
+ if ((avoidance_mask_ & nextObstacle->avoidance_layers_) == 0) {
+ return;
+ }
+ // ignore obstacle if below or above
+ if ((elevation_ > obstacle->elevation_ + obstacle->height_) || (elevation_ + height_ < obstacle->elevation_)) {
+ return;
+ }
+
+ const float distSq = distSqPointLineSegment(obstacle->point_, nextObstacle->point_, position_);
+
+ if (distSq < rangeSq) {
+ obstacleNeighbors_.push_back(std::make_pair(distSq, obstacle));
+
+ size_t i = obstacleNeighbors_.size() - 1;
+
+ while (i != 0 && distSq < obstacleNeighbors_[i - 1].first) {
+ obstacleNeighbors_[i] = obstacleNeighbors_[i - 1];
+ --i;
+ }
+
+ obstacleNeighbors_[i] = std::make_pair(distSq, obstacle);
+ }
+ //}
+ }
+
+ void Agent2D::update(RVOSimulator2D *sim_)
+ {
+ velocity_ = newVelocity_;
+ position_ += velocity_ * sim_->timeStep_;
+ }
+
+ bool linearProgram1(const std::vector<Line> &lines, size_t lineNo, float radius, const Vector2 &optVelocity, bool directionOpt, Vector2 &result)
+ {
+ const float dotProduct = lines[lineNo].point * lines[lineNo].direction;
+ const float discriminant = sqr(dotProduct) + sqr(radius) - absSq(lines[lineNo].point);
+
+ if (discriminant < 0.0f) {
+ /* Max speed circle fully invalidates line lineNo. */
+ return false;
+ }
+
+ const float sqrtDiscriminant = std::sqrt(discriminant);
+ float tLeft = -dotProduct - sqrtDiscriminant;
+ float tRight = -dotProduct + sqrtDiscriminant;
+
+ for (size_t i = 0; i < lineNo; ++i) {
+ const float denominator = det(lines[lineNo].direction, lines[i].direction);
+ const float numerator = det(lines[i].direction, lines[lineNo].point - lines[i].point);
+
+ if (std::fabs(denominator) <= RVO_EPSILON) {
+ /* Lines lineNo and i are (almost) parallel. */
+ if (numerator < 0.0f) {
+ return false;
+ }
+ else {
+ continue;
+ }
+ }
+
+ const float t = numerator / denominator;
+
+ if (denominator >= 0.0f) {
+ /* Line i bounds line lineNo on the right. */
+ tRight = std::min(tRight, t);
+ }
+ else {
+ /* Line i bounds line lineNo on the left. */
+ tLeft = std::max(tLeft, t);
+ }
+
+ if (tLeft > tRight) {
+ return false;
+ }
+ }
+
+ if (directionOpt) {
+ /* Optimize direction. */
+ if (optVelocity * lines[lineNo].direction > 0.0f) {
+ /* Take right extreme. */
+ result = lines[lineNo].point + tRight * lines[lineNo].direction;
+ }
+ else {
+ /* Take left extreme. */
+ result = lines[lineNo].point + tLeft * lines[lineNo].direction;
+ }
+ }
+ else {
+ /* Optimize closest point. */
+ const float t = lines[lineNo].direction * (optVelocity - lines[lineNo].point);
+
+ if (t < tLeft) {
+ result = lines[lineNo].point + tLeft * lines[lineNo].direction;
+ }
+ else if (t > tRight) {
+ result = lines[lineNo].point + tRight * lines[lineNo].direction;
+ }
+ else {
+ result = lines[lineNo].point + t * lines[lineNo].direction;
+ }
+ }
+
+ return true;
+ }
+
+ size_t linearProgram2(const std::vector<Line> &lines, float radius, const Vector2 &optVelocity, bool directionOpt, Vector2 &result)
+ {
+ if (directionOpt) {
+ /*
+ * Optimize direction. Note that the optimization velocity is of unit
+ * length in this case.
+ */
+ result = optVelocity * radius;
+ }
+ else if (absSq(optVelocity) > sqr(radius)) {
+ /* Optimize closest point and outside circle. */
+ result = normalize(optVelocity) * radius;
+ }
+ else {
+ /* Optimize closest point and inside circle. */
+ result = optVelocity;
+ }
+
+ for (size_t i = 0; i < lines.size(); ++i) {
+ if (det(lines[i].direction, lines[i].point - result) > 0.0f) {
+ /* Result does not satisfy constraint i. Compute new optimal result. */
+ const Vector2 tempResult = result;
+
+ if (!linearProgram1(lines, i, radius, optVelocity, directionOpt, result)) {
+ result = tempResult;
+ return i;
+ }
+ }
+ }
+
+ return lines.size();
+ }
+
+ void linearProgram3(const std::vector<Line> &lines, size_t numObstLines, size_t beginLine, float radius, Vector2 &result)
+ {
+ float distance = 0.0f;
+
+ for (size_t i = beginLine; i < lines.size(); ++i) {
+ if (det(lines[i].direction, lines[i].point - result) > distance) {
+ /* Result does not satisfy constraint of line i. */
+ std::vector<Line> projLines(lines.begin(), lines.begin() + static_cast<ptrdiff_t>(numObstLines));
+
+ for (size_t j = numObstLines; j < i; ++j) {
+ Line line;
+
+ float determinant = det(lines[i].direction, lines[j].direction);
+
+ if (std::fabs(determinant) <= RVO_EPSILON) {
+ /* Line i and line j are parallel. */
+ if (lines[i].direction * lines[j].direction > 0.0f) {
+ /* Line i and line j point in the same direction. */
+ continue;
+ }
+ else {
+ /* Line i and line j point in opposite direction. */
+ line.point = 0.5f * (lines[i].point + lines[j].point);
+ }
+ }
+ else {
+ line.point = lines[i].point + (det(lines[j].direction, lines[i].point - lines[j].point) / determinant) * lines[i].direction;
+ }
+
+ line.direction = normalize(lines[j].direction - lines[i].direction);
+ projLines.push_back(line);
+ }
+
+ const Vector2 tempResult = result;
+
+ if (linearProgram2(projLines, radius, Vector2(-lines[i].direction.y(), lines[i].direction.x()), true, result) < projLines.size()) {
+ /* This should in principle not happen. The result is by definition
+ * already in the feasible region of this linear program. If it fails,
+ * it is due to small floating point error, and the current result is
+ * kept.
+ */
+ result = tempResult;
+ }
+
+ distance = det(lines[i].direction, lines[i].point - result);
+ }
+ }
+ }
+}
diff --git a/thirdparty/rvo2/rvo2_2d/Agent2d.h b/thirdparty/rvo2/rvo2_2d/Agent2d.h
index f5b9ed8ebc..c666c2de7b 100644
--- a/thirdparty/rvo2/rvo2_2d/Agent2d.h
+++ b/thirdparty/rvo2/rvo2_2d/Agent2d.h
@@ -2,14 +2,13 @@
* Agent2d.h
* RVO2 Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,110 +27,134 @@
* Chapel Hill, N.C. 27599-3175
* United States of America
*
- * <https://gamma.cs.unc.edu/RVO2/>
+ * <http://gamma.cs.unc.edu/RVO2/>
*/
#ifndef RVO2D_AGENT_H_
#define RVO2D_AGENT_H_
/**
- * @file Agent2d.h
- * @brief Declares the Agent2D class.
+ * \file Agent2d.h
+ * \brief Contains the Agent class.
*/
-#include <cstddef>
-#include <cstdint>
-#include <utility>
-#include <vector>
-
-#include "Line.h"
-#include "Vector2.h"
+#include "Definitions.h"
+#include "RVOSimulator2d.h"
namespace RVO2D {
-class KdTree2D;
-class Obstacle2D;
-
-/**
- * @brief Defines an agent in the simulation.
- */
-class Agent2D {
- public:
- /**
- * @brief Constructs an agent instance.
- */
- Agent2D();
-
- /**
- * @brief Destroys this agent instance.
- */
- ~Agent2D();
-
- /**
- * @brief Computes the neighbors of this agent.
- * @param[in] kdTree A pointer to the k-D trees for agents and static
- * obstacles in the simulation.
- */
- void computeNeighbors(const KdTree2D *kdTree);
-
- /**
- * @brief Computes the new velocity of this agent.
- * @param[in] timeStep The time step of the simulation.
- */
- void computeNewVelocity(float timeStep);
-
- /**
- * @brief Inserts an agent neighbor into the set of neighbors of this
- * agent.
- * @param[in] agent A pointer to the agent to be inserted.
- * @param[in, out] rangeSq The squared range around this agent.
- */
- void insertAgentNeighbor(const Agent2D *agent,
- float &rangeSq); /* NOLINT(runtime/references) */
-
- /**
- * @brief Inserts a static obstacle neighbor into the set of
- * neighbors of this agent.
- * @param[in] obstacle The number of the static obstacle to be inserted.
- * @param[in, out] rangeSq The squared range around this agent.
- */
- void insertObstacleNeighbor(const Obstacle2D *obstacle, float rangeSq);
-
- /**
- * @brief Updates the two-dimensional position and two-dimensional
- * velocity of this agent.
- * @param[in] timeStep The time step of the simulation.
- */
- void update(float timeStep);
-
- /* Not implemented. */
- Agent2D(const Agent2D &other);
-
- /* Not implemented. */
- Agent2D &operator=(const Agent2D &other);
-
- std::vector<std::pair<float, const Agent2D *> > agentNeighbors_;
- std::vector<std::pair<float, const Obstacle2D *> > obstacleNeighbors_;
- std::vector<Line> orcaLines_;
- Vector2 newVelocity_;
- Vector2 position_;
- Vector2 prefVelocity_;
- Vector2 velocity_;
- std::size_t id_;
- std::size_t maxNeighbors_;
- float maxSpeed_;
- float neighborDist_;
- float radius_;
- float timeHorizon_;
- float timeHorizonObst_;
- float height_ = 0.0;
- float elevation_ = 0.0;
- uint32_t avoidance_layers_ = 1;
- uint32_t avoidance_mask_ = 1;
- float avoidance_priority_ = 1.0;
-
- friend class KdTree2D;
- friend class RVOSimulator2D;
-};
-} /* namespace RVO */
+ /**
+ * \brief Defines an agent in the simulation.
+ */
+ class Agent2D {
+ public:
+ /**
+ * \brief Constructs an agent instance.
+ * \param sim The simulator instance.
+ */
+ explicit Agent2D();
+
+ /**
+ * \brief Computes the neighbors of this agent.
+ */
+ void computeNeighbors(RVOSimulator2D *sim_);
+
+ /**
+ * \brief Computes the new velocity of this agent.
+ */
+ void computeNewVelocity(RVOSimulator2D *sim_);
+
+ /**
+ * \brief Inserts an agent neighbor into the set of neighbors of
+ * this agent.
+ * \param agent A pointer to the agent to be inserted.
+ * \param rangeSq The squared range around this agent.
+ */
+ void insertAgentNeighbor(const Agent2D *agent, float &rangeSq);
+
+ /**
+ * \brief Inserts a static obstacle neighbor into the set of neighbors
+ * of this agent.
+ * \param obstacle The number of the static obstacle to be
+ * inserted.
+ * \param rangeSq The squared range around this agent.
+ */
+ void insertObstacleNeighbor(const Obstacle2D *obstacle, float rangeSq);
+
+ /**
+ * \brief Updates the two-dimensional position and two-dimensional
+ * velocity of this agent.
+ */
+ void update(RVOSimulator2D *sim_);
+
+ std::vector<std::pair<float, const Agent2D *> > agentNeighbors_;
+ size_t maxNeighbors_;
+ float maxSpeed_;
+ float neighborDist_;
+ Vector2 newVelocity_;
+ std::vector<std::pair<float, const Obstacle2D *> > obstacleNeighbors_;
+ std::vector<Line> orcaLines_;
+ Vector2 position_;
+ Vector2 prefVelocity_;
+ float radius_;
+ float timeHorizon_;
+ float timeHorizonObst_;
+ Vector2 velocity_;
+ float height_ = 0.0;
+ float elevation_ = 0.0;
+ uint32_t avoidance_layers_ = 1;
+ uint32_t avoidance_mask_ = 1;
+ float avoidance_priority_ = 1.0;
+
+ size_t id_;
+
+ friend class KdTree2D;
+ friend class RVOSimulator2D;
+ };
+
+ /**
+ * \relates Agent
+ * \brief Solves a one-dimensional linear program on a specified line
+ * subject to linear constraints defined by lines and a circular
+ * constraint.
+ * \param lines Lines defining the linear constraints.
+ * \param lineNo The specified line constraint.
+ * \param radius The radius of the circular constraint.
+ * \param optVelocity The optimization velocity.
+ * \param directionOpt True if the direction should be optimized.
+ * \param result A reference to the result of the linear program.
+ * \return True if successful.
+ */
+ bool linearProgram1(const std::vector<Line> &lines, size_t lineNo,
+ float radius, const Vector2 &optVelocity,
+ bool directionOpt, Vector2 &result);
+
+ /**
+ * \relates Agent
+ * \brief Solves a two-dimensional linear program subject to linear
+ * constraints defined by lines and a circular constraint.
+ * \param lines Lines defining the linear constraints.
+ * \param radius The radius of the circular constraint.
+ * \param optVelocity The optimization velocity.
+ * \param directionOpt True if the direction should be optimized.
+ * \param result A reference to the result of the linear program.
+ * \return The number of the line it fails on, and the number of lines if successful.
+ */
+ size_t linearProgram2(const std::vector<Line> &lines, float radius,
+ const Vector2 &optVelocity, bool directionOpt,
+ Vector2 &result);
+
+ /**
+ * \relates Agent
+ * \brief Solves a two-dimensional linear program subject to linear
+ * constraints defined by lines and a circular constraint.
+ * \param lines Lines defining the linear constraints.
+ * \param numObstLines Count of obstacle lines.
+ * \param beginLine The line on which the 2-d linear program failed.
+ * \param radius The radius of the circular constraint.
+ * \param result A reference to the result of the linear program.
+ */
+ void linearProgram3(const std::vector<Line> &lines, size_t numObstLines, size_t beginLine,
+ float radius, Vector2 &result);
+}
#endif /* RVO2D_AGENT_H_ */
diff --git a/thirdparty/rvo2/rvo2_2d/Definitions.h b/thirdparty/rvo2/rvo2_2d/Definitions.h
new file mode 100644
index 0000000000..a5553d8378
--- /dev/null
+++ b/thirdparty/rvo2/rvo2_2d/Definitions.h
@@ -0,0 +1,110 @@
+/*
+ * Definitions.h
+ * RVO2 Library
+ *
+ * Copyright 2008 University of North Carolina at Chapel Hill
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to <geom@cs.unc.edu>.
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ * <http://gamma.cs.unc.edu/RVO2/>
+ */
+
+#ifndef RVO2D_DEFINITIONS_H_
+#define RVO2D_DEFINITIONS_H_
+
+/**
+ * \file Definitions.h
+ * \brief Contains functions and constants used in multiple classes.
+ */
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <vector>
+
+#include "Vector2.h"
+
+/**
+ * \brief A sufficiently small positive number.
+ */
+const float RVO_EPSILON = 0.00001f;
+
+namespace RVO2D {
+ class Agent2D;
+ class Obstacle2D;
+ class RVOSimulator2D;
+
+ /**
+ * \brief Computes the squared distance from a line segment with the
+ * specified endpoints to a specified point.
+ * \param a The first endpoint of the line segment.
+ * \param b The second endpoint of the line segment.
+ * \param c The point to which the squared distance is to
+ * be calculated.
+ * \return The squared distance from the line segment to the point.
+ */
+ inline float distSqPointLineSegment(const Vector2 &a, const Vector2 &b,
+ const Vector2 &c)
+ {
+ const float r = ((c - a) * (b - a)) / absSq(b - a);
+
+ if (r < 0.0f) {
+ return absSq(c - a);
+ }
+ else if (r > 1.0f) {
+ return absSq(c - b);
+ }
+ else {
+ return absSq(c - (a + r * (b - a)));
+ }
+ }
+
+ /**
+ * \brief Computes the signed distance from a line connecting the
+ * specified points to a specified point.
+ * \param a The first point on the line.
+ * \param b The second point on the line.
+ * \param c The point to which the signed distance is to
+ * be calculated.
+ * \return Positive when the point c lies to the left of the line ab.
+ */
+ inline float leftOf(const Vector2 &a, const Vector2 &b, const Vector2 &c)
+ {
+ return det(a - c, b - a);
+ }
+
+ /**
+ * \brief Computes the square of a float.
+ * \param a The float to be squared.
+ * \return The square of the float.
+ */
+ inline float sqr(float a)
+ {
+ return a * a;
+ }
+}
+
+#endif /* RVO2D_DEFINITIONS_H_ */
diff --git a/thirdparty/rvo2/rvo2_2d/KdTree2d.cc b/thirdparty/rvo2/rvo2_2d/KdTree2d.cc
deleted file mode 100644
index 6259a5d661..0000000000
--- a/thirdparty/rvo2/rvo2_2d/KdTree2d.cc
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * KdTree2d.cpp
- * RVO2 Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-/**
- * @file KdTree2d.cpp
- * @brief Defines the KdTree2D class.
- */
-
-#include "KdTree2d.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "Agent2d.h"
-#include "Obstacle2d.h"
-#include "RVOSimulator2d.h"
-#include "Vector2.h"
-
-namespace RVO2D {
-namespace {
-/**
- * @relates KdTree2D
- * @brief The maximum k-D tree node leaf size.
- */
-const std::size_t RVO_MAX_LEAF_SIZE = 10U;
-} /* namespace */
-
-/**
- * @brief Defines an agent k-D tree node.
- */
-class KdTree2D::AgentTreeNode {
- public:
- /**
- * @brief Constructs an agent k-D tree node instance.
- */
- AgentTreeNode();
-
- /**
- * @brief The beginning node number.
- */
- std::size_t begin;
-
- /**
- * @brief The ending node number.
- */
- std::size_t end;
-
- /**
- * @brief The left node number.
- */
- std::size_t left;
-
- /**
- * @brief The right node number.
- */
- std::size_t right;
-
- /**
- * @brief The maximum x-coordinate.
- */
- float maxX;
-
- /**
- * @brief The maximum y-coordinate.
- */
- float maxY;
-
- /**
- * @brief The minimum x-coordinate.
- */
- float minX;
-
- /**
- * @brief The minimum y-coordinate.
- */
- float minY;
-};
-
-KdTree2D::AgentTreeNode::AgentTreeNode()
- : begin(0U),
- end(0U),
- left(0U),
- right(0U),
- maxX(0.0F),
- maxY(0.0F),
- minX(0.0F),
- minY(0.0F) {}
-
-/**
- * @brief Defines an obstacle k-D tree node.
- */
-class KdTree2D::ObstacleTreeNode {
- public:
- /**
- * @brief Constructs an obstacle k-D tree node instance.
- */
- ObstacleTreeNode();
-
- /**
- * @brief Destroys this obstacle k-D tree node instance.
- */
- ~ObstacleTreeNode();
-
- /**
- * @brief The obstacle number.
- */
- const Obstacle2D *obstacle;
-
- /**
- * @brief The left obstacle tree node.
- */
- ObstacleTreeNode *left;
-
- /**
- * @brief The right obstacle tree node.
- */
- ObstacleTreeNode *right;
-
- private:
- /* Not implemented. */
- ObstacleTreeNode(const ObstacleTreeNode &other);
-
- /* Not implemented. */
- ObstacleTreeNode &operator=(const ObstacleTreeNode &other);
-};
-
-KdTree2D::ObstacleTreeNode::ObstacleTreeNode()
- : obstacle(NULL), left(NULL), right(NULL) {}
-
-KdTree2D::ObstacleTreeNode::~ObstacleTreeNode() {}
-
-KdTree2D::KdTree2D(RVOSimulator2D *simulator)
- : obstacleTree_(NULL), simulator_(simulator) {}
-
-KdTree2D::~KdTree2D() { deleteObstacleTree(obstacleTree_); }
-
-void KdTree2D::buildAgentTree(std::vector<Agent2D *> agents) {
- agents_.swap(agents);
-
- if (!agents_.empty()) {
- agentTree_.resize(2 * agents_.size() - 1);
- buildAgentTreeRecursive(0, agents_.size(), 0);
- }
-}
-
-void KdTree2D::buildAgentTreeRecursive(std::size_t begin, std::size_t end,
- std::size_t node) {
- agentTree_[node].begin = begin;
- agentTree_[node].end = end;
- agentTree_[node].minX = agentTree_[node].maxX = agents_[begin]->position_.x();
- agentTree_[node].minY = agentTree_[node].maxY = agents_[begin]->position_.y();
-
- for (std::size_t i = begin + 1U; i < end; ++i) {
- agentTree_[node].maxX =
- std::max(agentTree_[node].maxX, agents_[i]->position_.x());
- agentTree_[node].minX =
- std::min(agentTree_[node].minX, agents_[i]->position_.x());
- agentTree_[node].maxY =
- std::max(agentTree_[node].maxY, agents_[i]->position_.y());
- agentTree_[node].minY =
- std::min(agentTree_[node].minY, agents_[i]->position_.y());
- }
-
- if (end - begin > RVO_MAX_LEAF_SIZE) {
- /* No leaf node. */
- const bool isVertical = agentTree_[node].maxX - agentTree_[node].minX >
- agentTree_[node].maxY - agentTree_[node].minY;
- const float splitValue =
- 0.5F * (isVertical ? agentTree_[node].maxX + agentTree_[node].minX
- : agentTree_[node].maxY + agentTree_[node].minY);
-
- std::size_t left = begin;
- std::size_t right = end;
-
- while (left < right) {
- while (left < right &&
- (isVertical ? agents_[left]->position_.x()
- : agents_[left]->position_.y()) < splitValue) {
- ++left;
- }
-
- while (right > left &&
- (isVertical ? agents_[right - 1U]->position_.x()
- : agents_[right - 1U]->position_.y()) >= splitValue) {
- --right;
- }
-
- if (left < right) {
- std::swap(agents_[left], agents_[right - 1U]);
- ++left;
- --right;
- }
- }
-
- if (left == begin) {
- ++left;
- ++right;
- }
-
- agentTree_[node].left = node + 1U;
- agentTree_[node].right = node + 2U * (left - begin);
-
- buildAgentTreeRecursive(begin, left, agentTree_[node].left);
- buildAgentTreeRecursive(left, end, agentTree_[node].right);
- }
-}
-
-void KdTree2D::buildObstacleTree(std::vector<Obstacle2D *> obstacles) {
- deleteObstacleTree(obstacleTree_);
-
- obstacleTree_ = buildObstacleTreeRecursive(obstacles);
-}
-
-KdTree2D::ObstacleTreeNode *KdTree2D::buildObstacleTreeRecursive(
- const std::vector<Obstacle2D *> &obstacles) {
- if (!obstacles.empty()) {
- ObstacleTreeNode *const node = new ObstacleTreeNode();
-
- std::size_t optimalSplit = 0U;
- std::size_t minLeft = obstacles.size();
- std::size_t minRight = obstacles.size();
-
- for (std::size_t i = 0U; i < obstacles.size(); ++i) {
- std::size_t leftSize = 0U;
- std::size_t rightSize = 0U;
-
- const Obstacle2D *const obstacleI1 = obstacles[i];
- const Obstacle2D *const obstacleI2 = obstacleI1->next_;
-
- /* Compute optimal split node. */
- for (std::size_t j = 0U; j < obstacles.size(); ++j) {
- if (i != j) {
- const Obstacle2D *const obstacleJ1 = obstacles[j];
- const Obstacle2D *const obstacleJ2 = obstacleJ1->next_;
-
- const float j1LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_,
- obstacleJ1->point_);
- const float j2LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_,
- obstacleJ2->point_);
-
- if (j1LeftOfI >= -RVO2D_EPSILON && j2LeftOfI >= -RVO2D_EPSILON) {
- ++leftSize;
- } else if (j1LeftOfI <= RVO2D_EPSILON && j2LeftOfI <= RVO2D_EPSILON) {
- ++rightSize;
- } else {
- ++leftSize;
- ++rightSize;
- }
-
- if (std::make_pair(std::max(leftSize, rightSize),
- std::min(leftSize, rightSize)) >=
- std::make_pair(std::max(minLeft, minRight),
- std::min(minLeft, minRight))) {
- break;
- }
- }
- }
-
- if (std::make_pair(std::max(leftSize, rightSize),
- std::min(leftSize, rightSize)) <
- std::make_pair(std::max(minLeft, minRight),
- std::min(minLeft, minRight))) {
- minLeft = leftSize;
- minRight = rightSize;
- optimalSplit = i;
- }
- }
-
- /* Build split node. */
- std::vector<Obstacle2D *> leftObstacles(minLeft);
- std::vector<Obstacle2D *> rightObstacles(minRight);
-
- std::size_t leftCounter = 0U;
- std::size_t rightCounter = 0U;
- const std::size_t i = optimalSplit;
-
- const Obstacle2D *const obstacleI1 = obstacles[i];
- const Obstacle2D *const obstacleI2 = obstacleI1->next_;
-
- for (std::size_t j = 0U; j < obstacles.size(); ++j) {
- if (i != j) {
- Obstacle2D *const obstacleJ1 = obstacles[j];
- Obstacle2D *const obstacleJ2 = obstacleJ1->next_;
-
- const float j1LeftOfI =
- leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ1->point_);
- const float j2LeftOfI =
- leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ2->point_);
-
- if (j1LeftOfI >= -RVO2D_EPSILON && j2LeftOfI >= -RVO2D_EPSILON) {
- leftObstacles[leftCounter++] = obstacles[j];
- } else if (j1LeftOfI <= RVO2D_EPSILON && j2LeftOfI <= RVO2D_EPSILON) {
- rightObstacles[rightCounter++] = obstacles[j];
- } else {
- /* Split obstacle j. */
- const float t = det(obstacleI2->point_ - obstacleI1->point_,
- obstacleJ1->point_ - obstacleI1->point_) /
- det(obstacleI2->point_ - obstacleI1->point_,
- obstacleJ1->point_ - obstacleJ2->point_);
-
- const Vector2 splitPoint =
- obstacleJ1->point_ +
- t * (obstacleJ2->point_ - obstacleJ1->point_);
-
- Obstacle2D *const newObstacle = new Obstacle2D();
- newObstacle->direction_ = obstacleJ1->direction_;
- newObstacle->point_ = splitPoint;
- newObstacle->next_ = obstacleJ2;
- newObstacle->previous_ = obstacleJ1;
- newObstacle->id_ = simulator_->obstacles_.size();
- newObstacle->isConvex_ = true;
- simulator_->obstacles_.push_back(newObstacle);
-
- obstacleJ1->next_ = newObstacle;
- obstacleJ2->previous_ = newObstacle;
-
- if (j1LeftOfI > 0.0F) {
- leftObstacles[leftCounter++] = obstacleJ1;
- rightObstacles[rightCounter++] = newObstacle;
- } else {
- rightObstacles[rightCounter++] = obstacleJ1;
- leftObstacles[leftCounter++] = newObstacle;
- }
- }
- }
- }
-
- node->obstacle = obstacleI1;
- node->left = buildObstacleTreeRecursive(leftObstacles);
- node->right = buildObstacleTreeRecursive(rightObstacles);
-
- return node;
- }
-
- return NULL;
-}
-
-void KdTree2D::computeAgentNeighbors(Agent2D *agent, float &rangeSq) const {
- queryAgentTreeRecursive(agent, rangeSq, 0U);
-}
-
-void KdTree2D::computeObstacleNeighbors(Agent2D *agent, float rangeSq) const {
- queryObstacleTreeRecursive(agent, rangeSq, obstacleTree_);
-}
-
-void KdTree2D::deleteObstacleTree(ObstacleTreeNode *node) {
- if (node != NULL) {
- deleteObstacleTree(node->left);
- deleteObstacleTree(node->right);
- delete node;
- }
-}
-
-void KdTree2D::queryAgentTreeRecursive(Agent2D *agent, float &rangeSq,
- std::size_t node) const {
- if (agentTree_[node].end - agentTree_[node].begin <= RVO_MAX_LEAF_SIZE) {
- for (std::size_t i = agentTree_[node].begin; i < agentTree_[node].end;
- ++i) {
- agent->insertAgentNeighbor(agents_[i], rangeSq);
- }
- } else {
- const float distLeftMinX = std::max(
- 0.0F, agentTree_[agentTree_[node].left].minX - agent->position_.x());
- const float distLeftMaxX = std::max(
- 0.0F, agent->position_.x() - agentTree_[agentTree_[node].left].maxX);
- const float distLeftMinY = std::max(
- 0.0F, agentTree_[agentTree_[node].left].minY - agent->position_.y());
- const float distLeftMaxY = std::max(
- 0.0F, agent->position_.y() - agentTree_[agentTree_[node].left].maxY);
-
- const float distSqLeft =
- distLeftMinX * distLeftMinX + distLeftMaxX * distLeftMaxX +
- distLeftMinY * distLeftMinY + distLeftMaxY * distLeftMaxY;
-
- const float distRightMinX = std::max(
- 0.0F, agentTree_[agentTree_[node].right].minX - agent->position_.x());
- const float distRightMaxX = std::max(
- 0.0F, agent->position_.x() - agentTree_[agentTree_[node].right].maxX);
- const float distRightMinY = std::max(
- 0.0F, agentTree_[agentTree_[node].right].minY - agent->position_.y());
- const float distRightMaxY = std::max(
- 0.0F, agent->position_.y() - agentTree_[agentTree_[node].right].maxY);
-
- const float distSqRight =
- distRightMinX * distRightMinX + distRightMaxX * distRightMaxX +
- distRightMinY * distRightMinY + distRightMaxY * distRightMaxY;
-
- if (distSqLeft < distSqRight) {
- if (distSqLeft < rangeSq) {
- queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);
-
- if (distSqRight < rangeSq) {
- queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);
- }
- }
- } else if (distSqRight < rangeSq) {
- queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);
-
- if (distSqLeft < rangeSq) {
- queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);
- }
- }
- }
-}
-
-void KdTree2D::queryObstacleTreeRecursive(Agent2D *agent, float rangeSq,
- const ObstacleTreeNode *node) const {
- if (node != NULL) {
- const Obstacle2D *const obstacle1 = node->obstacle;
- const Obstacle2D *const obstacle2 = obstacle1->next_;
-
- const float agentLeftOfLine =
- leftOf(obstacle1->point_, obstacle2->point_, agent->position_);
-
- queryObstacleTreeRecursive(
- agent, rangeSq, agentLeftOfLine >= 0.0F ? node->left : node->right);
-
- const float distSqLine = agentLeftOfLine * agentLeftOfLine /
- absSq(obstacle2->point_ - obstacle1->point_);
-
- if (distSqLine < rangeSq) {
- if (agentLeftOfLine < 0.0F) {
- /* Try obstacle at this node only if agent is on right side of obstacle
- * and can see obstacle. */
- agent->insertObstacleNeighbor(node->obstacle, rangeSq);
- }
-
- /* Try other side of line. */
- queryObstacleTreeRecursive(
- agent, rangeSq, agentLeftOfLine >= 0.0F ? node->right : node->left);
- }
- }
-}
-
-bool KdTree2D::queryVisibility(const Vector2 &vector1, const Vector2 &vector2,
- float radius) const {
- return queryVisibilityRecursive(vector1, vector2, radius, obstacleTree_);
-}
-
-bool KdTree2D::queryVisibilityRecursive(const Vector2 &vector1,
- const Vector2 &vector2, float radius,
- const ObstacleTreeNode *node) const {
- if (node != NULL) {
- const Obstacle2D *const obstacle1 = node->obstacle;
- const Obstacle2D *const obstacle2 = obstacle1->next_;
-
- const float q1LeftOfI =
- leftOf(obstacle1->point_, obstacle2->point_, vector1);
- const float q2LeftOfI =
- leftOf(obstacle1->point_, obstacle2->point_, vector2);
- const float invLengthI =
- 1.0F / absSq(obstacle2->point_ - obstacle1->point_);
-
- if (q1LeftOfI >= 0.0F && q2LeftOfI >= 0.0F) {
- return queryVisibilityRecursive(vector1, vector2, radius, node->left) &&
- ((q1LeftOfI * q1LeftOfI * invLengthI >= radius * radius &&
- q2LeftOfI * q2LeftOfI * invLengthI >= radius * radius) ||
- queryVisibilityRecursive(vector1, vector2, radius, node->right));
- }
-
- if (q1LeftOfI <= 0.0F && q2LeftOfI <= 0.0F) {
- return queryVisibilityRecursive(vector1, vector2, radius, node->right) &&
- ((q1LeftOfI * q1LeftOfI * invLengthI >= radius * radius &&
- q2LeftOfI * q2LeftOfI * invLengthI >= radius * radius) ||
- queryVisibilityRecursive(vector1, vector2, radius, node->left));
- }
-
- if (q1LeftOfI >= 0.0F && q2LeftOfI <= 0.0F) {
- /* One can see through obstacle from left to right. */
- return queryVisibilityRecursive(vector1, vector2, radius, node->left) &&
- queryVisibilityRecursive(vector1, vector2, radius, node->right);
- }
-
- const float point1LeftOfQ = leftOf(vector1, vector2, obstacle1->point_);
- const float point2LeftOfQ = leftOf(vector1, vector2, obstacle2->point_);
- const float invLengthQ = 1.0F / absSq(vector2 - vector1);
-
- return point1LeftOfQ * point2LeftOfQ >= 0.0F &&
- point1LeftOfQ * point1LeftOfQ * invLengthQ > radius * radius &&
- point2LeftOfQ * point2LeftOfQ * invLengthQ > radius * radius &&
- queryVisibilityRecursive(vector1, vector2, radius, node->left) &&
- queryVisibilityRecursive(vector1, vector2, radius, node->right);
- }
-
- return true;
-}
-} /* namespace RVO2D */
diff --git a/thirdparty/rvo2/rvo2_2d/KdTree2d.cpp b/thirdparty/rvo2/rvo2_2d/KdTree2d.cpp
new file mode 100644
index 0000000000..184bc74fe2
--- /dev/null
+++ b/thirdparty/rvo2/rvo2_2d/KdTree2d.cpp
@@ -0,0 +1,357 @@
+/*
+ * KdTree2d.cpp
+ * RVO2 Library
+ *
+ * Copyright 2008 University of North Carolina at Chapel Hill
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to <geom@cs.unc.edu>.
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ * <http://gamma.cs.unc.edu/RVO2/>
+ */
+
+#include "KdTree2d.h"
+
+#include "Agent2d.h"
+#include "RVOSimulator2d.h"
+#include "Obstacle2d.h"
+
+namespace RVO2D {
+ KdTree2D::KdTree2D(RVOSimulator2D *sim) : obstacleTree_(NULL), sim_(sim) { }
+
+ KdTree2D::~KdTree2D()
+ {
+ deleteObstacleTree(obstacleTree_);
+ }
+
+ void KdTree2D::buildAgentTree(std::vector<Agent2D *> agents)
+ {
+ agents_.swap(agents);
+
+ if (!agents_.empty()) {
+ agentTree_.resize(2 * agents_.size() - 1);
+ buildAgentTreeRecursive(0, agents_.size(), 0);
+ }
+ }
+
+ void KdTree2D::buildAgentTreeRecursive(size_t begin, size_t end, size_t node)
+ {
+ agentTree_[node].begin = begin;
+ agentTree_[node].end = end;
+ agentTree_[node].minX = agentTree_[node].maxX = agents_[begin]->position_.x();
+ agentTree_[node].minY = agentTree_[node].maxY = agents_[begin]->position_.y();
+
+ for (size_t i = begin + 1; i < end; ++i) {
+ agentTree_[node].maxX = std::max(agentTree_[node].maxX, agents_[i]->position_.x());
+ agentTree_[node].minX = std::min(agentTree_[node].minX, agents_[i]->position_.x());
+ agentTree_[node].maxY = std::max(agentTree_[node].maxY, agents_[i]->position_.y());
+ agentTree_[node].minY = std::min(agentTree_[node].minY, agents_[i]->position_.y());
+ }
+
+ if (end - begin > MAX_LEAF_SIZE) {
+ /* No leaf node. */
+ const bool isVertical = (agentTree_[node].maxX - agentTree_[node].minX > agentTree_[node].maxY - agentTree_[node].minY);
+ const float splitValue = (isVertical ? 0.5f * (agentTree_[node].maxX + agentTree_[node].minX) : 0.5f * (agentTree_[node].maxY + agentTree_[node].minY));
+
+ size_t left = begin;
+ size_t right = end;
+
+ while (left < right) {
+ while (left < right && (isVertical ? agents_[left]->position_.x() : agents_[left]->position_.y()) < splitValue) {
+ ++left;
+ }
+
+ while (right > left && (isVertical ? agents_[right - 1]->position_.x() : agents_[right - 1]->position_.y()) >= splitValue) {
+ --right;
+ }
+
+ if (left < right) {
+ std::swap(agents_[left], agents_[right - 1]);
+ ++left;
+ --right;
+ }
+ }
+
+ if (left == begin) {
+ ++left;
+ ++right;
+ }
+
+ agentTree_[node].left = node + 1;
+ agentTree_[node].right = node + 2 * (left - begin);
+
+ buildAgentTreeRecursive(begin, left, agentTree_[node].left);
+ buildAgentTreeRecursive(left, end, agentTree_[node].right);
+ }
+ }
+
+ void KdTree2D::buildObstacleTree(std::vector<Obstacle2D *> obstacles)
+ {
+ deleteObstacleTree(obstacleTree_);
+
+ obstacleTree_ = buildObstacleTreeRecursive(obstacles);
+ }
+
+
+ KdTree2D::ObstacleTreeNode *KdTree2D::buildObstacleTreeRecursive(const std::vector<Obstacle2D *> &obstacles)
+ {
+ if (obstacles.empty()) {
+ return NULL;
+ }
+ else {
+ ObstacleTreeNode *const node = new ObstacleTreeNode;
+
+ size_t optimalSplit = 0;
+ size_t minLeft = obstacles.size();
+ size_t minRight = obstacles.size();
+
+ for (size_t i = 0; i < obstacles.size(); ++i) {
+ size_t leftSize = 0;
+ size_t rightSize = 0;
+
+ const Obstacle2D *const obstacleI1 = obstacles[i];
+ const Obstacle2D *const obstacleI2 = obstacleI1->nextObstacle_;
+
+ /* Compute optimal split node. */
+ for (size_t j = 0; j < obstacles.size(); ++j) {
+ if (i == j) {
+ continue;
+ }
+
+ const Obstacle2D *const obstacleJ1 = obstacles[j];
+ const Obstacle2D *const obstacleJ2 = obstacleJ1->nextObstacle_;
+
+ const float j1LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ1->point_);
+ const float j2LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ2->point_);
+
+ if (j1LeftOfI >= -RVO_EPSILON && j2LeftOfI >= -RVO_EPSILON) {
+ ++leftSize;
+ }
+ else if (j1LeftOfI <= RVO_EPSILON && j2LeftOfI <= RVO_EPSILON) {
+ ++rightSize;
+ }
+ else {
+ ++leftSize;
+ ++rightSize;
+ }
+
+ if (std::make_pair(std::max(leftSize, rightSize), std::min(leftSize, rightSize)) >= std::make_pair(std::max(minLeft, minRight), std::min(minLeft, minRight))) {
+ break;
+ }
+ }
+
+ if (std::make_pair(std::max(leftSize, rightSize), std::min(leftSize, rightSize)) < std::make_pair(std::max(minLeft, minRight), std::min(minLeft, minRight))) {
+ minLeft = leftSize;
+ minRight = rightSize;
+ optimalSplit = i;
+ }
+ }
+
+ /* Build split node. */
+ std::vector<Obstacle2D *> leftObstacles(minLeft);
+ std::vector<Obstacle2D *> rightObstacles(minRight);
+
+ size_t leftCounter = 0;
+ size_t rightCounter = 0;
+ const size_t i = optimalSplit;
+
+ const Obstacle2D *const obstacleI1 = obstacles[i];
+ const Obstacle2D *const obstacleI2 = obstacleI1->nextObstacle_;
+
+ for (size_t j = 0; j < obstacles.size(); ++j) {
+ if (i == j) {
+ continue;
+ }
+
+ Obstacle2D *const obstacleJ1 = obstacles[j];
+ Obstacle2D *const obstacleJ2 = obstacleJ1->nextObstacle_;
+
+ const float j1LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ1->point_);
+ const float j2LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ2->point_);
+
+ if (j1LeftOfI >= -RVO_EPSILON && j2LeftOfI >= -RVO_EPSILON) {
+ leftObstacles[leftCounter++] = obstacles[j];
+ }
+ else if (j1LeftOfI <= RVO_EPSILON && j2LeftOfI <= RVO_EPSILON) {
+ rightObstacles[rightCounter++] = obstacles[j];
+ }
+ else {
+ /* Split obstacle j. */
+ const float t = det(obstacleI2->point_ - obstacleI1->point_, obstacleJ1->point_ - obstacleI1->point_) / det(obstacleI2->point_ - obstacleI1->point_, obstacleJ1->point_ - obstacleJ2->point_);
+
+ const Vector2 splitpoint = obstacleJ1->point_ + t * (obstacleJ2->point_ - obstacleJ1->point_);
+
+ Obstacle2D *const newObstacle = new Obstacle2D();
+ newObstacle->point_ = splitpoint;
+ newObstacle->prevObstacle_ = obstacleJ1;
+ newObstacle->nextObstacle_ = obstacleJ2;
+ newObstacle->isConvex_ = true;
+ newObstacle->unitDir_ = obstacleJ1->unitDir_;
+
+ newObstacle->id_ = sim_->obstacles_.size();
+
+ sim_->obstacles_.push_back(newObstacle);
+
+ obstacleJ1->nextObstacle_ = newObstacle;
+ obstacleJ2->prevObstacle_ = newObstacle;
+
+ if (j1LeftOfI > 0.0f) {
+ leftObstacles[leftCounter++] = obstacleJ1;
+ rightObstacles[rightCounter++] = newObstacle;
+ }
+ else {
+ rightObstacles[rightCounter++] = obstacleJ1;
+ leftObstacles[leftCounter++] = newObstacle;
+ }
+ }
+ }
+
+ node->obstacle = obstacleI1;
+ node->left = buildObstacleTreeRecursive(leftObstacles);
+ node->right = buildObstacleTreeRecursive(rightObstacles);
+ return node;
+ }
+ }
+
+ void KdTree2D::computeAgentNeighbors(Agent2D *agent, float &rangeSq) const
+ {
+ queryAgentTreeRecursive(agent, rangeSq, 0);
+ }
+
+ void KdTree2D::computeObstacleNeighbors(Agent2D *agent, float rangeSq) const
+ {
+ queryObstacleTreeRecursive(agent, rangeSq, obstacleTree_);
+ }
+
+ void KdTree2D::deleteObstacleTree(ObstacleTreeNode *node)
+ {
+ if (node != NULL) {
+ deleteObstacleTree(node->left);
+ deleteObstacleTree(node->right);
+ delete node;
+ }
+ }
+
+ void KdTree2D::queryAgentTreeRecursive(Agent2D *agent, float &rangeSq, size_t node) const
+ {
+ if (agentTree_[node].end - agentTree_[node].begin <= MAX_LEAF_SIZE) {
+ for (size_t i = agentTree_[node].begin; i < agentTree_[node].end; ++i) {
+ agent->insertAgentNeighbor(agents_[i], rangeSq);
+ }
+ }
+ else {
+ const float distSqLeft = sqr(std::max(0.0f, agentTree_[agentTree_[node].left].minX - agent->position_.x())) + sqr(std::max(0.0f, agent->position_.x() - agentTree_[agentTree_[node].left].maxX)) + sqr(std::max(0.0f, agentTree_[agentTree_[node].left].minY - agent->position_.y())) + sqr(std::max(0.0f, agent->position_.y() - agentTree_[agentTree_[node].left].maxY));
+
+ const float distSqRight = sqr(std::max(0.0f, agentTree_[agentTree_[node].right].minX - agent->position_.x())) + sqr(std::max(0.0f, agent->position_.x() - agentTree_[agentTree_[node].right].maxX)) + sqr(std::max(0.0f, agentTree_[agentTree_[node].right].minY - agent->position_.y())) + sqr(std::max(0.0f, agent->position_.y() - agentTree_[agentTree_[node].right].maxY));
+
+ if (distSqLeft < distSqRight) {
+ if (distSqLeft < rangeSq) {
+ queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);
+
+ if (distSqRight < rangeSq) {
+ queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);
+ }
+ }
+ }
+ else {
+ if (distSqRight < rangeSq) {
+ queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);
+
+ if (distSqLeft < rangeSq) {
+ queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);
+ }
+ }
+ }
+
+ }
+ }
+
+ void KdTree2D::queryObstacleTreeRecursive(Agent2D *agent, float rangeSq, const ObstacleTreeNode *node) const
+ {
+ if (node == NULL) {
+ return;
+ }
+ else {
+ const Obstacle2D *const obstacle1 = node->obstacle;
+ const Obstacle2D *const obstacle2 = obstacle1->nextObstacle_;
+
+ const float agentLeftOfLine = leftOf(obstacle1->point_, obstacle2->point_, agent->position_);
+
+ queryObstacleTreeRecursive(agent, rangeSq, (agentLeftOfLine >= 0.0f ? node->left : node->right));
+
+ const float distSqLine = sqr(agentLeftOfLine) / absSq(obstacle2->point_ - obstacle1->point_);
+
+ if (distSqLine < rangeSq) {
+ if (agentLeftOfLine < 0.0f) {
+ /*
+ * Try obstacle at this node only if agent is on right side of
+ * obstacle (and can see obstacle).
+ */
+ agent->insertObstacleNeighbor(node->obstacle, rangeSq);
+ }
+
+ /* Try other side of line. */
+ queryObstacleTreeRecursive(agent, rangeSq, (agentLeftOfLine >= 0.0f ? node->right : node->left));
+
+ }
+ }
+ }
+
+ bool KdTree2D::queryVisibility(const Vector2 &q1, const Vector2 &q2, float radius) const
+ {
+ return queryVisibilityRecursive(q1, q2, radius, obstacleTree_);
+ }
+
+ bool KdTree2D::queryVisibilityRecursive(const Vector2 &q1, const Vector2 &q2, float radius, const ObstacleTreeNode *node) const
+ {
+ if (node == NULL) {
+ return true;
+ }
+ else {
+ const Obstacle2D *const obstacle1 = node->obstacle;
+ const Obstacle2D *const obstacle2 = obstacle1->nextObstacle_;
+
+ const float q1LeftOfI = leftOf(obstacle1->point_, obstacle2->point_, q1);
+ const float q2LeftOfI = leftOf(obstacle1->point_, obstacle2->point_, q2);
+ const float invLengthI = 1.0f / absSq(obstacle2->point_ - obstacle1->point_);
+
+ if (q1LeftOfI >= 0.0f && q2LeftOfI >= 0.0f) {
+ return queryVisibilityRecursive(q1, q2, radius, node->left) && ((sqr(q1LeftOfI) * invLengthI >= sqr(radius) && sqr(q2LeftOfI) * invLengthI >= sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node->right));
+ }
+ else if (q1LeftOfI <= 0.0f && q2LeftOfI <= 0.0f) {
+ return queryVisibilityRecursive(q1, q2, radius, node->right) && ((sqr(q1LeftOfI) * invLengthI >= sqr(radius) && sqr(q2LeftOfI) * invLengthI >= sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node->left));
+ }
+ else if (q1LeftOfI >= 0.0f && q2LeftOfI <= 0.0f) {
+ /* One can see through obstacle from left to right. */
+ return queryVisibilityRecursive(q1, q2, radius, node->left) && queryVisibilityRecursive(q1, q2, radius, node->right);
+ }
+ else {
+ const float point1LeftOfQ = leftOf(q1, q2, obstacle1->point_);
+ const float point2LeftOfQ = leftOf(q1, q2, obstacle2->point_);
+ const float invLengthQ = 1.0f / absSq(q2 - q1);
+
+ return (point1LeftOfQ * point2LeftOfQ >= 0.0f && sqr(point1LeftOfQ) * invLengthQ > sqr(radius) && sqr(point2LeftOfQ) * invLengthQ > sqr(radius) && queryVisibilityRecursive(q1, q2, radius, node->left) && queryVisibilityRecursive(q1, q2, radius, node->right));
+ }
+ }
+ }
+}
diff --git a/thirdparty/rvo2/rvo2_2d/KdTree2d.h b/thirdparty/rvo2/rvo2_2d/KdTree2d.h
index c0e0fe9a5b..c7159eab97 100644
--- a/thirdparty/rvo2/rvo2_2d/KdTree2d.h
+++ b/thirdparty/rvo2/rvo2_2d/KdTree2d.h
@@ -2,14 +2,13 @@
* KdTree2d.h
* RVO2 Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,162 +27,177 @@
* Chapel Hill, N.C. 27599-3175
* United States of America
*
- * <https://gamma.cs.unc.edu/RVO2/>
+ * <http://gamma.cs.unc.edu/RVO2/>
*/
#ifndef RVO2D_KD_TREE_H_
#define RVO2D_KD_TREE_H_
/**
- * @file KdTree2d.h
- * @brief Declares the KdTree2D class.
+ * \file KdTree2d.h
+ * \brief Contains the KdTree class.
*/
-#include <cstddef>
-#include <vector>
+#include "Definitions.h"
namespace RVO2D {
-class Agent2D;
-class Obstacle2D;
-class RVOSimulator2D;
-class Vector2;
-
-/**
- * @brief Defines k-D trees for agents and static obstacles in the simulation.
- */
-class KdTree2D {
- public:
- class AgentTreeNode;
- class ObstacleTreeNode;
-
- /**
- * @brief Constructs a k-D tree instance.
- * @param[in] simulator The simulator instance.
- */
- explicit KdTree2D(RVOSimulator2D *simulator);
-
- /**
- * @brief Destroys this k-D tree instance.
- */
- ~KdTree2D();
-
- /**
- * @brief Builds an agent k-D tree.
- */
- void buildAgentTree(std::vector<Agent2D *> agents);
-
- /**
- * @brief Recursive function to build an agent k-D tree.
- * @param[in] begin The beginning agent k-D tree node.
- * @param[in] end The ending agent k-D tree node.
- * @param[in] node The current agent k-D tree node.
- */
- void buildAgentTreeRecursive(std::size_t begin, std::size_t end,
- std::size_t node);
-
- /**
- * @brief Builds an obstacle k-D tree.
- */
- void buildObstacleTree(std::vector<Obstacle2D *> obstacles);
-
- /**
- * @brief Recursive function to build an obstacle k-D tree.
- * @param[in] obstacles List of obstacles from which to build the obstacle k-D
- * tree.
- */
- ObstacleTreeNode *buildObstacleTreeRecursive(
- const std::vector<Obstacle2D *> &obstacles);
-
- /**
- * @brief Computes the agent neighbors of the specified agent.
- * @param[in] agent A pointer to the agent for which agent neighbors
- * are to be computed.
- * @param[in, out] rangeSq The squared range around the agent.
- */
- void computeAgentNeighbors(
- Agent2D *agent, float &rangeSq) const; /* NOLINT(runtime/references) */
-
- /**
- * @brief Computes the obstacle neighbors of the specified agent.
- * @param[in] agent A pointer to the agent for which obstacle neighbors are
- * to be computed.
- * @param[in] rangeSq The squared range around the agent.
- */
- void computeObstacleNeighbors(Agent2D *agent, float rangeSq) const;
-
- /**
- * @brief Deletes the specified obstacle tree node.
- * @param[in] node A pointer to the obstacle tree node to be deleted.
- */
- void deleteObstacleTree(ObstacleTreeNode *node);
-
- /**
- * @brief Recursive function to compute the neighbors of the specified
- * agent.
- * @param[in] agent A pointer to the agent for which neighbors are to be
- * computed.
- * @param[in,out] rangeSq The squared range around the agent.
- * @param[in] node The current agent k-D tree node.
- */
- void queryAgentTreeRecursive(Agent2D *agent,
- float &rangeSq, /* NOLINT(runtime/references) */
- std::size_t node) const;
-
- /**
- * @brief Recursive function to compute the neighbors of the specified
- * obstacle.
- * @param[in] agent A pointer to the agent for which neighbors are to be
- * computed.
- * @param[in,out] rangeSq The squared range around the agent.
- * @param[in] node The current obstacle k-D tree node.
- */
- void queryObstacleTreeRecursive(Agent2D *agent, float rangeSq,
- const ObstacleTreeNode *node) const;
-
- /**
- * @brief Queries the visibility between two points within a specified
- * radius.
- * @param[in] vector1 The first point between which visibility is to be
- * tested.
- * @param[in] vector2 The second point between which visibility is to be
- * tested.
- * @param[in] radius The radius within which visibility is to be tested.
- * @return True if q1 and q2 are mutually visible within the radius; false
- * otherwise.
- */
- bool queryVisibility(const Vector2 &vector1, const Vector2 &vector2,
- float radius) const;
-
- /**
- * @brief Recursive function to query the visibility between two points
- * within a specified radius.
- * @param[in] vector1 The first point between which visibility is to be
- * tested.
- * @param[in] vector2 The second point between which visibility is to be
- * tested.
- * @param[in] radius The radius within which visibility is to be tested.
- * @param[in] node The current obstacle k-D tree node.
- * @return True if q1 and q2 are mutually visible within the radius; false
- * otherwise.
- */
- bool queryVisibilityRecursive(const Vector2 &vector1, const Vector2 &vector2,
- float radius,
- const ObstacleTreeNode *node) const;
-
- /* Not implemented. */
- KdTree2D(const KdTree2D &other);
-
- /* Not implemented. */
- KdTree2D &operator=(const KdTree2D &other);
-
- std::vector<Agent2D *> agents_;
- std::vector<AgentTreeNode> agentTree_;
- ObstacleTreeNode *obstacleTree_;
- RVOSimulator2D *simulator_;
-
- friend class Agent2D;
- friend class RVOSimulator2D;
-};
-} /* namespace RVO2D */
+ /**
+ * \brief Defines <i>k</i>d-trees for agents and static obstacles in the
+ * simulation.
+ */
+ class KdTree2D {
+ public:
+ /**
+ * \brief Defines an agent <i>k</i>d-tree node.
+ */
+ class AgentTreeNode {
+ public:
+ /**
+ * \brief The beginning node number.
+ */
+ size_t begin;
+
+ /**
+ * \brief The ending node number.
+ */
+ size_t end;
+
+ /**
+ * \brief The left node number.
+ */
+ size_t left;
+
+ /**
+ * \brief The maximum x-coordinate.
+ */
+ float maxX;
+
+ /**
+ * \brief The maximum y-coordinate.
+ */
+ float maxY;
+
+ /**
+ * \brief The minimum x-coordinate.
+ */
+ float minX;
+
+ /**
+ * \brief The minimum y-coordinate.
+ */
+ float minY;
+
+ /**
+ * \brief The right node number.
+ */
+ size_t right;
+ };
+
+ /**
+ * \brief Defines an obstacle <i>k</i>d-tree node.
+ */
+ class ObstacleTreeNode {
+ public:
+ /**
+ * \brief The left obstacle tree node.
+ */
+ ObstacleTreeNode *left;
+
+ /**
+ * \brief The obstacle number.
+ */
+ const Obstacle2D *obstacle;
+
+ /**
+ * \brief The right obstacle tree node.
+ */
+ ObstacleTreeNode *right;
+ };
+
+ /**
+ * \brief Constructs a <i>k</i>d-tree instance.
+ * \param sim The simulator instance.
+ */
+ explicit KdTree2D(RVOSimulator2D *sim);
+
+ /**
+ * \brief Destroys this kd-tree instance.
+ */
+ ~KdTree2D();
+
+ /**
+ * \brief Builds an agent <i>k</i>d-tree.
+ */
+ void buildAgentTree(std::vector<Agent2D *> agents);
+
+ void buildAgentTreeRecursive(size_t begin, size_t end, size_t node);
+
+ /**
+ * \brief Builds an obstacle <i>k</i>d-tree.
+ */
+ void buildObstacleTree(std::vector<Obstacle2D *> obstacles);
+
+ ObstacleTreeNode *buildObstacleTreeRecursive(const std::vector<Obstacle2D *> &
+ obstacles);
+
+ /**
+ * \brief Computes the agent neighbors of the specified agent.
+ * \param agent A pointer to the agent for which agent
+ * neighbors are to be computed.
+ * \param rangeSq The squared range around the agent.
+ */
+ void computeAgentNeighbors(Agent2D *agent, float &rangeSq) const;
+
+ /**
+ * \brief Computes the obstacle neighbors of the specified agent.
+ * \param agent A pointer to the agent for which obstacle
+ * neighbors are to be computed.
+ * \param rangeSq The squared range around the agent.
+ */
+ void computeObstacleNeighbors(Agent2D *agent, float rangeSq) const;
+
+ /**
+ * \brief Deletes the specified obstacle tree node.
+ * \param node A pointer to the obstacle tree node to be
+ * deleted.
+ */
+ void deleteObstacleTree(ObstacleTreeNode *node);
+
+ void queryAgentTreeRecursive(Agent2D *agent, float &rangeSq,
+ size_t node) const;
+
+ void queryObstacleTreeRecursive(Agent2D *agent, float rangeSq,
+ const ObstacleTreeNode *node) const;
+
+ /**
+ * \brief Queries the visibility between two points within a
+ * specified radius.
+ * \param q1 The first point between which visibility is
+ * to be tested.
+ * \param q2 The second point between which visibility is
+ * to be tested.
+ * \param radius The radius within which visibility is to be
+ * tested.
+ * \return True if q1 and q2 are mutually visible within the radius;
+ * false otherwise.
+ */
+ bool queryVisibility(const Vector2 &q1, const Vector2 &q2,
+ float radius) const;
+
+ bool queryVisibilityRecursive(const Vector2 &q1, const Vector2 &q2,
+ float radius,
+ const ObstacleTreeNode *node) const;
+
+ std::vector<Agent2D *> agents_;
+ std::vector<AgentTreeNode> agentTree_;
+ ObstacleTreeNode *obstacleTree_;
+ RVOSimulator2D *sim_;
+
+ static const size_t MAX_LEAF_SIZE = 10;
+
+ friend class Agent2D;
+ friend class RVOSimulator2D;
+ };
+}
#endif /* RVO2D_KD_TREE_H_ */
diff --git a/thirdparty/rvo2/rvo2_2d/Line.h b/thirdparty/rvo2/rvo2_2d/Line.h
deleted file mode 100644
index 046fa82e21..0000000000
--- a/thirdparty/rvo2/rvo2_2d/Line.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Line.h
- * RVO2 Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-#ifndef RVO2D_LINE_H_
-#define RVO2D_LINE_H_
-
-/**
- * @file Line.h
- * @brief Declares the Line class.
- */
-
-#include "Vector2.h"
-
-namespace RVO2D {
-/**
- * @brief Defines a directed line.
- */
-class Line {
- public:
- /**
- * @brief Constructs a directed line instance.
- */
- Line();
-
- /**
- * @brief The direction of the directed line.
- */
- Vector2 direction;
-
- /**
- * @brief A point on the directed line.
- */
- Vector2 point;
-};
-} /* namespace RVO2D */
-
-#endif /* RVO2D_LINE_H_ */
diff --git a/thirdparty/rvo2/rvo2_2d/Obstacle2d.cc b/thirdparty/rvo2/rvo2_2d/Obstacle2d.cc
deleted file mode 100644
index 0a0a5d6f26..0000000000
--- a/thirdparty/rvo2/rvo2_2d/Obstacle2d.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Obstacle2d.cpp
- * RVO2 Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-/**
- * @file Obstacle2d.cpp
- * @brief Defines the Obstacle2D class.
- */
-
-#include "Obstacle2d.h"
-
-namespace RVO2D {
-Obstacle2D::Obstacle2D()
- : next_(NULL), previous_(NULL), id_(0U), isConvex_(false) {}
-
-Obstacle2D::~Obstacle2D() {}
-} /* namespace RVO2D */
diff --git a/thirdparty/rvo2/rvo2_2d/Line.cc b/thirdparty/rvo2/rvo2_2d/Obstacle2d.cpp
index 3baf841cf6..a80c8af136 100644
--- a/thirdparty/rvo2/rvo2_2d/Line.cc
+++ b/thirdparty/rvo2/rvo2_2d/Obstacle2d.cpp
@@ -1,15 +1,14 @@
/*
- * Line.cc
+ * Obstacle2d.cpp
* RVO2 Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,16 +27,12 @@
* Chapel Hill, N.C. 27599-3175
* United States of America
*
- * <https://gamma.cs.unc.edu/RVO2/>
+ * <http://gamma.cs.unc.edu/RVO2/>
*/
-/**
- * @file Line.cc
- * @brief Defines the Line class.
- */
-
-#include "Line.h"
+#include "Obstacle2d.h"
+#include "RVOSimulator2d.h"
namespace RVO2D {
-Line::Line() {}
-} /* namespace RVO2D */
+ Obstacle2D::Obstacle2D() : isConvex_(false), nextObstacle_(NULL), prevObstacle_(NULL), id_(0) { }
+}
diff --git a/thirdparty/rvo2/rvo2_2d/Obstacle2d.h b/thirdparty/rvo2/rvo2_2d/Obstacle2d.h
index 8d9b61c13c..9ba5937053 100644
--- a/thirdparty/rvo2/rvo2_2d/Obstacle2d.h
+++ b/thirdparty/rvo2/rvo2_2d/Obstacle2d.h
@@ -2,14 +2,13 @@
* Obstacle2d.h
* RVO2 Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,59 +27,46 @@
* Chapel Hill, N.C. 27599-3175
* United States of America
*
- * <https://gamma.cs.unc.edu/RVO2/>
+ * <http://gamma.cs.unc.edu/RVO2/>
*/
#ifndef RVO2D_OBSTACLE_H_
#define RVO2D_OBSTACLE_H_
/**
- * @file Obstacle2d.h
- * @brief Declares the Obstacle2D class.
+ * \file Obstacle2d.h
+ * \brief Contains the Obstacle class.
*/
-#include <cstddef>
-#include <cstdint>
-
-#include "Vector2.h"
+#include "Definitions.h"
namespace RVO2D {
-/**
- * @brief Defines static obstacles in the simulation.
- */
-class Obstacle2D {
- public:
- /**
- * @brief Constructs a static obstacle instance.
- */
- Obstacle2D();
-
- /**
- * @brief Destroys this static obstacle instance.
- */
- ~Obstacle2D();
-
- /* Not implemented. */
- Obstacle2D(const Obstacle2D &other);
+ /**
+ * \brief Defines static obstacles in the simulation.
+ */
+ class Obstacle2D {
+ public:
+ /**
+ * \brief Constructs a static obstacle instance.
+ */
+ Obstacle2D();
- /* Not implemented. */
- Obstacle2D &operator=(const Obstacle2D &other);
+ bool isConvex_;
+ Obstacle2D *nextObstacle_;
+ Vector2 point_;
+ Obstacle2D *prevObstacle_;
+ Vector2 unitDir_;
- Vector2 direction_;
- Vector2 point_;
- Obstacle2D *next_;
- Obstacle2D *previous_;
- std::size_t id_;
- bool isConvex_;
+ float height_ = 1.0;
+ float elevation_ = 0.0;
+ uint32_t avoidance_layers_ = 1;
- float height_ = 1.0;
- float elevation_ = 0.0;
- uint32_t avoidance_layers_ = 1;
+ size_t id_;
- friend class Agent2D;
- friend class KdTree2D;
- friend class RVOSimulator2D;
-};
-} /* namespace RVO2D */
+ friend class Agent2D;
+ friend class KdTree2D;
+ friend class RVOSimulator2D;
+ };
+}
#endif /* RVO2D_OBSTACLE_H_ */
diff --git a/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.cc b/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.cc
deleted file mode 100644
index fe44842c5c..0000000000
--- a/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.cc
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * RVOSimulator2d.cpp
- * RVO2 Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-/**
- * @file RVOSimulator2d.cpp
- * @brief Defines the RVOSimulator2D class.
- */
-
-#include "RVOSimulator2d.h"
-
-#include <limits>
-#include <utility>
-
-#include "Agent2d.h"
-#include "KdTree2d.h"
-#include "Line.h"
-#include "Obstacle2d.h"
-#include "Vector2.h"
-
-#ifdef _OPENMP
-#include <omp.h>
-#endif /* _OPENMP */
-
-namespace RVO2D {
-const std::size_t RVO2D_ERROR = std::numeric_limits<std::size_t>::max();
-
-RVOSimulator2D::RVOSimulator2D()
- : defaultAgent_(NULL),
- kdTree_(new KdTree2D(this)),
- globalTime_(0.0F),
- timeStep_(0.0F) {}
-
-RVOSimulator2D::RVOSimulator2D(float timeStep, float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float timeHorizonObst, float radius, float maxSpeed)
- : defaultAgent_(new Agent2D()),
- kdTree_(new KdTree2D(this)),
- globalTime_(0.0F),
- timeStep_(timeStep) {
- defaultAgent_->maxNeighbors_ = maxNeighbors;
- defaultAgent_->maxSpeed_ = maxSpeed;
- defaultAgent_->neighborDist_ = neighborDist;
- defaultAgent_->radius_ = radius;
- defaultAgent_->timeHorizon_ = timeHorizon;
- defaultAgent_->timeHorizonObst_ = timeHorizonObst;
-}
-
-RVOSimulator2D::RVOSimulator2D(float timeStep, float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float timeHorizonObst, float radius, float maxSpeed,
- const Vector2 &velocity)
- : defaultAgent_(new Agent2D()),
- kdTree_(new KdTree2D(this)),
- globalTime_(0.0F),
- timeStep_(timeStep) {
- defaultAgent_->velocity_ = velocity;
- defaultAgent_->maxNeighbors_ = maxNeighbors;
- defaultAgent_->maxSpeed_ = maxSpeed;
- defaultAgent_->neighborDist_ = neighborDist;
- defaultAgent_->radius_ = radius;
- defaultAgent_->timeHorizon_ = timeHorizon;
- defaultAgent_->timeHorizonObst_ = timeHorizonObst;
-}
-
-RVOSimulator2D::~RVOSimulator2D() {
- delete defaultAgent_;
- delete kdTree_;
-
- for (std::size_t i = 0U; i < agents_.size(); ++i) {
- delete agents_[i];
- }
-
- for (std::size_t i = 0U; i < obstacles_.size(); ++i) {
- delete obstacles_[i];
- }
-}
-
-std::size_t RVOSimulator2D::addAgent(const Vector2 &position) {
- if (defaultAgent_ != NULL) {
- Agent2D *const agent = new Agent2D();
- agent->position_ = position;
- agent->velocity_ = defaultAgent_->velocity_;
- agent->id_ = agents_.size();
- agent->maxNeighbors_ = defaultAgent_->maxNeighbors_;
- agent->maxSpeed_ = defaultAgent_->maxSpeed_;
- agent->neighborDist_ = defaultAgent_->neighborDist_;
- agent->radius_ = defaultAgent_->radius_;
- agent->timeHorizon_ = defaultAgent_->timeHorizon_;
- agent->timeHorizonObst_ = defaultAgent_->timeHorizonObst_;
- agents_.push_back(agent);
-
- return agents_.size() - 1U;
- }
-
- return RVO2D_ERROR;
-}
-
-std::size_t RVOSimulator2D::addAgent(const Vector2 &position, float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float timeHorizonObst, float radius,
- float maxSpeed) {
- return addAgent(position, neighborDist, maxNeighbors, timeHorizon,
- timeHorizonObst, radius, maxSpeed, Vector2());
-}
-
-std::size_t RVOSimulator2D::addAgent(const Vector2 &position, float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float timeHorizonObst, float radius,
- float maxSpeed, const Vector2 &velocity) {
- Agent2D *const agent = new Agent2D();
- agent->position_ = position;
- agent->velocity_ = velocity;
- agent->id_ = agents_.size();
- agent->maxNeighbors_ = maxNeighbors;
- agent->maxSpeed_ = maxSpeed;
- agent->neighborDist_ = neighborDist;
- agent->radius_ = radius;
- agent->timeHorizon_ = timeHorizon;
- agent->timeHorizonObst_ = timeHorizonObst;
- agents_.push_back(agent);
-
- return agents_.size() - 1U;
-}
-
-std::size_t RVOSimulator2D::addObstacle(const std::vector<Vector2> &vertices) {
- if (vertices.size() > 1U) {
- const std::size_t obstacleNo = obstacles_.size();
-
- for (std::size_t i = 0U; i < vertices.size(); ++i) {
- Obstacle2D *const obstacle = new Obstacle2D();
- obstacle->point_ = vertices[i];
-
- if (i != 0U) {
- obstacle->previous_ = obstacles_.back();
- obstacle->previous_->next_ = obstacle;
- }
-
- if (i == vertices.size() - 1U) {
- obstacle->next_ = obstacles_[obstacleNo];
- obstacle->next_->previous_ = obstacle;
- }
-
- obstacle->direction_ = normalize(
- vertices[(i == vertices.size() - 1U ? 0U : i + 1U)] - vertices[i]);
-
- if (vertices.size() == 2U) {
- obstacle->isConvex_ = true;
- } else {
- obstacle->isConvex_ =
- leftOf(vertices[i == 0U ? vertices.size() - 1U : i - 1U],
- vertices[i],
- vertices[i == vertices.size() - 1U ? 0U : i + 1U]) >= 0.0F;
- }
-
- obstacle->id_ = obstacles_.size();
-
- obstacles_.push_back(obstacle);
- }
-
- return obstacleNo;
- }
-
- return RVO2D_ERROR;
-}
-
-void RVOSimulator2D::doStep() {
- kdTree_->buildAgentTree(agents_);
-
-#ifdef _OPENMP
-#pragma omp parallel for
-#endif /* _OPENMP */
- for (int i = 0; i < static_cast<int>(agents_.size()); ++i) {
- agents_[i]->computeNeighbors(kdTree_);
- agents_[i]->computeNewVelocity(timeStep_);
- }
-
-#ifdef _OPENMP
-#pragma omp parallel for
-#endif /* _OPENMP */
- for (int i = 0; i < static_cast<int>(agents_.size()); ++i) {
- agents_[i]->update(timeStep_);
- }
-
- globalTime_ += timeStep_;
-}
-
-std::size_t RVOSimulator2D::getAgentAgentNeighbor(std::size_t agentNo,
- std::size_t neighborNo) const {
- return agents_[agentNo]->agentNeighbors_[neighborNo].second->id_;
-}
-
-std::size_t RVOSimulator2D::getAgentMaxNeighbors(std::size_t agentNo) const {
- return agents_[agentNo]->maxNeighbors_;
-}
-
-float RVOSimulator2D::getAgentMaxSpeed(std::size_t agentNo) const {
- return agents_[agentNo]->maxSpeed_;
-}
-
-float RVOSimulator2D::getAgentNeighborDist(std::size_t agentNo) const {
- return agents_[agentNo]->neighborDist_;
-}
-
-std::size_t RVOSimulator2D::getAgentNumAgentNeighbors(std::size_t agentNo) const {
- return agents_[agentNo]->agentNeighbors_.size();
-}
-
-std::size_t RVOSimulator2D::getAgentNumObstacleNeighbors(
- std::size_t agentNo) const {
- return agents_[agentNo]->obstacleNeighbors_.size();
-}
-
-std::size_t RVOSimulator2D::getAgentNumORCALines(std::size_t agentNo) const {
- return agents_[agentNo]->orcaLines_.size();
-}
-
-std::size_t RVOSimulator2D::getAgentObstacleNeighbor(
- std::size_t agentNo, std::size_t neighborNo) const {
- return agents_[agentNo]->obstacleNeighbors_[neighborNo].second->id_;
-}
-
-const Line &RVOSimulator2D::getAgentORCALine(std::size_t agentNo,
- std::size_t lineNo) const {
- return agents_[agentNo]->orcaLines_[lineNo];
-}
-
-const Vector2 &RVOSimulator2D::getAgentPosition(std::size_t agentNo) const {
- return agents_[agentNo]->position_;
-}
-
-const Vector2 &RVOSimulator2D::getAgentPrefVelocity(std::size_t agentNo) const {
- return agents_[agentNo]->prefVelocity_;
-}
-
-float RVOSimulator2D::getAgentRadius(std::size_t agentNo) const {
- return agents_[agentNo]->radius_;
-}
-
-float RVOSimulator2D::getAgentTimeHorizon(std::size_t agentNo) const {
- return agents_[agentNo]->timeHorizon_;
-}
-
-float RVOSimulator2D::getAgentTimeHorizonObst(std::size_t agentNo) const {
- return agents_[agentNo]->timeHorizonObst_;
-}
-
-const Vector2 &RVOSimulator2D::getAgentVelocity(std::size_t agentNo) const {
- return agents_[agentNo]->velocity_;
-}
-
-const Vector2 &RVOSimulator2D::getObstacleVertex(std::size_t vertexNo) const {
- return obstacles_[vertexNo]->point_;
-}
-
-std::size_t RVOSimulator2D::getNextObstacleVertexNo(std::size_t vertexNo) const {
- return obstacles_[vertexNo]->next_->id_;
-}
-
-std::size_t RVOSimulator2D::getPrevObstacleVertexNo(std::size_t vertexNo) const {
- return obstacles_[vertexNo]->previous_->id_;
-}
-
-void RVOSimulator2D::processObstacles() { kdTree_->buildObstacleTree(obstacles_); }
-
-bool RVOSimulator2D::queryVisibility(const Vector2 &point1,
- const Vector2 &point2) const {
- return kdTree_->queryVisibility(point1, point2, 0.0F);
-}
-
-bool RVOSimulator2D::queryVisibility(const Vector2 &point1, const Vector2 &point2,
- float radius) const {
- return kdTree_->queryVisibility(point1, point2, radius);
-}
-
-void RVOSimulator2D::setAgentDefaults(float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float timeHorizonObst, float radius,
- float maxSpeed) {
- setAgentDefaults(neighborDist, maxNeighbors, timeHorizon, timeHorizonObst,
- radius, maxSpeed, Vector2());
-}
-
-void RVOSimulator2D::setAgentDefaults(float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float timeHorizonObst, float radius,
- float maxSpeed, const Vector2 &velocity) {
- if (defaultAgent_ == NULL) {
- defaultAgent_ = new Agent2D();
- }
-
- defaultAgent_->maxNeighbors_ = maxNeighbors;
- defaultAgent_->maxSpeed_ = maxSpeed;
- defaultAgent_->neighborDist_ = neighborDist;
- defaultAgent_->radius_ = radius;
- defaultAgent_->timeHorizon_ = timeHorizon;
- defaultAgent_->timeHorizonObst_ = timeHorizonObst;
- defaultAgent_->velocity_ = velocity;
-}
-
-void RVOSimulator2D::setAgentMaxNeighbors(std::size_t agentNo,
- std::size_t maxNeighbors) {
- agents_[agentNo]->maxNeighbors_ = maxNeighbors;
-}
-
-void RVOSimulator2D::setAgentMaxSpeed(std::size_t agentNo, float maxSpeed) {
- agents_[agentNo]->maxSpeed_ = maxSpeed;
-}
-
-void RVOSimulator2D::setAgentNeighborDist(std::size_t agentNo,
- float neighborDist) {
- agents_[agentNo]->neighborDist_ = neighborDist;
-}
-
-void RVOSimulator2D::setAgentPosition(std::size_t agentNo,
- const Vector2 &position) {
- agents_[agentNo]->position_ = position;
-}
-
-void RVOSimulator2D::setAgentPrefVelocity(std::size_t agentNo,
- const Vector2 &prefVelocity) {
- agents_[agentNo]->prefVelocity_ = prefVelocity;
-}
-
-void RVOSimulator2D::setAgentRadius(std::size_t agentNo, float radius) {
- agents_[agentNo]->radius_ = radius;
-}
-
-void RVOSimulator2D::setAgentTimeHorizon(std::size_t agentNo, float timeHorizon) {
- agents_[agentNo]->timeHorizon_ = timeHorizon;
-}
-
-void RVOSimulator2D::setAgentTimeHorizonObst(std::size_t agentNo,
- float timeHorizonObst) {
- agents_[agentNo]->timeHorizonObst_ = timeHorizonObst;
-}
-
-void RVOSimulator2D::setAgentVelocity(std::size_t agentNo,
- const Vector2 &velocity) {
- agents_[agentNo]->velocity_ = velocity;
-}
-} /* namespace RVO2D */
diff --git a/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.cpp b/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.cpp
new file mode 100644
index 0000000000..9fb1555ebc
--- /dev/null
+++ b/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.cpp
@@ -0,0 +1,363 @@
+/*
+ * RVOSimulator2d.cpp
+ * RVO2 Library
+ *
+ * Copyright 2008 University of North Carolina at Chapel Hill
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to <geom@cs.unc.edu>.
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ * <http://gamma.cs.unc.edu/RVO2/>
+ */
+
+#include "RVOSimulator2d.h"
+
+#include "Agent2d.h"
+#include "KdTree2d.h"
+#include "Obstacle2d.h"
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+namespace RVO2D {
+ RVOSimulator2D::RVOSimulator2D() : defaultAgent_(NULL), globalTime_(0.0f), kdTree_(NULL), timeStep_(0.0f)
+ {
+ kdTree_ = new KdTree2D(this);
+ }
+
+ RVOSimulator2D::RVOSimulator2D(float timeStep, float neighborDist, size_t maxNeighbors, float timeHorizon, float timeHorizonObst, float radius, float maxSpeed, const Vector2 &velocity) : defaultAgent_(NULL), globalTime_(0.0f), kdTree_(NULL), timeStep_(timeStep)
+ {
+ kdTree_ = new KdTree2D(this);
+ defaultAgent_ = new Agent2D();
+
+ defaultAgent_->maxNeighbors_ = maxNeighbors;
+ defaultAgent_->maxSpeed_ = maxSpeed;
+ defaultAgent_->neighborDist_ = neighborDist;
+ defaultAgent_->radius_ = radius;
+ defaultAgent_->timeHorizon_ = timeHorizon;
+ defaultAgent_->timeHorizonObst_ = timeHorizonObst;
+ defaultAgent_->velocity_ = velocity;
+ }
+
+ RVOSimulator2D::~RVOSimulator2D()
+ {
+ if (defaultAgent_ != NULL) {
+ delete defaultAgent_;
+ }
+
+ for (size_t i = 0; i < agents_.size(); ++i) {
+ delete agents_[i];
+ }
+
+ for (size_t i = 0; i < obstacles_.size(); ++i) {
+ delete obstacles_[i];
+ }
+
+ delete kdTree_;
+ }
+
+ size_t RVOSimulator2D::addAgent(const Vector2 &position)
+ {
+ if (defaultAgent_ == NULL) {
+ return RVO2D_ERROR;
+ }
+
+ Agent2D *agent = new Agent2D();
+
+ agent->position_ = position;
+ agent->maxNeighbors_ = defaultAgent_->maxNeighbors_;
+ agent->maxSpeed_ = defaultAgent_->maxSpeed_;
+ agent->neighborDist_ = defaultAgent_->neighborDist_;
+ agent->radius_ = defaultAgent_->radius_;
+ agent->timeHorizon_ = defaultAgent_->timeHorizon_;
+ agent->timeHorizonObst_ = defaultAgent_->timeHorizonObst_;
+ agent->velocity_ = defaultAgent_->velocity_;
+
+ agent->id_ = agents_.size();
+
+ agents_.push_back(agent);
+
+ return agents_.size() - 1;
+ }
+
+ size_t RVOSimulator2D::addAgent(const Vector2 &position, float neighborDist, size_t maxNeighbors, float timeHorizon, float timeHorizonObst, float radius, float maxSpeed, const Vector2 &velocity)
+ {
+ Agent2D *agent = new Agent2D();
+
+ agent->position_ = position;
+ agent->maxNeighbors_ = maxNeighbors;
+ agent->maxSpeed_ = maxSpeed;
+ agent->neighborDist_ = neighborDist;
+ agent->radius_ = radius;
+ agent->timeHorizon_ = timeHorizon;
+ agent->timeHorizonObst_ = timeHorizonObst;
+ agent->velocity_ = velocity;
+
+ agent->id_ = agents_.size();
+
+ agents_.push_back(agent);
+
+ return agents_.size() - 1;
+ }
+
+ size_t RVOSimulator2D::addObstacle(const std::vector<Vector2> &vertices)
+ {
+ if (vertices.size() < 2) {
+ return RVO2D_ERROR;
+ }
+
+ const size_t obstacleNo = obstacles_.size();
+
+ for (size_t i = 0; i < vertices.size(); ++i) {
+ Obstacle2D *obstacle = new Obstacle2D();
+ obstacle->point_ = vertices[i];
+
+ if (i != 0) {
+ obstacle->prevObstacle_ = obstacles_.back();
+ obstacle->prevObstacle_->nextObstacle_ = obstacle;
+ }
+
+ if (i == vertices.size() - 1) {
+ obstacle->nextObstacle_ = obstacles_[obstacleNo];
+ obstacle->nextObstacle_->prevObstacle_ = obstacle;
+ }
+
+ obstacle->unitDir_ = normalize(vertices[(i == vertices.size() - 1 ? 0 : i + 1)] - vertices[i]);
+
+ if (vertices.size() == 2) {
+ obstacle->isConvex_ = true;
+ }
+ else {
+ obstacle->isConvex_ = (leftOf(vertices[(i == 0 ? vertices.size() - 1 : i - 1)], vertices[i], vertices[(i == vertices.size() - 1 ? 0 : i + 1)]) >= 0.0f);
+ }
+
+ obstacle->id_ = obstacles_.size();
+
+ obstacles_.push_back(obstacle);
+ }
+
+ return obstacleNo;
+ }
+
+ void RVOSimulator2D::doStep()
+ {
+ kdTree_->buildAgentTree(agents_);
+
+ for (int i = 0; i < static_cast<int>(agents_.size()); ++i) {
+ agents_[i]->computeNeighbors(this);
+ agents_[i]->computeNewVelocity(this);
+ }
+
+ for (int i = 0; i < static_cast<int>(agents_.size()); ++i) {
+ agents_[i]->update(this);
+ }
+
+ globalTime_ += timeStep_;
+ }
+
+ size_t RVOSimulator2D::getAgentAgentNeighbor(size_t agentNo, size_t neighborNo) const
+ {
+ return agents_[agentNo]->agentNeighbors_[neighborNo].second->id_;
+ }
+
+ size_t RVOSimulator2D::getAgentMaxNeighbors(size_t agentNo) const
+ {
+ return agents_[agentNo]->maxNeighbors_;
+ }
+
+ float RVOSimulator2D::getAgentMaxSpeed(size_t agentNo) const
+ {
+ return agents_[agentNo]->maxSpeed_;
+ }
+
+ float RVOSimulator2D::getAgentNeighborDist(size_t agentNo) const
+ {
+ return agents_[agentNo]->neighborDist_;
+ }
+
+ size_t RVOSimulator2D::getAgentNumAgentNeighbors(size_t agentNo) const
+ {
+ return agents_[agentNo]->agentNeighbors_.size();
+ }
+
+ size_t RVOSimulator2D::getAgentNumObstacleNeighbors(size_t agentNo) const
+ {
+ return agents_[agentNo]->obstacleNeighbors_.size();
+ }
+
+ size_t RVOSimulator2D::getAgentNumORCALines(size_t agentNo) const
+ {
+ return agents_[agentNo]->orcaLines_.size();
+ }
+
+ size_t RVOSimulator2D::getAgentObstacleNeighbor(size_t agentNo, size_t neighborNo) const
+ {
+ return agents_[agentNo]->obstacleNeighbors_[neighborNo].second->id_;
+ }
+
+ const Line &RVOSimulator2D::getAgentORCALine(size_t agentNo, size_t lineNo) const
+ {
+ return agents_[agentNo]->orcaLines_[lineNo];
+ }
+
+ const Vector2 &RVOSimulator2D::getAgentPosition(size_t agentNo) const
+ {
+ return agents_[agentNo]->position_;
+ }
+
+ const Vector2 &RVOSimulator2D::getAgentPrefVelocity(size_t agentNo) const
+ {
+ return agents_[agentNo]->prefVelocity_;
+ }
+
+ float RVOSimulator2D::getAgentRadius(size_t agentNo) const
+ {
+ return agents_[agentNo]->radius_;
+ }
+
+ float RVOSimulator2D::getAgentTimeHorizon(size_t agentNo) const
+ {
+ return agents_[agentNo]->timeHorizon_;
+ }
+
+ float RVOSimulator2D::getAgentTimeHorizonObst(size_t agentNo) const
+ {
+ return agents_[agentNo]->timeHorizonObst_;
+ }
+
+ const Vector2 &RVOSimulator2D::getAgentVelocity(size_t agentNo) const
+ {
+ return agents_[agentNo]->velocity_;
+ }
+
+ float RVOSimulator2D::getGlobalTime() const
+ {
+ return globalTime_;
+ }
+
+ size_t RVOSimulator2D::getNumAgents() const
+ {
+ return agents_.size();
+ }
+
+ size_t RVOSimulator2D::getNumObstacleVertices() const
+ {
+ return obstacles_.size();
+ }
+
+ const Vector2 &RVOSimulator2D::getObstacleVertex(size_t vertexNo) const
+ {
+ return obstacles_[vertexNo]->point_;
+ }
+
+ size_t RVOSimulator2D::getNextObstacleVertexNo(size_t vertexNo) const
+ {
+ return obstacles_[vertexNo]->nextObstacle_->id_;
+ }
+
+ size_t RVOSimulator2D::getPrevObstacleVertexNo(size_t vertexNo) const
+ {
+ return obstacles_[vertexNo]->prevObstacle_->id_;
+ }
+
+ float RVOSimulator2D::getTimeStep() const
+ {
+ return timeStep_;
+ }
+
+ void RVOSimulator2D::processObstacles()
+ {
+ kdTree_->buildObstacleTree(obstacles_);
+ }
+
+ bool RVOSimulator2D::queryVisibility(const Vector2 &point1, const Vector2 &point2, float radius) const
+ {
+ return kdTree_->queryVisibility(point1, point2, radius);
+ }
+
+ void RVOSimulator2D::setAgentDefaults(float neighborDist, size_t maxNeighbors, float timeHorizon, float timeHorizonObst, float radius, float maxSpeed, const Vector2 &velocity)
+ {
+ if (defaultAgent_ == NULL) {
+ defaultAgent_ = new Agent2D();
+ }
+
+ defaultAgent_->maxNeighbors_ = maxNeighbors;
+ defaultAgent_->maxSpeed_ = maxSpeed;
+ defaultAgent_->neighborDist_ = neighborDist;
+ defaultAgent_->radius_ = radius;
+ defaultAgent_->timeHorizon_ = timeHorizon;
+ defaultAgent_->timeHorizonObst_ = timeHorizonObst;
+ defaultAgent_->velocity_ = velocity;
+ }
+
+ void RVOSimulator2D::setAgentMaxNeighbors(size_t agentNo, size_t maxNeighbors)
+ {
+ agents_[agentNo]->maxNeighbors_ = maxNeighbors;
+ }
+
+ void RVOSimulator2D::setAgentMaxSpeed(size_t agentNo, float maxSpeed)
+ {
+ agents_[agentNo]->maxSpeed_ = maxSpeed;
+ }
+
+ void RVOSimulator2D::setAgentNeighborDist(size_t agentNo, float neighborDist)
+ {
+ agents_[agentNo]->neighborDist_ = neighborDist;
+ }
+
+ void RVOSimulator2D::setAgentPosition(size_t agentNo, const Vector2 &position)
+ {
+ agents_[agentNo]->position_ = position;
+ }
+
+ void RVOSimulator2D::setAgentPrefVelocity(size_t agentNo, const Vector2 &prefVelocity)
+ {
+ agents_[agentNo]->prefVelocity_ = prefVelocity;
+ }
+
+ void RVOSimulator2D::setAgentRadius(size_t agentNo, float radius)
+ {
+ agents_[agentNo]->radius_ = radius;
+ }
+
+ void RVOSimulator2D::setAgentTimeHorizon(size_t agentNo, float timeHorizon)
+ {
+ agents_[agentNo]->timeHorizon_ = timeHorizon;
+ }
+
+ void RVOSimulator2D::setAgentTimeHorizonObst(size_t agentNo, float timeHorizonObst)
+ {
+ agents_[agentNo]->timeHorizonObst_ = timeHorizonObst;
+ }
+
+ void RVOSimulator2D::setAgentVelocity(size_t agentNo, const Vector2 &velocity)
+ {
+ agents_[agentNo]->velocity_ = velocity;
+ }
+
+ void RVOSimulator2D::setTimeStep(float timeStep)
+ {
+ timeStep_ = timeStep;
+ }
+}
diff --git a/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.h b/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.h
index 638c357437..e074e0fe0e 100644
--- a/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.h
+++ b/thirdparty/rvo2/rvo2_2d/RVOSimulator2d.h
@@ -1,15 +1,14 @@
/*
- * RVOSimulator.h
+ * RVOSimulator2d.h
* RVO2 Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,638 +27,566 @@
* Chapel Hill, N.C. 27599-3175
* United States of America
*
- * <https://gamma.cs.unc.edu/RVO2/>
+ * <http://gamma.cs.unc.edu/RVO2/>
*/
#ifndef RVO2D_RVO_SIMULATOR_H_
#define RVO2D_RVO_SIMULATOR_H_
/**
- * @file RVOSimulator2d.h
- * @brief Declares and defines the RVOSimulator2D class.
+ * \file RVOSimulator2d.h
+ * \brief Contains the RVOSimulator2D class.
*/
#include <cstddef>
+#include <limits>
#include <vector>
+#include "Vector2.h"
namespace RVO2D {
-class Agent2D;
-class KdTree2D;
-class Line;
-class Obstacle2D;
-class Vector2;
-
-/**
- * @relates RVOSimulator2D
- * @brief Error value. A value equal to the largest unsigned integer that is
- * returned in case of an error by functions in RVO::RVOSimulator.
- */
-extern const std::size_t RVO2D_ERROR;
-
-/**
- * @brief Defines the simulation. The main class of the library that contains
- * all simulation functionality.
- */
-class RVOSimulator2D {
- public:
- /**
- * @brief Constructs a simulator instance.
- */
- RVOSimulator2D();
-
- /**
- * @brief Constructs a simulator instance and sets the default
- * properties for any new agent that is added.
- * @param[in] timeStep The time step of the simulation. Must be
- * positive.
- * @param[in] neighborDist The default maximum distance center-point to
- * center-point to other agents a new agent takes
- * into account in the navigation. The larger this
- * number, the longer he running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe. Must be
- * non-negative.
- * @param[in] maxNeighbors The default maximum number of other agents a
- * new agent takes into account in the navigation.
- * The larger this number, the longer the running
- * time of the simulation. If the number is too
- * low, the simulation will not be safe.
- * @param[in] timeHorizon The default minimal amount of time for which a
- * new agent's velocities that are computed by the
- * simulation are safe with respect to other
- * agents. The larger this number, the sooner an
- * agent will respond to the presence of other
- * agents, but the less freedom the agent has in
- * choosing its velocities. Must be positive.
- * @param[in] timeHorizonObst The default minimal amount of time for which a
- * new agent's velocities that are computed by the
- * simulation are safe with respect to obstacles.
- * The larger this number, the sooner an agent will
- * respond to the presence of obstacles, but the
- * less freedom the agent has in choosing its
- * velocities. Must be positive.
- * @param[in] radius The default radius of a new agent. Must be
- * non-negative.
- * @param[in] maxSpeed The default maximum speed of a new agent. Must
- * be non-negative.
- */
- RVOSimulator2D(float timeStep, float neighborDist, std::size_t maxNeighbors,
- float timeHorizon, float timeHorizonObst, float radius,
- float maxSpeed);
-
- /**
- * @brief Constructs a simulator instance and sets the default properties
- * for any new agent that is added.
- * @param[in] timeStep The time step of the simulation. Must be
- * positive.
- * @param[in] neighborDist The default maximum distance center-point to
- * center-point to other agents a new agent takes
- * into account in the navigation. The larger this
- * number, the longer he running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe. Must be
- * non-negative.
- * @param[in] maxNeighbors The default maximum number of other agents a new
- * agent takes into account in the navigation. The
- * larger this number, the longer the running time
- * of the simulation. If the number is too low, the
- * simulation will not be safe.
- * @param[in] timeHorizon The default minimal amount of time for which a
- * new agent's velocities that are computed by the
- * simulation are safe with respect to other
- * agents. The larger this number, the sooner an
- * agent will respond to the presence of other
- * agents, but the less freedom the agent has in
- * choosing its velocities. Must be positive.
- * @param[in] timeHorizonObst The default minimal amount of time for which a
- * new agent's velocities that are computed by the
- * simulation are safe with respect to obstacles.
- * The larger this number, the sooner an agent will
- * respond to the presence of obstacles, but the
- * less freedom the agent has in choosing its
- * velocities. Must be positive.
- * @param[in] radius The default radius of a new agent. Must be
- * non-negative.
- * @param[in] maxSpeed The default maximum speed of a new agent. Must
- * be non-negative.
- * @param[in] velocity The default initial two-dimensional linear
- * velocity of a new agent.
- */
- RVOSimulator2D(float timeStep, float neighborDist, std::size_t maxNeighbors,
- float timeHorizon, float timeHorizonObst, float radius,
- float maxSpeed, const Vector2 &velocity);
-
- /**
- * @brief Destroys this simulator instance.
- */
- ~RVOSimulator2D();
-
- /**
- * @brief Adds a new agent with default properties to the simulation.
- * @param[in] position The two-dimensional starting position of this agent.
- * @return The number of the agent, or RVO::RVO2D_ERROR when the agent
- * defaults have not been set.
- */
- std::size_t addAgent(const Vector2 &position);
-
- /**
- * @brief Adds a new agent to the simulation.
- * @param[in] position The two-dimensional starting position of this
- * agent.
- * @param[in] neighborDist The maximum distance center-point to
- * center-point to other agents this agent takes
- * into account in the navigation. The larger this
- * number, the longer the running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe. Must be
- * non-negative.
- * @param[in] maxNeighbors The maximum number of other agents this agent
- * takes into account in the navigation. The larger
- * this number, the longer the running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe.
- * @param[in] timeHorizon The minimal amount of time for which this
- * agent's velocities that are computed by the
- * simulation are safe with respect to other
- * agents. The larger this number, the sooner this
- * agent will respond to the presence of other
- * agents, but the less freedom this agent has in
- * choosing its velocities. Must be positive.
- * @param[in] timeHorizonObst The minimal amount of time for which this
- * agent's velocities that are computed by the
- * simulation are safe with respect to obstacles
- * The larger this number, the sooner this agent
- * will respond to the presence of obstacles, but
- * the less freedom this agent has in choosing its
- * velocities. Must be positive.
- * @param[in] radius The radius of this agent. Must be non-negative.
- * @param[in] maxSpeed The maximum speed of this agent. Must be
- * non-negative.
- * @return The number of the agent.
- */
- std::size_t addAgent(const Vector2 &position, float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float timeHorizonObst, float radius, float maxSpeed);
-
- /**
- * @brief Adds a new agent to the simulation.
- * @param[in] position The two-dimensional starting position of this
- * agent.
- * @param[in] neighborDist The maximum distance center-point to
- * center-point to other agents this agent takes
- * into account in the navigation. The larger this
- * number, the longer the running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe. Must be
- * non-negative.
- * @param[in] maxNeighbors The maximum number of other agents this agent
- * takes into account in the navigation. The larger
- * this number, the longer the running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe.
- * @param[in] timeHorizon The minimal amount of time for which this
- * agent's velocities that are computed by the
- * simulation are safe with respect to other
- * agents. The larger this number, the sooner this
- * agent will respond to the presence of other
- * agents, but the less freedom this agent has in
- * choosing its velocities. Must be positive.
- * @param[in] timeHorizonObst The minimal amount of time for which this
- * agent's velocities that are computed by the
- * simulation are safe with respect to obstacles.
- * The larger this number, the sooner this agent
- * will respond to the presence of obstacles, but
- * the less freedom this agent has in choosing its
- * velocities. Must be positive.
- * @param[in] radius The radius of this agent. Must be non-negative.
- * @param[in] maxSpeed The maximum speed of this agent. Must be
- * non-negative.
- * @param[in] velocity The initial two-dimensional linear velocity of
- * this agent.
- * @return The number of the agent.
- */
- std::size_t addAgent(const Vector2 &position, float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float timeHorizonObst, float radius, float maxSpeed,
- const Vector2 &velocity);
-
- /**
- * @brief Adds a new obstacle to the simulation.
- * @param[in] vertices List of the vertices of the polygonal obstacle in
- * counterclockwise order.
- * @return The number of the first vertex of the obstacle, or
- * RVO::RVO2D_ERROR when the number of vertices is less than two.
- * @note To add a "negative" obstacle, e.g., a bounding polygon around
- * the environment, the vertices should be listed in clockwise
- * order.
- */
- std::size_t addObstacle(const std::vector<Vector2> &vertices);
-
- /**
- * @brief Lets the simulator perform a simulation step and updates the
- * two-dimensional position and two-dimensional velocity of each agent.
- */
- void doStep();
-
- /**
- * @brief Returns the specified agent neighbor of the specified agent.
- * @param[in] agentNo The number of the agent whose agent neighbor is to be
- * retrieved.
- * @param[in] neighborNo The number of the agent neighbor to be retrieved.
- * @return The number of the neighboring agent.
- */
- std::size_t getAgentAgentNeighbor(std::size_t agentNo,
- std::size_t neighborNo) const;
-
- /**
- * @brief Returns the maximum neighbor count of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum neighbor count is
- * to be retrieved.
- * @return The present maximum neighbor count of the agent.
- */
- std::size_t getAgentMaxNeighbors(std::size_t agentNo) const;
-
- /**
- * @brief Returns the maximum speed of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum speed is to be
- * retrieved.
- * @return The present maximum speed of the agent.
- */
- float getAgentMaxSpeed(std::size_t agentNo) const;
-
- /**
- * @brief Returns the maximum neighbor distance of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum neighbor distance
- * is to be retrieved.
- * @return The present maximum neighbor distance of the agent.
- */
- float getAgentNeighborDist(std::size_t agentNo) const;
-
- /**
- * @brief Returns the count of agent neighbors taken into account to
- * compute the current velocity for the specified agent.
- * @param[in] agentNo The number of the agent whose count of agent neighbors
- * is to be retrieved.
- * @return The count of agent neighbors taken into account to compute the
- * current velocity for the specified agent.
- */
- std::size_t getAgentNumAgentNeighbors(std::size_t agentNo) const;
-
- /**
- * @brief Returns the count of obstacle neighbors taken into account to
- * compute the current velocity for the specified agent.
- * @param[in] agentNo The number of the agent whose count of obstacle
- * neighbors is to be retrieved.
- * @return The count of obstacle neighbors taken into account to compute
- * the current velocity for the specified agent.
- */
- std::size_t getAgentNumObstacleNeighbors(std::size_t agentNo) const;
-
- /**
- * @brief Returns the count of ORCA constraints used to compute the
- * current velocity for the specified agent.
- * @param[in] agentNo The number of the agent whose count of ORCA constraints
- * is to be retrieved.
- * @return The count of ORCA constraints used to compute the current
- * velocity for the specified agent.
- */
- std::size_t getAgentNumORCALines(std::size_t agentNo) const;
-
- /**
- * @brief Returns the specified obstacle neighbor of the specified agent.
- * @param[in] agentNo The number of the agent whose obstacle neighbor is to
- * be retrieved.
- * @param[in] neighborNo The number of the obstacle neighbor to be retrieved.
- * @return The number of the first vertex of the neighboring obstacle edge.
- */
- std::size_t getAgentObstacleNeighbor(std::size_t agentNo,
- std::size_t neighborNo) const;
-
- /**
- * @brief Returns the specified ORCA constraint of the specified agent.
- * @param[in] agentNo The number of the agent whose ORCA constraint is to be
- * retrieved.
- * @param[in] lineNo The number of the ORCA constraint to be retrieved.
- * @return A line representing the specified ORCA constraint.
- * @note The half-plane to the left of the line is the region of
- * permissible velocities with respect to the specified ORCA
- * constraint.
- */
- const Line &getAgentORCALine(std::size_t agentNo, std::size_t lineNo) const;
-
- /**
- * @brief Returns the two-dimensional position of a specified agent.
- * @param[in] agentNo The number of the agent whose two-dimensional position
- * is to be retrieved.
- * @return The present two-dimensional position of the center of the agent.
- */
- const Vector2 &getAgentPosition(std::size_t agentNo) const;
-
- /**
- * @brief Returns the two-dimensional preferred velocity of a specified
- * agent.
- * @param[in] agentNo The number of the agent whose two-dimensional preferred
- * velocity is to be retrieved.
- * @return The present two-dimensional preferred velocity of the agent.
- */
- const Vector2 &getAgentPrefVelocity(std::size_t agentNo) const;
-
- /**
- * @brief Returns the radius of a specified agent.
- * @param[in] agentNo The number of the agent whose radius is to be retrieved.
- * @return The present radius of the agent.
- */
- float getAgentRadius(std::size_t agentNo) const;
-
- /**
- * @brief Returns the time horizon of a specified agent.
- * @param[in] agentNo The number of the agent whose time horizon is to be
- * retrieved.
- * @return The present time horizon of the agent.
- */
- float getAgentTimeHorizon(std::size_t agentNo) const;
-
- /**
- * @brief Returns the time horizon with respect to obstacles of a
- * specified agent.
- * @param[in] agentNo The number of the agent whose time horizon with respect
- * to obstacles is to be retrieved.
- * @return The present time horizon with respect to obstacles of the agent.
- */
- float getAgentTimeHorizonObst(std::size_t agentNo) const;
-
- /**
- * @brief Returns the two-dimensional linear velocity of a specified
- * agent.
- * @param[in] agentNo The number of the agent whose two-dimensional linear
- * velocity is to be retrieved.
- * @return The present two-dimensional linear velocity of the agent.
- */
- const Vector2 &getAgentVelocity(std::size_t agentNo) const;
-
- /**
- * @brief Returns the global time of the simulation.
- * @return The present global time of the simulation (zero initially).
- */
- float getGlobalTime() const { return globalTime_; }
-
- /**
- * @brief Returns the count of agents in the simulation.
- * @return The count of agents in the simulation.
- */
- std::size_t getNumAgents() const { return agents_.size(); }
-
- /**
- * @brief Returns the count of obstacle vertices in the simulation.
- * @return The count of obstacle vertices in the simulation.
- */
- std::size_t getNumObstacleVertices() const { return obstacles_.size(); }
-
- /**
- * @brief Returns the two-dimensional position of a specified obstacle
- * vertex.
- * @param[in] vertexNo The number of the obstacle vertex to be retrieved.
- * @return The two-dimensional position of the specified obstacle vertex.
- */
- const Vector2 &getObstacleVertex(std::size_t vertexNo) const;
-
- /**
- * @brief Returns the number of the obstacle vertex succeeding the
- * specified obstacle vertex in its polygon.
- * @param[in] vertexNo The number of the obstacle vertex whose successor is to
- * be retrieved.
- * @return The number of the obstacle vertex succeeding the specified
- * obstacle vertex in its polygon.
- */
- std::size_t getNextObstacleVertexNo(std::size_t vertexNo) const;
-
- /**
- * @brief Returns the number of the obstacle vertex preceding the
- * specified obstacle vertex in its polygon.
- * @param[in] vertexNo The number of the obstacle vertex whose predecessor is
- * to be retrieved.
- * @return The number of the obstacle vertex preceding the specified
- * obstacle vertex in its polygon.
- */
- std::size_t getPrevObstacleVertexNo(std::size_t vertexNo) const;
-
- /**
- * @brief Returns the time step of the simulation.
- * @return The present time step of the simulation.
- */
- float getTimeStep() const { return timeStep_; }
-
- /**
- * @brief Processes the obstacles that have been added so that they are
- * accounted for in the simulation.
- * @note Obstacles added to the simulation after this function has been
- * called are not accounted for in the simulation.
- */
- void processObstacles();
-
- /**
- * @brief Performs a visibility query between the two specified points
- * with respect to the obstacles
- * @param[in] point1 The first point of the query.
- * @param[in] point2 The second point of the query.
- * @return A boolean specifying whether the two points are mutually
- * visible. Returns true when the obstacles have not been
- * processed.
- */
- bool queryVisibility(const Vector2 &point1, const Vector2 &point2) const;
-
- /**
- * @brief Performs a visibility query between the two specified points
- * with respect to the obstacles
- * @param[in] point1 The first point of the query.
- * @param[in] point2 The second point of the query.
- * @param[in] radius The minimal distance between the line connecting the two
- * points and the obstacles in order for the points to be
- * mutually visible. Must be non-negative.
- * @return A boolean specifying whether the two points are mutually
- * visible. Returns true when the obstacles have not been
- * processed.
- */
- bool queryVisibility(const Vector2 &point1, const Vector2 &point2,
- float radius) const;
-
- /**
- * @brief Sets the default properties for any new agent that is added.
- * @param[in] neighborDist The default maximum distance center-point to
- * center-point to other agents a new agent takes
- * into account in the navigation. The larger this
- * number, the longer he running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe. Must be
- * non-negative.
- * @param[in] maxNeighbors The default maximum number of other agents a new
- * agent takes into account in the navigation. The
- * larger this number, the longer the running time
- * of the simulation. If the number is too low, the
- * simulation will not be safe.
- * @param[in] timeHorizon The default minimal amount of time for which a
- * new agent's velocities that are computed by the
- * simulation are safe with respect to other
- * agents. The larger this number, the sooner an
- * agent will respond to the presence of other
- * agents, but the less freedom the agent has in
- * choosing its velocities. Must be positive.
- * @param[in] timeHorizonObst The default minimal amount of time for which a
- * new agent's velocities that are computed by the
- * simulation are safe with respect to obstacles.
- * The larger this number, the sooner an agent will
- * respond to the presence of obstacles, but the
- * less freedom the agent has in choosing its
- * velocities. Must be positive.
- * @param[in] radius The default radius of a new agent. Must be
- * non-negative.
- * @param[in] maxSpeed The default maximum speed of a new agent. Must
- * be non-negative.
- */
- void setAgentDefaults(float neighborDist, std::size_t maxNeighbors,
- float timeHorizon, float timeHorizonObst, float radius,
- float maxSpeed);
-
- /**
- * @brief Sets the default properties for any new agent that is added.
- * @param[in] neighborDist The default maximum distance center-point to
- * center-point to other agents a new agent takes
- * into account in the navigation. The larger this
- * number, the longer he running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe. Must be
- * non-negative.
- * @param[in] maxNeighbors The default maximum number of other agents a new
- * agent takes into account in the navigation. The
- * larger this number, the longer the running time
- * of the simulation. If the number is too low, the
- * simulation will not be safe.
- * @param[in] timeHorizon The default minimal amount of time for which a
- * new agent's velocities that are computed by the
- * simulation are safe with respect to other
- * agents. The larger this number, the sooner an
- * agent will respond to the presence of other
- * agents, but the less freedom the agent has in
- * choosing its velocities. Must be positive.
- * @param[in] timeHorizonObst The default minimal amount of time for which a
- * new agent's velocities that are computed by the
- * simulation are safe with respect to obstacles.
- * The larger this number, the sooner an agent will
- * respond to the presence of obstacles, but the
- * less freedom the agent has in choosing its
- * velocities. Must be positive.
- * @param[in] radius The default radius of a new agent. Must be
- * non-negative.
- * @param[in] maxSpeed The default maximum speed of a new agent. Must
- * be non-negative.
- * @param[in] velocity The default initial two-dimensional linear
- * velocity of a new agent.
- */
- void setAgentDefaults(float neighborDist, std::size_t maxNeighbors,
- float timeHorizon, float timeHorizonObst, float radius,
- float maxSpeed, const Vector2 &velocity);
-
- /**
- * @brief Sets the maximum neighbor count of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum neighbor
- * count is to be modified.
- * @param[in] maxNeighbors The replacement maximum neighbor count.
- */
- void setAgentMaxNeighbors(std::size_t agentNo, std::size_t maxNeighbors);
-
- /**
- * @brief Sets the maximum speed of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum speed is to be
- * modified.
- * @param[in] maxSpeed The replacement maximum speed. Must be non-negative.
- */
- void setAgentMaxSpeed(std::size_t agentNo, float maxSpeed);
-
- /**
- * @brief Sets the maximum neighbor distance of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum neighbor
- * distance is to be modified.
- * @param[in] neighborDist The replacement maximum neighbor distance. Must be
- * non-negative.
- */
- void setAgentNeighborDist(std::size_t agentNo, float neighborDist);
-
- /**
- * @brief Sets the two-dimensional position of a specified agent.
- * @param[in] agentNo The number of the agent whose two-dimensional position
- * is to be modified.
- * @param[in] position The replacement of the two-dimensional position.
- */
- void setAgentPosition(std::size_t agentNo, const Vector2 &position);
-
- /**
- * @brief Sets the two-dimensional preferred velocity of a specified
- * agent.
- * @param[in] agentNo The number of the agent whose two-dimensional
- * preferred velocity is to be modified.
- * @param[in] prefVelocity The replacement of the two-dimensional preferred
- * velocity.
- */
- void setAgentPrefVelocity(std::size_t agentNo, const Vector2 &prefVelocity);
-
- /**
- * @brief Sets the radius of a specified agent.
- * @param[in] agentNo The number of the agent whose radius is to be modified.
- * @param[in] radius The replacement radius. Must be non-negative.
- */
- void setAgentRadius(std::size_t agentNo, float radius);
-
- /**
- * @brief Sets the time horizon of a specified agent with respect to other
- * agents.
- * @param[in] agentNo The number of the agent whose time horizon is to be
- * modified.
- * @param[in] timeHorizon The replacement time horizon with respect to other
- * agents. Must be positive.
- */
- void setAgentTimeHorizon(std::size_t agentNo, float timeHorizon);
-
- /**
- * @brief Sets the time horizon of a specified agent with respect to
- * obstacles.
- * @param[in] agentNo The number of the agent whose time horizon with
- * respect to obstacles is to be modified.
- * @param[in] timeHorizonObst The replacement time horizon with respect to
- * obstacles. Must be positive.
- */
- void setAgentTimeHorizonObst(std::size_t agentNo, float timeHorizonObst);
-
- /**
- * @brief Sets the two-dimensional linear velocity of a specified agent.
- * @param[in] agentNo The number of the agent whose two-dimensional linear
- * velocity is to be modified.
- * @param[in] velocity The replacement two-dimensional linear velocity.
- */
- void setAgentVelocity(std::size_t agentNo, const Vector2 &velocity);
-
- /**
- * @brief Sets the time step of the simulation.
- * @param[in] timeStep The time step of the simulation. Must be positive.
- */
- void setTimeStep(float timeStep) { timeStep_ = timeStep; }
-
- public:
- /* Not implemented. */
- RVOSimulator2D(const RVOSimulator2D &other);
-
- /* Not implemented. */
- RVOSimulator2D &operator=(const RVOSimulator2D &other);
-
- std::vector<Agent2D *> agents_;
- std::vector<Obstacle2D *> obstacles_;
- Agent2D *defaultAgent_;
- KdTree2D *kdTree_;
- float globalTime_;
- float timeStep_;
-
- friend class KdTree2D;
-};
-} /* namespace RVO2D */
+ /**
+ * \brief Error value.
+ *
+ * A value equal to the largest unsigned integer that is returned in case
+ * of an error by functions in RVO2D::RVOSimulator2D.
+ */
+ const size_t RVO2D_ERROR = std::numeric_limits<size_t>::max();
+
+ /**
+ * \brief Defines a directed line.
+ */
+ class Line {
+ public:
+ /**
+ * \brief A point on the directed line.
+ */
+ Vector2 point;
+
+ /**
+ * \brief The direction of the directed line.
+ */
+ Vector2 direction;
+ };
+
+ class Agent2D;
+ class KdTree2D;
+ class Obstacle2D;
+
+ /**
+ * \brief Defines the simulation.
+ *
+ * The main class of the library that contains all simulation functionality.
+ */
+ class RVOSimulator2D {
+ public:
+ /**
+ * \brief Constructs a simulator instance.
+ */
+ RVOSimulator2D();
+
+ /**
+ * \brief Constructs a simulator instance and sets the default
+ * properties for any new agent that is added.
+ * \param timeStep The time step of the simulation.
+ * Must be positive.
+ * \param neighborDist The default maximum distance (center point
+ * to center point) to other agents a new agent
+ * takes into account in the navigation. The
+ * larger this number, the longer he running
+ * time of the simulation. If the number is too
+ * low, the simulation will not be safe. Must be
+ * non-negative.
+ * \param maxNeighbors The default maximum number of other agents a
+ * new agent takes into account in the
+ * navigation. The larger this number, the
+ * longer the running time of the simulation.
+ * If the number is too low, the simulation
+ * will not be safe.
+ * \param timeHorizon The default minimal amount of time for which
+ * a new agent's velocities that are computed
+ * by the simulation are safe with respect to
+ * other agents. The larger this number, the
+ * sooner an agent will respond to the presence
+ * of other agents, but the less freedom the
+ * agent has in choosing its velocities.
+ * Must be positive.
+ * \param timeHorizonObst The default minimal amount of time for which
+ * a new agent's velocities that are computed
+ * by the simulation are safe with respect to
+ * obstacles. The larger this number, the
+ * sooner an agent will respond to the presence
+ * of obstacles, but the less freedom the agent
+ * has in choosing its velocities.
+ * Must be positive.
+ * \param radius The default radius of a new agent.
+ * Must be non-negative.
+ * \param maxSpeed The default maximum speed of a new agent.
+ * Must be non-negative.
+ * \param velocity The default initial two-dimensional linear
+ * velocity of a new agent (optional).
+ */
+ RVOSimulator2D(float timeStep, float neighborDist, size_t maxNeighbors,
+ float timeHorizon, float timeHorizonObst, float radius,
+ float maxSpeed, const Vector2 &velocity = Vector2());
+
+ /**
+ * \brief Destroys this simulator instance.
+ */
+ ~RVOSimulator2D();
+
+ /**
+ * \brief Adds a new agent with default properties to the
+ * simulation.
+ * \param position The two-dimensional starting position of
+ * this agent.
+ * \return The number of the agent, or RVO2D::RVO2D_ERROR when the agent
+ * defaults have not been set.
+ */
+ size_t addAgent(const Vector2 &position);
+
+ /**
+ * \brief Adds a new agent to the simulation.
+ * \param position The two-dimensional starting position of
+ * this agent.
+ * \param neighborDist The maximum distance (center point to
+ * center point) to other agents this agent
+ * takes into account in the navigation. The
+ * larger this number, the longer the running
+ * time of the simulation. If the number is too
+ * low, the simulation will not be safe.
+ * Must be non-negative.
+ * \param maxNeighbors The maximum number of other agents this
+ * agent takes into account in the navigation.
+ * The larger this number, the longer the
+ * running time of the simulation. If the
+ * number is too low, the simulation will not
+ * be safe.
+ * \param timeHorizon The minimal amount of time for which this
+ * agent's velocities that are computed by the
+ * simulation are safe with respect to other
+ * agents. The larger this number, the sooner
+ * this agent will respond to the presence of
+ * other agents, but the less freedom this
+ * agent has in choosing its velocities.
+ * Must be positive.
+ * \param timeHorizonObst The minimal amount of time for which this
+ * agent's velocities that are computed by the
+ * simulation are safe with respect to
+ * obstacles. The larger this number, the
+ * sooner this agent will respond to the
+ * presence of obstacles, but the less freedom
+ * this agent has in choosing its velocities.
+ * Must be positive.
+ * \param radius The radius of this agent.
+ * Must be non-negative.
+ * \param maxSpeed The maximum speed of this agent.
+ * Must be non-negative.
+ * \param velocity The initial two-dimensional linear velocity
+ * of this agent (optional).
+ * \return The number of the agent.
+ */
+ size_t addAgent(const Vector2 &position, float neighborDist,
+ size_t maxNeighbors, float timeHorizon,
+ float timeHorizonObst, float radius, float maxSpeed,
+ const Vector2 &velocity = Vector2());
+
+ /**
+ * \brief Adds a new obstacle to the simulation.
+ * \param vertices List of the vertices of the polygonal
+ * obstacle in counterclockwise order.
+ * \return The number of the first vertex of the obstacle,
+ * or RVO2D::RVO2D_ERROR when the number of vertices is less than two.
+ * \note To add a "negative" obstacle, e.g. a bounding polygon around
+ * the environment, the vertices should be listed in clockwise
+ * order.
+ */
+ size_t addObstacle(const std::vector<Vector2> &vertices);
+
+ /**
+ * \brief Lets the simulator perform a simulation step and updates the
+ * two-dimensional position and two-dimensional velocity of
+ * each agent.
+ */
+ void doStep();
+
+ /**
+ * \brief Returns the specified agent neighbor of the specified
+ * agent.
+ * \param agentNo The number of the agent whose agent
+ * neighbor is to be retrieved.
+ * \param neighborNo The number of the agent neighbor to be
+ * retrieved.
+ * \return The number of the neighboring agent.
+ */
+ size_t getAgentAgentNeighbor(size_t agentNo, size_t neighborNo) const;
+
+ /**
+ * \brief Returns the maximum neighbor count of a specified agent.
+ * \param agentNo The number of the agent whose maximum
+ * neighbor count is to be retrieved.
+ * \return The present maximum neighbor count of the agent.
+ */
+ size_t getAgentMaxNeighbors(size_t agentNo) const;
+
+ /**
+ * \brief Returns the maximum speed of a specified agent.
+ * \param agentNo The number of the agent whose maximum speed
+ * is to be retrieved.
+ * \return The present maximum speed of the agent.
+ */
+ float getAgentMaxSpeed(size_t agentNo) const;
+
+ /**
+ * \brief Returns the maximum neighbor distance of a specified
+ * agent.
+ * \param agentNo The number of the agent whose maximum
+ * neighbor distance is to be retrieved.
+ * \return The present maximum neighbor distance of the agent.
+ */
+ float getAgentNeighborDist(size_t agentNo) const;
+
+ /**
+ * \brief Returns the count of agent neighbors taken into account to
+ * compute the current velocity for the specified agent.
+ * \param agentNo The number of the agent whose count of agent
+ * neighbors is to be retrieved.
+ * \return The count of agent neighbors taken into account to compute
+ * the current velocity for the specified agent.
+ */
+ size_t getAgentNumAgentNeighbors(size_t agentNo) const;
+
+ /**
+ * \brief Returns the count of obstacle neighbors taken into account
+ * to compute the current velocity for the specified agent.
+ * \param agentNo The number of the agent whose count of
+ * obstacle neighbors is to be retrieved.
+ * \return The count of obstacle neighbors taken into account to
+ * compute the current velocity for the specified agent.
+ */
+ size_t getAgentNumObstacleNeighbors(size_t agentNo) const;
+
+
+ /**
+ * \brief Returns the count of ORCA constraints used to compute
+ * the current velocity for the specified agent.
+ * \param agentNo The number of the agent whose count of ORCA
+ * constraints is to be retrieved.
+ * \return The count of ORCA constraints used to compute the current
+ * velocity for the specified agent.
+ */
+ size_t getAgentNumORCALines(size_t agentNo) const;
+
+ /**
+ * \brief Returns the specified obstacle neighbor of the specified
+ * agent.
+ * \param agentNo The number of the agent whose obstacle
+ * neighbor is to be retrieved.
+ * \param neighborNo The number of the obstacle neighbor to be
+ * retrieved.
+ * \return The number of the first vertex of the neighboring obstacle
+ * edge.
+ */
+ size_t getAgentObstacleNeighbor(size_t agentNo, size_t neighborNo) const;
+
+ /**
+ * \brief Returns the specified ORCA constraint of the specified
+ * agent.
+ * \param agentNo The number of the agent whose ORCA
+ * constraint is to be retrieved.
+ * \param lineNo The number of the ORCA constraint to be
+ * retrieved.
+ * \return A line representing the specified ORCA constraint.
+ * \note The halfplane to the left of the line is the region of
+ * permissible velocities with respect to the specified
+ * ORCA constraint.
+ */
+ const Line &getAgentORCALine(size_t agentNo, size_t lineNo) const;
+
+ /**
+ * \brief Returns the two-dimensional position of a specified
+ * agent.
+ * \param agentNo The number of the agent whose
+ * two-dimensional position is to be retrieved.
+ * \return The present two-dimensional position of the (center of the)
+ * agent.
+ */
+ const Vector2 &getAgentPosition(size_t agentNo) const;
+
+ /**
+ * \brief Returns the two-dimensional preferred velocity of a
+ * specified agent.
+ * \param agentNo The number of the agent whose
+ * two-dimensional preferred velocity is to be
+ * retrieved.
+ * \return The present two-dimensional preferred velocity of the agent.
+ */
+ const Vector2 &getAgentPrefVelocity(size_t agentNo) const;
+
+ /**
+ * \brief Returns the radius of a specified agent.
+ * \param agentNo The number of the agent whose radius is to
+ * be retrieved.
+ * \return The present radius of the agent.
+ */
+ float getAgentRadius(size_t agentNo) const;
+
+ /**
+ * \brief Returns the time horizon of a specified agent.
+ * \param agentNo The number of the agent whose time horizon
+ * is to be retrieved.
+ * \return The present time horizon of the agent.
+ */
+ float getAgentTimeHorizon(size_t agentNo) const;
+
+ /**
+ * \brief Returns the time horizon with respect to obstacles of a
+ * specified agent.
+ * \param agentNo The number of the agent whose time horizon
+ * with respect to obstacles is to be
+ * retrieved.
+ * \return The present time horizon with respect to obstacles of the
+ * agent.
+ */
+ float getAgentTimeHorizonObst(size_t agentNo) const;
+
+ /**
+ * \brief Returns the two-dimensional linear velocity of a
+ * specified agent.
+ * \param agentNo The number of the agent whose
+ * two-dimensional linear velocity is to be
+ * retrieved.
+ * \return The present two-dimensional linear velocity of the agent.
+ */
+ const Vector2 &getAgentVelocity(size_t agentNo) const;
+
+ /**
+ * \brief Returns the global time of the simulation.
+ * \return The present global time of the simulation (zero initially).
+ */
+ float getGlobalTime() const;
+
+ /**
+ * \brief Returns the count of agents in the simulation.
+ * \return The count of agents in the simulation.
+ */
+ size_t getNumAgents() const;
+
+ /**
+ * \brief Returns the count of obstacle vertices in the simulation.
+ * \return The count of obstacle vertices in the simulation.
+ */
+ size_t getNumObstacleVertices() const;
+
+ /**
+ * \brief Returns the two-dimensional position of a specified obstacle
+ * vertex.
+ * \param vertexNo The number of the obstacle vertex to be
+ * retrieved.
+ * \return The two-dimensional position of the specified obstacle
+ * vertex.
+ */
+ const Vector2 &getObstacleVertex(size_t vertexNo) const;
+
+ /**
+ * \brief Returns the number of the obstacle vertex succeeding the
+ * specified obstacle vertex in its polygon.
+ * \param vertexNo The number of the obstacle vertex whose
+ * successor is to be retrieved.
+ * \return The number of the obstacle vertex succeeding the specified
+ * obstacle vertex in its polygon.
+ */
+ size_t getNextObstacleVertexNo(size_t vertexNo) const;
+
+ /**
+ * \brief Returns the number of the obstacle vertex preceding the
+ * specified obstacle vertex in its polygon.
+ * \param vertexNo The number of the obstacle vertex whose
+ * predecessor is to be retrieved.
+ * \return The number of the obstacle vertex preceding the specified
+ * obstacle vertex in its polygon.
+ */
+ size_t getPrevObstacleVertexNo(size_t vertexNo) const;
+
+ /**
+ * \brief Returns the time step of the simulation.
+ * \return The present time step of the simulation.
+ */
+ float getTimeStep() const;
+
+ /**
+ * \brief Processes the obstacles that have been added so that they
+ * are accounted for in the simulation.
+ * \note Obstacles added to the simulation after this function has
+ * been called are not accounted for in the simulation.
+ */
+ void processObstacles();
+
+ /**
+ * \brief Performs a visibility query between the two specified
+ * points with respect to the obstacles
+ * \param point1 The first point of the query.
+ * \param point2 The second point of the query.
+ * \param radius The minimal distance between the line
+ * connecting the two points and the obstacles
+ * in order for the points to be mutually
+ * visible (optional). Must be non-negative.
+ * \return A boolean specifying whether the two points are mutually
+ * visible. Returns true when the obstacles have not been
+ * processed.
+ */
+ bool queryVisibility(const Vector2 &point1, const Vector2 &point2,
+ float radius = 0.0f) const;
+
+ /**
+ * \brief Sets the default properties for any new agent that is
+ * added.
+ * \param neighborDist The default maximum distance (center point
+ * to center point) to other agents a new agent
+ * takes into account in the navigation. The
+ * larger this number, the longer he running
+ * time of the simulation. If the number is too
+ * low, the simulation will not be safe.
+ * Must be non-negative.
+ * \param maxNeighbors The default maximum number of other agents a
+ * new agent takes into account in the
+ * navigation. The larger this number, the
+ * longer the running time of the simulation.
+ * If the number is too low, the simulation
+ * will not be safe.
+ * \param timeHorizon The default minimal amount of time for which
+ * a new agent's velocities that are computed
+ * by the simulation are safe with respect to
+ * other agents. The larger this number, the
+ * sooner an agent will respond to the presence
+ * of other agents, but the less freedom the
+ * agent has in choosing its velocities.
+ * Must be positive.
+ * \param timeHorizonObst The default minimal amount of time for which
+ * a new agent's velocities that are computed
+ * by the simulation are safe with respect to
+ * obstacles. The larger this number, the
+ * sooner an agent will respond to the presence
+ * of obstacles, but the less freedom the agent
+ * has in choosing its velocities.
+ * Must be positive.
+ * \param radius The default radius of a new agent.
+ * Must be non-negative.
+ * \param maxSpeed The default maximum speed of a new agent.
+ * Must be non-negative.
+ * \param velocity The default initial two-dimensional linear
+ * velocity of a new agent (optional).
+ */
+ void setAgentDefaults(float neighborDist, size_t maxNeighbors,
+ float timeHorizon, float timeHorizonObst,
+ float radius, float maxSpeed,
+ const Vector2 &velocity = Vector2());
+
+ /**
+ * \brief Sets the maximum neighbor count of a specified agent.
+ * \param agentNo The number of the agent whose maximum
+ * neighbor count is to be modified.
+ * \param maxNeighbors The replacement maximum neighbor count.
+ */
+ void setAgentMaxNeighbors(size_t agentNo, size_t maxNeighbors);
+
+ /**
+ * \brief Sets the maximum speed of a specified agent.
+ * \param agentNo The number of the agent whose maximum speed
+ * is to be modified.
+ * \param maxSpeed The replacement maximum speed. Must be
+ * non-negative.
+ */
+ void setAgentMaxSpeed(size_t agentNo, float maxSpeed);
+
+ /**
+ * \brief Sets the maximum neighbor distance of a specified agent.
+ * \param agentNo The number of the agent whose maximum
+ * neighbor distance is to be modified.
+ * \param neighborDist The replacement maximum neighbor distance.
+ * Must be non-negative.
+ */
+ void setAgentNeighborDist(size_t agentNo, float neighborDist);
+
+ /**
+ * \brief Sets the two-dimensional position of a specified agent.
+ * \param agentNo The number of the agent whose
+ * two-dimensional position is to be modified.
+ * \param position The replacement of the two-dimensional
+ * position.
+ */
+ void setAgentPosition(size_t agentNo, const Vector2 &position);
+
+ /**
+ * \brief Sets the two-dimensional preferred velocity of a
+ * specified agent.
+ * \param agentNo The number of the agent whose
+ * two-dimensional preferred velocity is to be
+ * modified.
+ * \param prefVelocity The replacement of the two-dimensional
+ * preferred velocity.
+ */
+ void setAgentPrefVelocity(size_t agentNo, const Vector2 &prefVelocity);
+
+ /**
+ * \brief Sets the radius of a specified agent.
+ * \param agentNo The number of the agent whose radius is to
+ * be modified.
+ * \param radius The replacement radius.
+ * Must be non-negative.
+ */
+ void setAgentRadius(size_t agentNo, float radius);
+
+ /**
+ * \brief Sets the time horizon of a specified agent with respect
+ * to other agents.
+ * \param agentNo The number of the agent whose time horizon
+ * is to be modified.
+ * \param timeHorizon The replacement time horizon with respect
+ * to other agents. Must be positive.
+ */
+ void setAgentTimeHorizon(size_t agentNo, float timeHorizon);
+
+ /**
+ * \brief Sets the time horizon of a specified agent with respect
+ * to obstacles.
+ * \param agentNo The number of the agent whose time horizon
+ * with respect to obstacles is to be modified.
+ * \param timeHorizonObst The replacement time horizon with respect to
+ * obstacles. Must be positive.
+ */
+ void setAgentTimeHorizonObst(size_t agentNo, float timeHorizonObst);
+
+ /**
+ * \brief Sets the two-dimensional linear velocity of a specified
+ * agent.
+ * \param agentNo The number of the agent whose
+ * two-dimensional linear velocity is to be
+ * modified.
+ * \param velocity The replacement two-dimensional linear
+ * velocity.
+ */
+ void setAgentVelocity(size_t agentNo, const Vector2 &velocity);
+
+ /**
+ * \brief Sets the time step of the simulation.
+ * \param timeStep The time step of the simulation.
+ * Must be positive.
+ */
+ void setTimeStep(float timeStep);
+
+ public:
+ std::vector<Agent2D *> agents_;
+ Agent2D *defaultAgent_;
+ float globalTime_;
+ KdTree2D *kdTree_;
+ std::vector<Obstacle2D *> obstacles_;
+ float timeStep_;
+
+ friend class Agent2D;
+ friend class KdTree2D;
+ friend class Obstacle2D;
+ };
+}
#endif /* RVO2D_RVO_SIMULATOR_H_ */
diff --git a/thirdparty/rvo2/rvo2_2d/Vector2.cc b/thirdparty/rvo2/rvo2_2d/Vector2.cc
deleted file mode 100644
index 303e4c8fdd..0000000000
--- a/thirdparty/rvo2/rvo2_2d/Vector2.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Vector2.cpp
- * RVO2 Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-/**
- * @file Vector2.cc
- * @brief Defines the Vector2 class.
- */
-
-#include "Vector2.h"
-
-#include <cmath>
-#include <ostream>
-
-namespace RVO2D {
-const float RVO2D_EPSILON = 0.00001F;
-
-Vector2::Vector2() : x_(0.0F), y_(0.0F) {}
-
-Vector2::Vector2(float x, float y) : x_(x), y_(y) {}
-
-Vector2 Vector2::operator-() const { return Vector2(-x_, -y_); }
-
-float Vector2::operator*(const Vector2 &vector) const {
- return x_ * vector.x_ + y_ * vector.y_;
-}
-
-Vector2 Vector2::operator*(float scalar) const {
- return Vector2(x_ * scalar, y_ * scalar);
-}
-
-Vector2 Vector2::operator/(float scalar) const {
- const float invScalar = 1.0F / scalar;
-
- return Vector2(x_ * invScalar, y_ * invScalar);
-}
-
-Vector2 Vector2::operator+(const Vector2 &vector) const {
- return Vector2(x_ + vector.x_, y_ + vector.y_);
-}
-
-Vector2 Vector2::operator-(const Vector2 &vector) const {
- return Vector2(x_ - vector.x_, y_ - vector.y_);
-}
-
-bool Vector2::operator==(const Vector2 &vector) const {
- return x_ == vector.x_ && y_ == vector.y_;
-}
-
-bool Vector2::operator!=(const Vector2 &vector) const {
- return x_ != vector.x_ || y_ != vector.y_;
-}
-
-Vector2 &Vector2::operator*=(float scalar) {
- x_ *= scalar;
- y_ *= scalar;
-
- return *this;
-}
-
-Vector2 &Vector2::operator/=(float scalar) {
- const float invScalar = 1.0F / scalar;
- x_ *= invScalar;
- y_ *= invScalar;
-
- return *this;
-}
-
-Vector2 &Vector2::operator+=(const Vector2 &vector) {
- x_ += vector.x_;
- y_ += vector.y_;
-
- return *this;
-}
-
-Vector2 &Vector2::operator-=(const Vector2 &vector) {
- x_ -= vector.x_;
- y_ -= vector.y_;
-
- return *this;
-}
-
-Vector2 operator*(float scalar, const Vector2 &vector) {
- return Vector2(scalar * vector.x(), scalar * vector.y());
-}
-
-std::ostream &operator<<(std::ostream &stream, const Vector2 &vector) {
- stream << "(" << vector.x() << "," << vector.y() << ")";
-
- return stream;
-}
-
-float abs(const Vector2 &vector) { return std::sqrt(vector * vector); }
-
-float absSq(const Vector2 &vector) { return vector * vector; }
-
-float det(const Vector2 &vector1, const Vector2 &vector2) {
- return vector1.x() * vector2.y() - vector1.y() * vector2.x();
-}
-
-float leftOf(const Vector2 &vector1, const Vector2 &vector2,
- const Vector2 &vector3) {
- return det(vector1 - vector3, vector2 - vector1);
-}
-
-Vector2 normalize(const Vector2 &vector) { return vector / abs(vector); }
-} /* namespace RVO */
diff --git a/thirdparty/rvo2/rvo2_2d/Vector2.h b/thirdparty/rvo2/rvo2_2d/Vector2.h
index 0cc76f2ba1..24353e09f3 100644
--- a/thirdparty/rvo2/rvo2_2d/Vector2.h
+++ b/thirdparty/rvo2/rvo2_2d/Vector2.h
@@ -2,14 +2,13 @@
* Vector2.h
* RVO2 Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,246 +27,320 @@
* Chapel Hill, N.C. 27599-3175
* United States of America
*
- * <https://gamma.cs.unc.edu/RVO2/>
+ * <http://gamma.cs.unc.edu/RVO2/>
*/
#ifndef RVO_VECTOR2_H_
#define RVO_VECTOR2_H_
/**
- * @file Vector2.h
- * @brief Declares and defines the Vector2 class.
+ * \file Vector2.h
+ * \brief Contains the Vector2 class.
*/
-#include <iosfwd>
+#include <cmath>
+#include <ostream>
namespace RVO2D {
-/**
- * @brief A sufficiently small positive number.
- */
-extern const float RVO2D_EPSILON;
+ /**
+ * \brief Defines a two-dimensional vector.
+ */
+ class Vector2 {
+ public:
+ /**
+ * \brief Constructs and initializes a two-dimensional vector instance
+ * to (0.0, 0.0).
+ */
+ inline Vector2() : x_(0.0f), y_(0.0f) { }
-/**
- * @brief Defines a two-dimensional vector.
- */
-class Vector2 {
- public:
- /**
- * @brief Constructs and initializes a two-dimensional vector instance to
- * (0.0, 0.0).
- */
- Vector2();
-
- /**
- * @brief Constructs and initializes a two-dimensional vector from the
- * specified xy-coordinates.
- * @param[in] x The x-coordinate of the two-dimensional vector.
- * @param[in] y The y-coordinate of the two-dimensional vector.
- */
- Vector2(float x, float y);
-
- /**
- * @brief Returns the x-coordinate of this two-dimensional vector.
- * @return The x-coordinate of the two-dimensional vector.
- */
- float x() const { return x_; }
-
- /**
- * @brief Returns the y-coordinate of this two-dimensional vector.
- * @return The y-coordinate of the two-dimensional vector.
- */
- float y() const { return y_; }
-
- /**
- * @brief Computes the negation of this two-dimensional vector.
- * @return The negation of this two-dimensional vector.
- */
- Vector2 operator-() const;
-
- /**
- * @brief Computes the dot product of this two-dimensional vector with the
- * specified two-dimensional vector.
- * @param[in] vector The two-dimensional vector with which the dot product
- * should be computed.
- * @return The dot product of this two-dimensional vector with a specified
- * two-dimensional vector.
- */
- float operator*(const Vector2 &vector) const;
-
- /**
- * @brief Computes the scalar multiplication of this two-dimensional
- * vector with the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar multiplication
- * should be computed.
- * @return The scalar multiplication of this two-dimensional vector with a
- * specified scalar value.
- */
- Vector2 operator*(float scalar) const;
-
- /**
- * @brief Computes the scalar division of this two-dimensional vector with
- * the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar division should be
- * computed.
- * @return The scalar division of this two-dimensional vector with a
- * specified scalar value.
- */
- Vector2 operator/(float scalar) const;
-
- /**
- * @brief Computes the vector sum of this two-dimensional vector with the
- * specified two-dimensional vector.
- * @param[in] vector The two-dimensional vector with which the vector sum
- * should be computed.
- * @return The vector sum of this two-dimensional vector with a specified
- * two-dimensional vector.
- */
- Vector2 operator+(const Vector2 &vector) const;
-
- /**
- * @brief Computes the vector difference of this two-dimensional vector
- * with the specified two-dimensional vector.
- * @param[in] vector The two-dimensional vector with which the vector
- * difference should be computed.
- * @return The vector difference of this two-dimensional vector with a
- * specified two-dimensional vector.
- */
- Vector2 operator-(const Vector2 &vector) const;
-
- /**
- * @brief Tests this two-dimensional vector for equality with the
- * specified two-dimensional vector.
- * @param[in] vector The two-dimensional vector with which to test for
- * equality.
- * @return True if the two-dimensional vectors are equal.
- */
- bool operator==(const Vector2 &vector) const;
-
- /**
- * @brief Tests this two-dimensional vector for inequality with the
- * specified two-dimensional vector.
- * @param[in] vector The two-dimensional vector with which to test for
- * inequality.
- * @return True if the two-dimensional vectors are not equal.
- */
- bool operator!=(const Vector2 &vector) const;
-
- /**
- * @brief Sets the value of this two-dimensional vector to the scalar
- * multiplication of itself with the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar multiplication
- * should be computed.
- * @return A reference to this two-dimensional vector.
- */
- Vector2 &operator*=(float scalar);
-
- /**
- * @brief Sets the value of this two-dimensional vector to the scalar
- * division of itself with the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar division should be
- * computed.
- * @return A reference to this two-dimensional vector.
- */
- Vector2 &operator/=(float scalar);
-
- /**
- * @brief Sets the value of this two-dimensional vector to the vector sum
- * of itself with the specified two-dimensional vector.
- * @param[in] vector The two-dimensional vector with which the vector sum
- * should be computed.
- * @return A reference to this two-dimensional vector.
- */
- Vector2 &operator+=(const Vector2 &vector);
-
- /**
- * @brief Sets the value of this two-dimensional vector to the vector
- * difference of itself with the specified two-dimensional vector.
- * @param[in] vector The two-dimensional vector with which the vector
- * difference should be computed.
- * @return A reference to this two-dimensional vector.
- */
- Vector2 &operator-=(const Vector2 &vector);
-
- private:
- float x_;
- float y_;
-};
+ /**
+ * \brief Constructs and initializes a two-dimensional vector from
+ * the specified xy-coordinates.
+ * \param x The x-coordinate of the two-dimensional
+ * vector.
+ * \param y The y-coordinate of the two-dimensional
+ * vector.
+ */
+ inline Vector2(float x, float y) : x_(x), y_(y) { }
-/**
- * @relates Vector2
- * @brief Computes the scalar multiplication of the specified
- * two-dimensional vector with the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar multiplication
- * should be computed.
- * @param[in] vector The two-dimensional vector with which the scalar
- * multiplication should be computed.
- * @return The scalar multiplication of the two-dimensional vector with the
- * scalar value.
- */
- Vector2 operator*(float scalar, const Vector2 &vector);
+ inline Vector2(const Vector2 &vector)
+ {
+ x_ = vector.x();
+ y_ = vector.y();
+ }
-/**
- * @relates Vector2
- * @brief Inserts the specified two-dimensional vector into the
- * specified output stream.
- * @param[in, out] stream The output stream into which the two-dimensional
- * vector should be inserted.
- * @param[in] vector The two-dimensional vector which to insert into the
- * output stream.
- * @return A reference to the output stream.
- */
- std::ostream &operator<<(std::ostream &stream,
- const Vector2 &vector);
+ /**
+ * \brief Returns the x-coordinate of this two-dimensional vector.
+ * \return The x-coordinate of the two-dimensional vector.
+ */
+ inline float x() const { return x_; }
-/**
- * @relates Vector2
- * @brief Computes the length of a specified two-dimensional vector.
- * @param[in] vector The two-dimensional vector whose length is to be computed.
- * @return The length of the two-dimensional vector.
- */
- float abs(const Vector2 &vector);
+ /**
+ * \brief Returns the y-coordinate of this two-dimensional vector.
+ * \return The y-coordinate of the two-dimensional vector.
+ */
+ inline float y() const { return y_; }
-/**
- * @relates Vector2
- * @brief Computes the squared length of a specified two-dimensional vector.
- * @param[in] vector The two-dimensional vector whose squared length is to be
- * computed.
- * @return The squared length of the two-dimensional vector.
- */
- float absSq(const Vector2 &vector);
+ /**
+ * \brief Computes the negation of this two-dimensional vector.
+ * \return The negation of this two-dimensional vector.
+ */
+ inline Vector2 operator-() const
+ {
+ return Vector2(-x_, -y_);
+ }
-/**
- * @relates Vector2
- * @brief Computes the determinant of a two-dimensional square matrix with
- * rows consisting of the specified two-dimensional vectors.
- * @param[in] vector1 The top row of the two-dimensional square matrix.
- * @param[in] vector2 The bottom row of the two-dimensional square matrix.
- * @return The determinant of the two-dimensional square matrix.
- */
- float det(const Vector2 &vector1, const Vector2 &vector2);
+ /**
+ * \brief Computes the dot product of this two-dimensional vector with
+ * the specified two-dimensional vector.
+ * \param vector The two-dimensional vector with which the
+ * dot product should be computed.
+ * \return The dot product of this two-dimensional vector with a
+ * specified two-dimensional vector.
+ */
+ inline float operator*(const Vector2 &vector) const
+ {
+ return x_ * vector.x() + y_ * vector.y();
+ }
-/**
- * @brief Computes the signed distance from a line connecting th specified
- * points to a specified point.
- * @param[in] vector1 The first point on the line.
- * @param[in] vector2 The second point on the line.
- * @param[in] vector3 The point to which the signed distance is to be
- * calculated.
- * @return Positive when the point vector3 lies to the left of the line
- * vector1-vector2.
- */
- float leftOf(const Vector2 &vector1, const Vector2 &vector2,
- const Vector2 &vector3);
+ /**
+ * \brief Computes the scalar multiplication of this
+ * two-dimensional vector with the specified scalar value.
+ * \param s The scalar value with which the scalar
+ * multiplication should be computed.
+ * \return The scalar multiplication of this two-dimensional vector
+ * with a specified scalar value.
+ */
+ inline Vector2 operator*(float s) const
+ {
+ return Vector2(x_ * s, y_ * s);
+ }
-/**
- * @relates Vector2
- * @brief Computes the normalization of the specified two-dimensional
- * vector.
- * @param[in] vector The two-dimensional vector whose normalization is to be
- * computed.
- * @return The normalization of the two-dimensional vector.
- */
- Vector2 normalize(const Vector2 &vector);
-} /* namespace RVO2D */
+ /**
+ * \brief Computes the scalar division of this two-dimensional vector
+ * with the specified scalar value.
+ * \param s The scalar value with which the scalar
+ * division should be computed.
+ * \return The scalar division of this two-dimensional vector with a
+ * specified scalar value.
+ */
+ inline Vector2 operator/(float s) const
+ {
+ const float invS = 1.0f / s;
+
+ return Vector2(x_ * invS, y_ * invS);
+ }
+
+ /**
+ * \brief Computes the vector sum of this two-dimensional vector with
+ * the specified two-dimensional vector.
+ * \param vector The two-dimensional vector with which the
+ * vector sum should be computed.
+ * \return The vector sum of this two-dimensional vector with a
+ * specified two-dimensional vector.
+ */
+ inline Vector2 operator+(const Vector2 &vector) const
+ {
+ return Vector2(x_ + vector.x(), y_ + vector.y());
+ }
+
+ /**
+ * \brief Computes the vector difference of this two-dimensional
+ * vector with the specified two-dimensional vector.
+ * \param vector The two-dimensional vector with which the
+ * vector difference should be computed.
+ * \return The vector difference of this two-dimensional vector with a
+ * specified two-dimensional vector.
+ */
+ inline Vector2 operator-(const Vector2 &vector) const
+ {
+ return Vector2(x_ - vector.x(), y_ - vector.y());
+ }
+
+ /**
+ * \brief Tests this two-dimensional vector for equality with the
+ * specified two-dimensional vector.
+ * \param vector The two-dimensional vector with which to
+ * test for equality.
+ * \return True if the two-dimensional vectors are equal.
+ */
+ inline bool operator==(const Vector2 &vector) const
+ {
+ return x_ == vector.x() && y_ == vector.y();
+ }
+
+ /**
+ * \brief Tests this two-dimensional vector for inequality with the
+ * specified two-dimensional vector.
+ * \param vector The two-dimensional vector with which to
+ * test for inequality.
+ * \return True if the two-dimensional vectors are not equal.
+ */
+ inline bool operator!=(const Vector2 &vector) const
+ {
+ return x_ != vector.x() || y_ != vector.y();
+ }
+
+ /**
+ * \brief Sets the value of this two-dimensional vector to the scalar
+ * multiplication of itself with the specified scalar value.
+ * \param s The scalar value with which the scalar
+ * multiplication should be computed.
+ * \return A reference to this two-dimensional vector.
+ */
+ inline Vector2 &operator*=(float s)
+ {
+ x_ *= s;
+ y_ *= s;
+
+ return *this;
+ }
+
+ /**
+ * \brief Sets the value of this two-dimensional vector to the scalar
+ * division of itself with the specified scalar value.
+ * \param s The scalar value with which the scalar
+ * division should be computed.
+ * \return A reference to this two-dimensional vector.
+ */
+ inline Vector2 &operator/=(float s)
+ {
+ const float invS = 1.0f / s;
+ x_ *= invS;
+ y_ *= invS;
+
+ return *this;
+ }
+
+ /**
+ * \brief Sets the value of this two-dimensional vector to the vector
+ * sum of itself with the specified two-dimensional vector.
+ * \param vector The two-dimensional vector with which the
+ * vector sum should be computed.
+ * \return A reference to this two-dimensional vector.
+ */
+ inline Vector2 &operator+=(const Vector2 &vector)
+ {
+ x_ += vector.x();
+ y_ += vector.y();
+
+ return *this;
+ }
+
+ /**
+ * \brief Sets the value of this two-dimensional vector to the vector
+ * difference of itself with the specified two-dimensional
+ * vector.
+ * \param vector The two-dimensional vector with which the
+ * vector difference should be computed.
+ * \return A reference to this two-dimensional vector.
+ */
+ inline Vector2 &operator-=(const Vector2 &vector)
+ {
+ x_ -= vector.x();
+ y_ -= vector.y();
+
+ return *this;
+ }
+
+ inline Vector2 &operator=(const Vector2 &vector)
+ {
+ x_ = vector.x();
+ y_ = vector.y();
+
+ return *this;
+ }
+
+ private:
+ float x_;
+ float y_;
+ };
+
+ /**
+ * \relates Vector2
+ * \brief Computes the scalar multiplication of the specified
+ * two-dimensional vector with the specified scalar value.
+ * \param s The scalar value with which the scalar
+ * multiplication should be computed.
+ * \param vector The two-dimensional vector with which the scalar
+ * multiplication should be computed.
+ * \return The scalar multiplication of the two-dimensional vector with the
+ * scalar value.
+ */
+ inline Vector2 operator*(float s, const Vector2 &vector)
+ {
+ return Vector2(s * vector.x(), s * vector.y());
+ }
+
+ /**
+ * \relates Vector2
+ * \brief Inserts the specified two-dimensional vector into the specified
+ * output stream.
+ * \param os The output stream into which the two-dimensional
+ * vector should be inserted.
+ * \param vector The two-dimensional vector which to insert into
+ * the output stream.
+ * \return A reference to the output stream.
+ */
+ inline std::ostream &operator<<(std::ostream &os, const Vector2 &vector)
+ {
+ os << "(" << vector.x() << "," << vector.y() << ")";
+
+ return os;
+ }
+
+ /**
+ * \relates Vector2
+ * \brief Computes the length of a specified two-dimensional vector.
+ * \param vector The two-dimensional vector whose length is to be
+ * computed.
+ * \return The length of the two-dimensional vector.
+ */
+ inline float abs(const Vector2 &vector)
+ {
+ return std::sqrt(vector * vector);
+ }
+
+ /**
+ * \relates Vector2
+ * \brief Computes the squared length of a specified two-dimensional
+ * vector.
+ * \param vector The two-dimensional vector whose squared length
+ * is to be computed.
+ * \return The squared length of the two-dimensional vector.
+ */
+ inline float absSq(const Vector2 &vector)
+ {
+ return vector * vector;
+ }
+
+ /**
+ * \relates Vector2
+ * \brief Computes the determinant of a two-dimensional square matrix with
+ * rows consisting of the specified two-dimensional vectors.
+ * \param vector1 The top row of the two-dimensional square
+ * matrix.
+ * \param vector2 The bottom row of the two-dimensional square
+ * matrix.
+ * \return The determinant of the two-dimensional square matrix.
+ */
+ inline float det(const Vector2 &vector1, const Vector2 &vector2)
+ {
+ return vector1.x() * vector2.y() - vector1.y() * vector2.x();
+ }
+
+ /**
+ * \relates Vector2
+ * \brief Computes the normalization of the specified two-dimensional
+ * vector.
+ * \param vector The two-dimensional vector whose normalization
+ * is to be computed.
+ * \return The normalization of the two-dimensional vector.
+ */
+ inline Vector2 normalize(const Vector2 &vector)
+ {
+ return vector / abs(vector);
+ }
+}
#endif /* RVO_VECTOR2_H_ */
diff --git a/thirdparty/rvo2/rvo2_3d/Agent3d.cc b/thirdparty/rvo2/rvo2_3d/Agent3d.cc
deleted file mode 100644
index 860ebdc58c..0000000000
--- a/thirdparty/rvo2/rvo2_3d/Agent3d.cc
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Agent3d.cc
- * RVO2-3D Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-#include "Agent3d.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include "KdTree3d.h"
-#include "RVOSimulator3d.h"
-
-namespace RVO3D {
-namespace {
-/**
- * @brief A sufficiently small positive number.
- */
-const float RVO3D_EPSILON = 0.00001F;
-
-/**
- * @brief Defines a directed line.
- */
-class Line3D {
- public:
- /**
- * @brief Constructs a directed line.``
- */
- Line3D();
-
- /**
- * @brief The direction of the directed line.
- */
- Vector3 direction;
-
- /**
- * @brief A point on the directed line.
- */
- Vector3 point;
-};
-
-Line3D::Line3D() {}
-
-/**
- * @brief Solves a one-dimensional linear program on a specified line
- * subject to linear constraints defined by planes and a spherical
- * constraint.
- * @param[in] planes Planes defining the linear constraints.
- * @param[in] planeNo The plane on which the line lies.
- * @param[in] line The line on which the one-dimensional linear program
- * is solved.
- * @param[in] radius The radius of the spherical constraint.
- * @param[in] optVelocity The optimization velocity.
- * @param[in] directionOpt True if the direction should be optimized.
- * @param[in] result A reference to the result of the linear program.
- * @return True if successful.
- */
-bool linearProgram1(const std::vector<Plane> &planes, std::size_t planeNo,
- const Line3D &line, float radius, const Vector3 &optVelocity,
- bool directionOpt,
- Vector3 &result) { /* NOLINT(runtime/references) */
- const float dotProduct = line.point * line.direction;
- const float discriminant =
- dotProduct * dotProduct + radius * radius - absSq(line.point);
-
- if (discriminant < 0.0F) {
- /* Max speed sphere fully invalidates line. */
- return false;
- }
-
- const float sqrtDiscriminant = std::sqrt(discriminant);
- float tLeft = -dotProduct - sqrtDiscriminant;
- float tRight = -dotProduct + sqrtDiscriminant;
-
- for (std::size_t i = 0U; i < planeNo; ++i) {
- const float numerator = (planes[i].point - line.point) * planes[i].normal;
- const float denominator = line.direction * planes[i].normal;
-
- if (denominator * denominator <= RVO3D_EPSILON) {
- /* Lines line is (almost) parallel to plane i. */
- if (numerator > 0.0F) {
- return false;
- }
-
- continue;
- }
-
- const float t = numerator / denominator;
-
- if (denominator >= 0.0F) {
- /* Plane i bounds line on the left. */
- tLeft = std::max(tLeft, t);
- } else {
- /* Plane i bounds line on the right. */
- tRight = std::min(tRight, t);
- }
-
- if (tLeft > tRight) {
- return false;
- }
- }
-
- if (directionOpt) {
- /* Optimize direction. */
- if (optVelocity * line.direction > 0.0F) {
- /* Take right extreme. */
- result = line.point + tRight * line.direction;
- } else {
- /* Take left extreme. */
- result = line.point + tLeft * line.direction;
- }
- } else {
- /* Optimize closest point. */
- const float t = line.direction * (optVelocity - line.point);
-
- if (t < tLeft) {
- result = line.point + tLeft * line.direction;
- } else if (t > tRight) {
- result = line.point + tRight * line.direction;
- } else {
- result = line.point + t * line.direction;
- }
- }
-
- return true;
-}
-
-/**
- * @brief Solves a two-dimensional linear program on a specified plane
- * subject to linear constraints defined by planes and a spherical
- * constraint.
- * @param[in] planes Planes defining the linear constraints.
- * @param[in] planeNo The plane on which the two-dimensional linear
- * program is solved.
- * @param[in] radius The radius of the spherical constraint.
- * @param[in] optVelocity The optimization velocity.
- * @param[in] directionOpt True if the direction should be optimized.
- * @param[out] result A reference to the result of the linear program.
- * @return True if successful.
- */
-bool linearProgram2(const std::vector<Plane> &planes, std::size_t planeNo,
- float radius, const Vector3 &optVelocity, bool directionOpt,
- Vector3 &result) { /* NOLINT(runtime/references) */
- const float planeDist = planes[planeNo].point * planes[planeNo].normal;
- const float planeDistSq = planeDist * planeDist;
- const float radiusSq = radius * radius;
-
- if (planeDistSq > radiusSq) {
- /* Max speed sphere fully invalidates plane planeNo. */
- return false;
- }
-
- const float planeRadiusSq = radiusSq - planeDistSq;
-
- const Vector3 planeCenter = planeDist * planes[planeNo].normal;
-
- if (directionOpt) {
- /* Project direction optVelocity on plane planeNo. */
- const Vector3 planeOptVelocity =
- optVelocity -
- (optVelocity * planes[planeNo].normal) * planes[planeNo].normal;
- const float planeOptVelocityLengthSq = absSq(planeOptVelocity);
-
- if (planeOptVelocityLengthSq <= RVO3D_EPSILON) {
- result = planeCenter;
- } else {
- result =
- planeCenter + std::sqrt(planeRadiusSq / planeOptVelocityLengthSq) *
- planeOptVelocity;
- }
- } else {
- /* Project point optVelocity on plane planeNo. */
- result = optVelocity +
- ((planes[planeNo].point - optVelocity) * planes[planeNo].normal) *
- planes[planeNo].normal;
-
- /* If outside planeCircle, project on planeCircle. */
- if (absSq(result) > radiusSq) {
- const Vector3 planeResult = result - planeCenter;
- const float planeResultLengthSq = absSq(planeResult);
- result = planeCenter +
- std::sqrt(planeRadiusSq / planeResultLengthSq) * planeResult;
- }
- }
-
- for (std::size_t i = 0U; i < planeNo; ++i) {
- if (planes[i].normal * (planes[i].point - result) > 0.0F) {
- /* Result does not satisfy constraint i. Compute new optimal result.
- * Compute intersection line of plane i and plane planeNo.
- */
- Vector3 crossProduct = cross(planes[i].normal, planes[planeNo].normal);
-
- if (absSq(crossProduct) <= RVO3D_EPSILON) {
- /* Planes planeNo and i are (almost) parallel, and plane i fully
- * invalidates plane planeNo.
- */
- return false;
- }
-
- Line3D line;
- line.direction = normalize(crossProduct);
- const Vector3 lineNormal = cross(line.direction, planes[planeNo].normal);
- line.point =
- planes[planeNo].point +
- (((planes[i].point - planes[planeNo].point) * planes[i].normal) /
- (lineNormal * planes[i].normal)) *
- lineNormal;
-
- if (!linearProgram1(planes, i, line, radius, optVelocity, directionOpt,
- result)) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-/**
- * @brief Solves a three-dimensional linear program subject to linear
- * constraints defined by planes and a spherical constraint.
- * @param[in] planes Planes defining the linear constraints.
- * @param[in] radius The radius of the spherical constraint.
- * @param[in] optVelocity The optimization velocity.
- * @param[in] directionOpt True if the direction should be optimized.
- * @param[out] result A reference to the result of the linear program.
- * @return The number of the plane it fails on, and the number of planes if
- * successful.
- */
-std::size_t linearProgram3(const std::vector<Plane> &planes, float radius,
- const Vector3 &optVelocity, bool directionOpt,
- Vector3 &result) { /* NOLINT(runtime/references) */
- if (directionOpt) {
- /* Optimize direction. Note that the optimization velocity is of unit length
- * in this case.
- */
- result = optVelocity * radius;
- } else if (absSq(optVelocity) > radius * radius) {
- /* Optimize closest point and outside circle. */
- result = normalize(optVelocity) * radius;
- } else {
- /* Optimize closest point and inside circle. */
- result = optVelocity;
- }
-
- for (std::size_t i = 0U; i < planes.size(); ++i) {
- if (planes[i].normal * (planes[i].point - result) > 0.0F) {
- /* Result does not satisfy constraint i. Compute new optimal result. */
- const Vector3 tempResult = result;
-
- if (!linearProgram2(planes, i, radius, optVelocity, directionOpt,
- result)) {
- result = tempResult;
- return i;
- }
- }
- }
-
- return planes.size();
-}
-
-/**
- * @brief Solves a four-dimensional linear program subject to linear
- * constraints defined by planes and a spherical constraint.
- * @param[in] planes Planes defining the linear constraints.
- * @param[in] beginPlane The plane on which the three-dimensional linear
- * program failed.
- * @param[in] radius The radius of the spherical constraint.
- * @param[out] result A reference to the result of the linear program.
- */
-void linearProgram4(const std::vector<Plane> &planes, std::size_t beginPlane,
- float radius,
- Vector3 &result) { /* NOLINT(runtime/references) */
- float distance = 0.0F;
-
- for (std::size_t i = beginPlane; i < planes.size(); ++i) {
- if (planes[i].normal * (planes[i].point - result) > distance) {
- /* Result does not satisfy constraint of plane i. */
- std::vector<Plane> projPlanes;
-
- for (std::size_t j = 0U; j < i; ++j) {
- Plane plane;
-
- const Vector3 crossProduct = cross(planes[j].normal, planes[i].normal);
-
- if (absSq(crossProduct) <= RVO3D_EPSILON) {
- /* Plane i and plane j are (almost) parallel. */
- if (planes[i].normal * planes[j].normal > 0.0F) {
- /* Plane i and plane j point in the same direction. */
- continue;
- }
-
- /* Plane i and plane j point in opposite direction. */
- plane.point = 0.5F * (planes[i].point + planes[j].point);
- } else {
- /* Plane.point is point on line of intersection between plane i and
- * plane j.
- */
- const Vector3 lineNormal = cross(crossProduct, planes[i].normal);
- plane.point =
- planes[i].point +
- (((planes[j].point - planes[i].point) * planes[j].normal) /
- (lineNormal * planes[j].normal)) *
- lineNormal;
- }
-
- plane.normal = normalize(planes[j].normal - planes[i].normal);
- projPlanes.push_back(plane);
- }
-
- const Vector3 tempResult = result;
-
- if (linearProgram3(projPlanes, radius, planes[i].normal, true, result) <
- projPlanes.size()) {
- /* This should in principle not happen. The result is by definition
- * already in the feasible region of this linear program. If it fails,
- * it is due to small floating point error, and the current result is
- * kept.
- */
- result = tempResult;
- }
-
- distance = planes[i].normal * (planes[i].point - result);
- }
- }
-}
-} /* namespace */
-
-Agent3D::Agent3D()
- : id_(0U),
- maxNeighbors_(0U),
- maxSpeed_(0.0F),
- neighborDist_(0.0F),
- radius_(0.0F),
- timeHorizon_(0.0F) {}
-
-Agent3D::~Agent3D() {}
-
-void Agent3D::computeNeighbors(RVOSimulator3D *sim_) {
- agentNeighbors_.clear();
-
- if (maxNeighbors_ > 0) {
- sim_->kdTree_->computeAgentNeighbors(this, neighborDist_ * neighborDist_);
- }
-}
-
-void Agent3D::computeNewVelocity(RVOSimulator3D *sim_) {
- orcaPlanes_.clear();
- const float invTimeHorizon = 1.0F / timeHorizon_;
-
- /* Create agent ORCA planes. */
- for (std::size_t i = 0U; i < agentNeighbors_.size(); ++i) {
- const Agent3D *const other = agentNeighbors_[i].second;
- const Vector3 relativePosition = other->position_ - position_;
- const Vector3 relativeVelocity = velocity_ - other->velocity_;
- const float distSq = absSq(relativePosition);
- const float combinedRadius = radius_ + other->radius_;
- const float combinedRadiusSq = combinedRadius * combinedRadius;
-
- Plane plane;
- Vector3 u;
-
- if (distSq > combinedRadiusSq) {
- /* No collision. */
- const Vector3 w = relativeVelocity - invTimeHorizon * relativePosition;
- /* Vector from cutoff center to relative velocity. */
- const float wLengthSq = absSq(w);
-
- const float dotProduct = w * relativePosition;
-
- if (dotProduct < 0.0F &&
- dotProduct * dotProduct > combinedRadiusSq * wLengthSq) {
- /* Project on cut-off circle. */
- const float wLength = std::sqrt(wLengthSq);
- const Vector3 unitW = w / wLength;
-
- plane.normal = unitW;
- u = (combinedRadius * invTimeHorizon - wLength) * unitW;
- } else {
- /* Project on cone. */
- const float a = distSq;
- const float b = relativePosition * relativeVelocity;
- const float c = absSq(relativeVelocity) -
- absSq(cross(relativePosition, relativeVelocity)) /
- (distSq - combinedRadiusSq);
- const float t = (b + std::sqrt(b * b - a * c)) / a;
- const Vector3 ww = relativeVelocity - t * relativePosition;
- const float wwLength = abs(ww);
- const Vector3 unitWW = ww / wwLength;
-
- plane.normal = unitWW;
- u = (combinedRadius * t - wwLength) * unitWW;
- }
- } else {
- /* Collision. */
- const float invTimeStep = 1.0F / sim_->timeStep_;
- const Vector3 w = relativeVelocity - invTimeStep * relativePosition;
- const float wLength = abs(w);
- const Vector3 unitW = w / wLength;
-
- plane.normal = unitW;
- u = (combinedRadius * invTimeStep - wLength) * unitW;
- }
-
- plane.point = velocity_ + 0.5F * u;
- orcaPlanes_.push_back(plane);
- }
-
- const std::size_t planeFail = linearProgram3(
- orcaPlanes_, maxSpeed_, prefVelocity_, false, newVelocity_);
-
- if (planeFail < orcaPlanes_.size()) {
- linearProgram4(orcaPlanes_, planeFail, maxSpeed_, newVelocity_);
- }
-}
-
-void Agent3D::insertAgentNeighbor(const Agent3D *agent, float &rangeSq) {
- if (this != agent) {
- const float distSq = absSq(position_ - agent->position_);
-
- if (distSq < rangeSq) {
- if (agentNeighbors_.size() < maxNeighbors_) {
- agentNeighbors_.push_back(std::make_pair(distSq, agent));
- }
-
- std::size_t i = agentNeighbors_.size() - 1U;
-
- while (i != 0U && distSq < agentNeighbors_[i - 1U].first) {
- agentNeighbors_[i] = agentNeighbors_[i - 1U];
- --i;
- }
-
- agentNeighbors_[i] = std::make_pair(distSq, agent);
-
- if (agentNeighbors_.size() == maxNeighbors_) {
- rangeSq = agentNeighbors_.back().first;
- }
- }
- }
-}
-
-void Agent3D::update(RVOSimulator3D *sim_) {
- velocity_ = newVelocity_;
- position_ += velocity_ * sim_->timeStep_;
-}
-} /* namespace RVO3D */
diff --git a/thirdparty/rvo2/rvo2_3d/Agent3d.cpp b/thirdparty/rvo2/rvo2_3d/Agent3d.cpp
new file mode 100644
index 0000000000..bddf226db1
--- /dev/null
+++ b/thirdparty/rvo2/rvo2_3d/Agent3d.cpp
@@ -0,0 +1,449 @@
+/*
+ * Agent.cpp
+ * RVO2-3D Library
+ *
+ * Copyright 2008 University of North Carolina at Chapel Hill
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to <geom@cs.unc.edu>.
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ * <https://gamma.cs.unc.edu/RVO2/>
+ */
+
+#include "Agent3d.h"
+
+#include <cmath>
+#include <algorithm>
+
+#include "Definitions.h"
+#include "KdTree3d.h"
+
+namespace RVO3D {
+ /**
+ * \brief A sufficiently small positive number.
+ */
+ const float RVO3D_EPSILON = 0.00001f;
+
+ /**
+ * \brief Defines a directed line.
+ */
+ class Line3D {
+ public:
+ /**
+ * \brief The direction of the directed line.
+ */
+ Vector3 direction;
+
+ /**
+ * \brief A point on the directed line.
+ */
+ Vector3 point;
+ };
+
+ /**
+ * \brief Solves a one-dimensional linear program on a specified line subject to linear constraints defined by planes and a spherical constraint.
+ * \param planes Planes defining the linear constraints.
+ * \param planeNo The plane on which the line lies.
+ * \param line The line on which the 1-d linear program is solved
+ * \param radius The radius of the spherical constraint.
+ * \param optVelocity The optimization velocity.
+ * \param directionOpt True if the direction should be optimized.
+ * \param result A reference to the result of the linear program.
+ * \return True if successful.
+ */
+ bool linearProgram1(const std::vector<Plane> &planes, size_t planeNo, const Line3D &line, float radius, const Vector3 &optVelocity, bool directionOpt, Vector3 &result);
+
+ /**
+ * \brief Solves a two-dimensional linear program on a specified plane subject to linear constraints defined by planes and a spherical constraint.
+ * \param planes Planes defining the linear constraints.
+ * \param planeNo The plane on which the 2-d linear program is solved
+ * \param radius The radius of the spherical constraint.
+ * \param optVelocity The optimization velocity.
+ * \param directionOpt True if the direction should be optimized.
+ * \param result A reference to the result of the linear program.
+ * \return True if successful.
+ */
+ bool linearProgram2(const std::vector<Plane> &planes, size_t planeNo, float radius, const Vector3 &optVelocity, bool directionOpt, Vector3 &result);
+
+ /**
+ * \brief Solves a three-dimensional linear program subject to linear constraints defined by planes and a spherical constraint.
+ * \param planes Planes defining the linear constraints.
+ * \param radius The radius of the spherical constraint.
+ * \param optVelocity The optimization velocity.
+ * \param directionOpt True if the direction should be optimized.
+ * \param result A reference to the result of the linear program.
+ * \return The number of the plane it fails on, and the number of planes if successful.
+ */
+ size_t linearProgram3(const std::vector<Plane> &planes, float radius, const Vector3 &optVelocity, bool directionOpt, Vector3 &result);
+
+ /**
+ * \brief Solves a four-dimensional linear program subject to linear constraints defined by planes and a spherical constraint.
+ * \param planes Planes defining the linear constraints.
+ * \param beginPlane The plane on which the 3-d linear program failed.
+ * \param radius The radius of the spherical constraint.
+ * \param result A reference to the result of the linear program.
+ */
+ void linearProgram4(const std::vector<Plane> &planes, size_t beginPlane, float radius, Vector3 &result);
+
+ Agent3D::Agent3D() : id_(0), maxNeighbors_(0), maxSpeed_(0.0f), neighborDist_(0.0f), radius_(0.0f), timeHorizon_(0.0f) { }
+
+ void Agent3D::computeNeighbors(RVOSimulator3D *sim_)
+ {
+ agentNeighbors_.clear();
+
+ if (maxNeighbors_ > 0) {
+ sim_->kdTree_->computeAgentNeighbors(this, neighborDist_ * neighborDist_);
+ }
+ }
+
+ void Agent3D::computeNewVelocity(RVOSimulator3D *sim_)
+ {
+ orcaPlanes_.clear();
+
+ const float invTimeHorizon = 1.0f / timeHorizon_;
+
+ /* Create agent ORCA planes. */
+ for (size_t i = 0; i < agentNeighbors_.size(); ++i) {
+ const Agent3D *const other = agentNeighbors_[i].second;
+
+ //const float timeHorizon_mod = (avoidance_priority_ - other->avoidance_priority_ + 1.0f) * 0.5f;
+ //const float invTimeHorizon = (1.0f / timeHorizon_) * timeHorizon_mod;
+
+ const Vector3 relativePosition = other->position_ - position_;
+ const Vector3 relativeVelocity = velocity_ - other->velocity_;
+ const float distSq = absSq(relativePosition);
+ const float combinedRadius = radius_ + other->radius_;
+ const float combinedRadiusSq = sqr(combinedRadius);
+
+ Plane plane;
+ Vector3 u;
+
+ if (distSq > combinedRadiusSq) {
+ /* No collision. */
+ const Vector3 w = relativeVelocity - invTimeHorizon * relativePosition;
+ /* Vector from cutoff center to relative velocity. */
+ const float wLengthSq = absSq(w);
+
+ const float dotProduct = w * relativePosition;
+
+ if (dotProduct < 0.0f && sqr(dotProduct) > combinedRadiusSq * wLengthSq) {
+ /* Project on cut-off circle. */
+ const float wLength = std::sqrt(wLengthSq);
+ const Vector3 unitW = w / wLength;
+
+ plane.normal = unitW;
+ u = (combinedRadius * invTimeHorizon - wLength) * unitW;
+ }
+ else {
+ /* Project on cone. */
+ const float a = distSq;
+ const float b = relativePosition * relativeVelocity;
+ const float c = absSq(relativeVelocity) - absSq(cross(relativePosition, relativeVelocity)) / (distSq - combinedRadiusSq);
+ const float t = (b + std::sqrt(sqr(b) - a * c)) / a;
+ const Vector3 w = relativeVelocity - t * relativePosition;
+ const float wLength = abs(w);
+ const Vector3 unitW = w / wLength;
+
+ plane.normal = unitW;
+ u = (combinedRadius * t - wLength) * unitW;
+ }
+ }
+ else {
+ /* Collision. */
+ const float invTimeStep = 1.0f / sim_->timeStep_;
+ const Vector3 w = relativeVelocity - invTimeStep * relativePosition;
+ const float wLength = abs(w);
+ const Vector3 unitW = w / wLength;
+
+ plane.normal = unitW;
+ u = (combinedRadius * invTimeStep - wLength) * unitW;
+ }
+
+ plane.point = velocity_ + 0.5f * u;
+ orcaPlanes_.push_back(plane);
+ }
+
+ const size_t planeFail = linearProgram3(orcaPlanes_, maxSpeed_, prefVelocity_, false, newVelocity_);
+
+ if (planeFail < orcaPlanes_.size()) {
+ linearProgram4(orcaPlanes_, planeFail, maxSpeed_, newVelocity_);
+ }
+ }
+
+ void Agent3D::insertAgentNeighbor(const Agent3D *agent, float &rangeSq)
+ {
+ // no point processing same agent
+ if (this == agent) {
+ return;
+ }
+ // ignore other agent if layers/mask bitmasks have no matching bit
+ if ((avoidance_mask_ & agent->avoidance_layers_) == 0) {
+ return;
+ }
+
+ if (avoidance_priority_ > agent->avoidance_priority_) {
+ return;
+ }
+
+ const float distSq = absSq(position_ - agent->position_);
+
+ if (distSq < rangeSq) {
+ if (agentNeighbors_.size() < maxNeighbors_) {
+ agentNeighbors_.push_back(std::make_pair(distSq, agent));
+ }
+
+ size_t i = agentNeighbors_.size() - 1;
+
+ while (i != 0 && distSq < agentNeighbors_[i - 1].first) {
+ agentNeighbors_[i] = agentNeighbors_[i - 1];
+ --i;
+ }
+
+ agentNeighbors_[i] = std::make_pair(distSq, agent);
+
+ if (agentNeighbors_.size() == maxNeighbors_) {
+ rangeSq = agentNeighbors_.back().first;
+ }
+ }
+ }
+
+ void Agent3D::update(RVOSimulator3D *sim_)
+ {
+ velocity_ = newVelocity_;
+ position_ += velocity_ * sim_->timeStep_;
+ }
+
+ bool linearProgram1(const std::vector<Plane> &planes, size_t planeNo, const Line3D &line, float radius, const Vector3 &optVelocity, bool directionOpt, Vector3 &result)
+ {
+ const float dotProduct = line.point * line.direction;
+ const float discriminant = sqr(dotProduct) + sqr(radius) - absSq(line.point);
+
+ if (discriminant < 0.0f) {
+ /* Max speed sphere fully invalidates line. */
+ return false;
+ }
+
+ const float sqrtDiscriminant = std::sqrt(discriminant);
+ float tLeft = -dotProduct - sqrtDiscriminant;
+ float tRight = -dotProduct + sqrtDiscriminant;
+
+ for (size_t i = 0; i < planeNo; ++i) {
+ const float numerator = (planes[i].point - line.point) * planes[i].normal;
+ const float denominator = line.direction * planes[i].normal;
+
+ if (sqr(denominator) <= RVO3D_EPSILON) {
+ /* Lines3D line is (almost) parallel to plane i. */
+ if (numerator > 0.0f) {
+ return false;
+ }
+ else {
+ continue;
+ }
+ }
+
+ const float t = numerator / denominator;
+
+ if (denominator >= 0.0f) {
+ /* Plane i bounds line on the left. */
+ tLeft = std::max(tLeft, t);
+ }
+ else {
+ /* Plane i bounds line on the right. */
+ tRight = std::min(tRight, t);
+ }
+
+ if (tLeft > tRight) {
+ return false;
+ }
+ }
+
+ if (directionOpt) {
+ /* Optimize direction. */
+ if (optVelocity * line.direction > 0.0f) {
+ /* Take right extreme. */
+ result = line.point + tRight * line.direction;
+ }
+ else {
+ /* Take left extreme. */
+ result = line.point + tLeft * line.direction;
+ }
+ }
+ else {
+ /* Optimize closest point. */
+ const float t = line.direction * (optVelocity - line.point);
+
+ if (t < tLeft) {
+ result = line.point + tLeft * line.direction;
+ }
+ else if (t > tRight) {
+ result = line.point + tRight * line.direction;
+ }
+ else {
+ result = line.point + t * line.direction;
+ }
+ }
+
+ return true;
+ }
+
+ bool linearProgram2(const std::vector<Plane> &planes, size_t planeNo, float radius, const Vector3 &optVelocity, bool directionOpt, Vector3 &result)
+ {
+ const float planeDist = planes[planeNo].point * planes[planeNo].normal;
+ const float planeDistSq = sqr(planeDist);
+ const float radiusSq = sqr(radius);
+
+ if (planeDistSq > radiusSq) {
+ /* Max speed sphere fully invalidates plane planeNo. */
+ return false;
+ }
+
+ const float planeRadiusSq = radiusSq - planeDistSq;
+
+ const Vector3 planeCenter = planeDist * planes[planeNo].normal;
+
+ if (directionOpt) {
+ /* Project direction optVelocity on plane planeNo. */
+ const Vector3 planeOptVelocity = optVelocity - (optVelocity * planes[planeNo].normal) * planes[planeNo].normal;
+ const float planeOptVelocityLengthSq = absSq(planeOptVelocity);
+
+ if (planeOptVelocityLengthSq <= RVO3D_EPSILON) {
+ result = planeCenter;
+ }
+ else {
+ result = planeCenter + std::sqrt(planeRadiusSq / planeOptVelocityLengthSq) * planeOptVelocity;
+ }
+ }
+ else {
+ /* Project point optVelocity on plane planeNo. */
+ result = optVelocity + ((planes[planeNo].point - optVelocity) * planes[planeNo].normal) * planes[planeNo].normal;
+
+ /* If outside planeCircle, project on planeCircle. */
+ if (absSq(result) > radiusSq) {
+ const Vector3 planeResult = result - planeCenter;
+ const float planeResultLengthSq = absSq(planeResult);
+ result = planeCenter + std::sqrt(planeRadiusSq / planeResultLengthSq) * planeResult;
+ }
+ }
+
+ for (size_t i = 0; i < planeNo; ++i) {
+ if (planes[i].normal * (planes[i].point - result) > 0.0f) {
+ /* Result does not satisfy constraint i. Compute new optimal result. */
+ /* Compute intersection line of plane i and plane planeNo. */
+ Vector3 crossProduct = cross(planes[i].normal, planes[planeNo].normal);
+
+ if (absSq(crossProduct) <= RVO3D_EPSILON) {
+ /* Planes planeNo and i are (almost) parallel, and plane i fully invalidates plane planeNo. */
+ return false;
+ }
+
+ Line3D line;
+ line.direction = normalize(crossProduct);
+ const Vector3 lineNormal = cross(line.direction, planes[planeNo].normal);
+ line.point = planes[planeNo].point + (((planes[i].point - planes[planeNo].point) * planes[i].normal) / (lineNormal * planes[i].normal)) * lineNormal;
+
+ if (!linearProgram1(planes, i, line, radius, optVelocity, directionOpt, result)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ size_t linearProgram3(const std::vector<Plane> &planes, float radius, const Vector3 &optVelocity, bool directionOpt, Vector3 &result)
+ {
+ if (directionOpt) {
+ /* Optimize direction. Note that the optimization velocity is of unit length in this case. */
+ result = optVelocity * radius;
+ }
+ else if (absSq(optVelocity) > sqr(radius)) {
+ /* Optimize closest point and outside circle. */
+ result = normalize(optVelocity) * radius;
+ }
+ else {
+ /* Optimize closest point and inside circle. */
+ result = optVelocity;
+ }
+
+ for (size_t i = 0; i < planes.size(); ++i) {
+ if (planes[i].normal * (planes[i].point - result) > 0.0f) {
+ /* Result does not satisfy constraint i. Compute new optimal result. */
+ const Vector3 tempResult = result;
+
+ if (!linearProgram2(planes, i, radius, optVelocity, directionOpt, result)) {
+ result = tempResult;
+ return i;
+ }
+ }
+ }
+
+ return planes.size();
+ }
+
+ void linearProgram4(const std::vector<Plane> &planes, size_t beginPlane, float radius, Vector3 &result)
+ {
+ float distance = 0.0f;
+
+ for (size_t i = beginPlane; i < planes.size(); ++i) {
+ if (planes[i].normal * (planes[i].point - result) > distance) {
+ /* Result does not satisfy constraint of plane i. */
+ std::vector<Plane> projPlanes;
+
+ for (size_t j = 0; j < i; ++j) {
+ Plane plane;
+
+ const Vector3 crossProduct = cross(planes[j].normal, planes[i].normal);
+
+ if (absSq(crossProduct) <= RVO3D_EPSILON) {
+ /* Plane i and plane j are (almost) parallel. */
+ if (planes[i].normal * planes[j].normal > 0.0f) {
+ /* Plane i and plane j point in the same direction. */
+ continue;
+ }
+ else {
+ /* Plane i and plane j point in opposite direction. */
+ plane.point = 0.5f * (planes[i].point + planes[j].point);
+ }
+ }
+ else {
+ /* Plane.point is point on line of intersection between plane i and plane j. */
+ const Vector3 lineNormal = cross(crossProduct, planes[i].normal);
+ plane.point = planes[i].point + (((planes[j].point - planes[i].point) * planes[j].normal) / (lineNormal * planes[j].normal)) * lineNormal;
+ }
+
+ plane.normal = normalize(planes[j].normal - planes[i].normal);
+ projPlanes.push_back(plane);
+ }
+
+ const Vector3 tempResult = result;
+
+ if (linearProgram3(projPlanes, radius, planes[i].normal, true, result) < projPlanes.size()) {
+ /* This should in principle not happen. The result is by definition already in the feasible region of this linear program. If it fails, it is due to small floating point error, and the current result is kept. */
+ result = tempResult;
+ }
+
+ distance = planes[i].normal * (planes[i].point - result);
+ }
+ }
+ }
+}
diff --git a/thirdparty/rvo2/rvo2_3d/Agent3d.h b/thirdparty/rvo2/rvo2_3d/Agent3d.h
index 353d64ce82..d99e3cac66 100644
--- a/thirdparty/rvo2/rvo2_3d/Agent3d.h
+++ b/thirdparty/rvo2/rvo2_3d/Agent3d.h
@@ -1,15 +1,14 @@
/*
- * Agent3d.h
+ * Agent.h
* RVO2-3D Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,97 +27,80 @@
* Chapel Hill, N.C. 27599-3175
* United States of America
*
- * <https://gamma.cs.unc.edu/RVO2/>
+ * <http://gamma.cs.unc.edu/RVO2/>
*/
-#ifndef RVO3D_AGENT_H_
-#define RVO3D_AGENT_H_
-
/**
- * @file Agent3d.h
- * @brief Contains the Agent3D class.
+ * \file Agent.h
+ * \brief Contains the Agent class.
*/
+#ifndef RVO3D_AGENT_H_
+#define RVO3D_AGENT_H_
#include <cstddef>
#include <cstdint>
#include <utility>
#include <vector>
-#include "Plane.h"
+#include "RVOSimulator3d.h"
#include "Vector3.h"
namespace RVO3D {
-class RVOSimulator3D;
-
-/**
- * @brief Defines an agent in the simulation.
- */
-class Agent3D {
- public:
- /**
- * @brief Constructs an agent instance.
- * @param[in] sim The simulator instance.
- */
- explicit Agent3D();
-
- /**
- * @brief Destroys this agent instance.
- */
- ~Agent3D();
-
- /**
- * @brief Computes the neighbors of this agent.
- */
- void computeNeighbors(RVOSimulator3D *sim_);
-
- /**
- * @brief Computes the new velocity of this agent.
- */
- void computeNewVelocity(RVOSimulator3D *sim_);
-
- /**
- * @brief Inserts an agent neighbor into the set of neighbors of this
- * agent.
- * @param[in] agent A pointer to the agent to be inserted.
- * @param[in] rangeSq The squared range around this agent.
- */
- void insertAgentNeighbor(const Agent3D *agent,
- float &rangeSq); /* NOLINT(runtime/references) */
-
- /**
- * @brief Updates the three-dimensional position and three-dimensional
- * velocity of this agent.
- */
- void update(RVOSimulator3D *sim_);;
-
- /* Not implemented. */
- Agent3D(const Agent3D &other);
-
- /* Not implemented. */
- Agent3D &operator=(const Agent3D &other);
-
- Vector3 newVelocity_;
- Vector3 position_;
- Vector3 prefVelocity_;
- Vector3 velocity_;
- RVOSimulator3D *sim_;
- std::size_t id_;
- std::size_t maxNeighbors_;
- float maxSpeed_;
- float neighborDist_;
- float radius_;
- float timeHorizon_;
- float timeHorizonObst_;
- std::vector<std::pair<float, const Agent3D *> > agentNeighbors_;
- std::vector<Plane> orcaPlanes_;
- float height_ = 1.0;
- uint32_t avoidance_layers_ = 1;
- uint32_t avoidance_mask_ = 1;
- float avoidance_priority_ = 1.0;
-
- friend class KdTree3D;
- friend class RVOSimulator3D;
-};
-} /* namespace RVO3D */
+ /**
+ * \brief Defines an agent in the simulation.
+ */
+ class Agent3D {
+ public:
+ /**
+ * \brief Constructs an agent instance.
+ * \param sim The simulator instance.
+ */
+ explicit Agent3D();
+
+ /**
+ * \brief Computes the neighbors of this agent.
+ */
+ void computeNeighbors(RVOSimulator3D *sim_);
+
+ /**
+ * \brief Computes the new velocity of this agent.
+ */
+ void computeNewVelocity(RVOSimulator3D *sim_);
+
+ /**
+ * \brief Inserts an agent neighbor into the set of neighbors of this agent.
+ * \param agent A pointer to the agent to be inserted.
+ * \param rangeSq The squared range around this agent.
+ */
+ void insertAgentNeighbor(const Agent3D *agent, float &rangeSq);
+
+ /**
+ * \brief Updates the three-dimensional position and three-dimensional velocity of this agent.
+ */
+ void update(RVOSimulator3D *sim_);
+
+ Vector3 newVelocity_;
+ Vector3 position_;
+ Vector3 prefVelocity_;
+ Vector3 velocity_;
+ RVOSimulator3D *sim_;
+ size_t id_;
+ size_t maxNeighbors_;
+ float maxSpeed_;
+ float neighborDist_;
+ float radius_;
+ float timeHorizon_;
+ float timeHorizonObst_;
+ std::vector<std::pair<float, const Agent3D *> > agentNeighbors_;
+ std::vector<Plane> orcaPlanes_;
+ float height_ = 1.0;
+ uint32_t avoidance_layers_ = 1;
+ uint32_t avoidance_mask_ = 1;
+ float avoidance_priority_ = 1.0;
+
+ friend class KdTree3D;
+ friend class RVOSimulator3D;
+ };
+}
#endif /* RVO3D_AGENT_H_ */
diff --git a/thirdparty/rvo2/rvo2_3d/Plane.cc b/thirdparty/rvo2/rvo2_3d/Definitions.h
index 24c223fb26..34d1d06e0a 100644
--- a/thirdparty/rvo2/rvo2_3d/Plane.cc
+++ b/thirdparty/rvo2/rvo2_3d/Definitions.h
@@ -1,9 +1,8 @@
/*
- * Plane.cc
+ * Definitions.h
* RVO2-3D Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,8 +30,24 @@
* <https://gamma.cs.unc.edu/RVO2/>
*/
-#include "Plane.h"
+/**
+ * \file Definitions.h
+ * \brief Contains functions and constants used in multiple classes.
+ */
+
+#ifndef RVO3D_DEFINITIONS_H_
+#define RVO3D_DEFINITIONS_H_
namespace RVO3D {
-Plane::Plane() {}
-} /* namespace RVO3D */
+ /**
+ * \brief Computes the square of a float.
+ * \param scalar The float to be squared.
+ * \return The square of the float.
+ */
+ inline float sqr(float scalar)
+ {
+ return scalar * scalar;
+ }
+}
+
+#endif /* RVO3D_DEFINITIONS_H_ */
diff --git a/thirdparty/rvo2/rvo2_3d/KdTree3d.cc b/thirdparty/rvo2/rvo2_3d/KdTree3d.cc
deleted file mode 100644
index ac64d1560a..0000000000
--- a/thirdparty/rvo2/rvo2_3d/KdTree3d.cc
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * KdTree3d.cc
- * RVO2-3D Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-#include "KdTree3d.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "Agent3d.h"
-#include "RVOSimulator3d.h"
-#include "Vector3.h"
-
-namespace RVO3D {
-namespace {
-/**
- * @brief The maximum size of a k-D leaf node.
- */
-const std::size_t RVO3D_MAX_LEAF_SIZE = 10U;
-} /* namespace */
-
-/**
- * @brief Defines an agent k-D tree node.
- */
-class KdTree3D::AgentTreeNode {
- public:
- /**
- * @brief Constructs an agent k-D tree node.
- */
- AgentTreeNode();
-
- /**
- * @brief The beginning node number.
- */
- std::size_t begin;
-
- /**
- * @brief The ending node number.
- */
- std::size_t end;
-
- /**
- * @brief The left node number.
- */
- std::size_t left;
-
- /**
- * @brief The right node number.
- */
- std::size_t right;
-
- /**
- * @brief The maximum coordinates.
- */
- Vector3 maxCoord;
-
- /**
- * @brief The minimum coordinates.
- */
- Vector3 minCoord;
-};
-
-KdTree3D::AgentTreeNode::AgentTreeNode()
- : begin(0U), end(0U), left(0U), right(0U) {}
-
-KdTree3D::KdTree3D(RVOSimulator3D *sim) : sim_(sim) {}
-
-KdTree3D::~KdTree3D() {}
-
-void KdTree3D::buildAgentTree(std::vector<Agent3D *> agents) {
- agents_.swap(agents_);
-
- if (!agents_.empty()) {
- agentTree_.resize(2U * agents_.size() - 1U);
- buildAgentTreeRecursive(0U, agents_.size(), 0U);
- }
-}
-
-void KdTree3D::buildAgentTreeRecursive(std::size_t begin, std::size_t end,
- std::size_t node) {
- agentTree_[node].begin = begin;
- agentTree_[node].end = end;
- agentTree_[node].minCoord = agents_[begin]->position_;
- agentTree_[node].maxCoord = agents_[begin]->position_;
-
- for (std::size_t i = begin + 1U; i < end; ++i) {
- agentTree_[node].maxCoord[0] =
- std::max(agentTree_[node].maxCoord[0], agents_[i]->position_.x());
- agentTree_[node].minCoord[0] =
- std::min(agentTree_[node].minCoord[0], agents_[i]->position_.x());
- agentTree_[node].maxCoord[1] =
- std::max(agentTree_[node].maxCoord[1], agents_[i]->position_.y());
- agentTree_[node].minCoord[1] =
- std::min(agentTree_[node].minCoord[1], agents_[i]->position_.y());
- agentTree_[node].maxCoord[2] =
- std::max(agentTree_[node].maxCoord[2], agents_[i]->position_.z());
- agentTree_[node].minCoord[2] =
- std::min(agentTree_[node].minCoord[2], agents_[i]->position_.z());
- }
-
- if (end - begin > RVO3D_MAX_LEAF_SIZE) {
- /* No leaf node. */
- std::size_t coord = 0U;
-
- if (agentTree_[node].maxCoord[0] - agentTree_[node].minCoord[0] >
- agentTree_[node].maxCoord[1] - agentTree_[node].minCoord[1] &&
- agentTree_[node].maxCoord[0] - agentTree_[node].minCoord[0] >
- agentTree_[node].maxCoord[2] - agentTree_[node].minCoord[2]) {
- coord = 0U;
- } else if (agentTree_[node].maxCoord[1] - agentTree_[node].minCoord[1] >
- agentTree_[node].maxCoord[2] - agentTree_[node].minCoord[2]) {
- coord = 1U;
- } else {
- coord = 2U;
- }
-
- const float splitValue = 0.5F * (agentTree_[node].maxCoord[coord] +
- agentTree_[node].minCoord[coord]);
-
- std::size_t left = begin;
-
- std::size_t right = end;
-
- while (left < right) {
- while (left < right && agents_[left]->position_[coord] < splitValue) {
- ++left;
- }
-
- while (right > left &&
- agents_[right - 1U]->position_[coord] >= splitValue) {
- --right;
- }
-
- if (left < right) {
- std::swap(agents_[left], agents_[right - 1U]);
- ++left;
- --right;
- }
- }
-
- std::size_t leftSize = left - begin;
-
- if (leftSize == 0U) {
- ++leftSize;
- ++left;
- }
-
- agentTree_[node].left = node + 1U;
- agentTree_[node].right = node + 2U * leftSize;
-
- buildAgentTreeRecursive(begin, left, agentTree_[node].left);
- buildAgentTreeRecursive(left, end, agentTree_[node].right);
- }
-}
-
-void KdTree3D::computeAgentNeighbors(Agent3D *agent, float rangeSq) const {
- queryAgentTreeRecursive(agent, rangeSq, 0U);
-}
-
-void KdTree3D::queryAgentTreeRecursive(Agent3D *agent, float &rangeSq,
- std::size_t node) const {
- if (agentTree_[node].end - agentTree_[node].begin <= RVO3D_MAX_LEAF_SIZE) {
- for (std::size_t i = agentTree_[node].begin; i < agentTree_[node].end;
- ++i) {
- agent->insertAgentNeighbor(agents_[i], rangeSq);
- }
- } else {
- const float distSqLeftMinX =
- std::max(0.0F, agentTree_[agentTree_[node].left].minCoord[0] -
- agent->position_.x());
- const float distSqLeftMaxX =
- std::max(0.0F, agent->position_.x() -
- agentTree_[agentTree_[node].left].maxCoord[0]);
- const float distSqLeftMinY =
- std::max(0.0F, agentTree_[agentTree_[node].left].minCoord[1] -
- agent->position_.y());
- const float distSqLeftMaxY =
- std::max(0.0F, agent->position_.y() -
- agentTree_[agentTree_[node].left].maxCoord[1]);
- const float distSqLeftMinZ =
- std::max(0.0F, agentTree_[agentTree_[node].left].minCoord[2] -
- agent->position_.z());
- const float distSqLeftMaxZ =
- std::max(0.0F, agent->position_.z() -
- agentTree_[agentTree_[node].left].maxCoord[2]);
-
- const float distSqLeft =
- distSqLeftMinX * distSqLeftMinX + distSqLeftMaxX * distSqLeftMaxX +
- distSqLeftMinY * distSqLeftMinY + distSqLeftMaxY * distSqLeftMaxY +
- distSqLeftMinZ * distSqLeftMinZ + distSqLeftMaxZ * distSqLeftMaxZ;
-
- const float distSqRightMinX =
- std::max(0.0F, agentTree_[agentTree_[node].right].minCoord[0] -
- agent->position_.x());
- const float distSqRightMaxX =
- std::max(0.0F, agent->position_.x() -
- agentTree_[agentTree_[node].right].maxCoord[0]);
- const float distSqRightMinY =
- std::max(0.0F, agentTree_[agentTree_[node].right].minCoord[1] -
- agent->position_.y());
- const float distSqRightMaxY =
- std::max(0.0F, agent->position_.y() -
- agentTree_[agentTree_[node].right].maxCoord[1]);
- const float distSqRightMinZ =
- std::max(0.0F, agentTree_[agentTree_[node].right].minCoord[2] -
- agent->position_.z());
- const float distSqRightMaxZ =
- std::max(0.0F, agent->position_.z() -
- agentTree_[agentTree_[node].right].maxCoord[2]);
-
- const float distSqRight =
- distSqRightMinX * distSqRightMinX + distSqRightMaxX * distSqRightMaxX +
- distSqRightMinY * distSqRightMinY + distSqRightMaxY * distSqRightMaxY +
- distSqRightMinZ * distSqRightMinZ + distSqRightMaxZ * distSqRightMaxZ;
-
- if (distSqLeft < distSqRight) {
- if (distSqLeft < rangeSq) {
- queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);
-
- if (distSqRight < rangeSq) {
- queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);
- }
- }
- } else {
- if (distSqRight < rangeSq) {
- queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);
-
- if (distSqLeft < rangeSq) {
- queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);
- }
- }
- }
- }
-}
-} /* namespace RVO3D */
diff --git a/thirdparty/rvo2/rvo2_3d/KdTree3d.cpp b/thirdparty/rvo2/rvo2_3d/KdTree3d.cpp
new file mode 100644
index 0000000000..2534871db1
--- /dev/null
+++ b/thirdparty/rvo2/rvo2_3d/KdTree3d.cpp
@@ -0,0 +1,161 @@
+/*
+ * KdTree.cpp
+ * RVO2-3D Library
+ *
+ * Copyright 2008 University of North Carolina at Chapel Hill
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to <geom@cs.unc.edu>.
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ * <https://gamma.cs.unc.edu/RVO2/>
+ */
+
+#include "KdTree3d.h"
+
+#include <algorithm>
+
+#include "Agent3d.h"
+#include "Definitions.h"
+#include "RVOSimulator3d.h"
+
+namespace RVO3D {
+ const size_t RVO3D_MAX_LEAF_SIZE = 10;
+
+ KdTree3D::KdTree3D(RVOSimulator3D *sim) : sim_(sim) { }
+
+ void KdTree3D::buildAgentTree(std::vector<Agent3D *> agents)
+ {
+ agents_.swap(agents);
+
+ if (!agents_.empty()) {
+ agentTree_.resize(2 * agents_.size() - 1);
+ buildAgentTreeRecursive(0, agents_.size(), 0);
+ }
+ }
+
+ void KdTree3D::buildAgentTreeRecursive(size_t begin, size_t end, size_t node)
+ {
+ agentTree_[node].begin = begin;
+ agentTree_[node].end = end;
+ agentTree_[node].minCoord = agents_[begin]->position_;
+ agentTree_[node].maxCoord = agents_[begin]->position_;
+
+ for (size_t i = begin + 1; i < end; ++i) {
+ agentTree_[node].maxCoord[0] = std::max(agentTree_[node].maxCoord[0], agents_[i]->position_.x());
+ agentTree_[node].minCoord[0] = std::min(agentTree_[node].minCoord[0], agents_[i]->position_.x());
+ agentTree_[node].maxCoord[1] = std::max(agentTree_[node].maxCoord[1], agents_[i]->position_.y());
+ agentTree_[node].minCoord[1] = std::min(agentTree_[node].minCoord[1], agents_[i]->position_.y());
+ agentTree_[node].maxCoord[2] = std::max(agentTree_[node].maxCoord[2], agents_[i]->position_.z());
+ agentTree_[node].minCoord[2] = std::min(agentTree_[node].minCoord[2], agents_[i]->position_.z());
+ }
+
+ if (end - begin > RVO3D_MAX_LEAF_SIZE) {
+ /* No leaf node. */
+ size_t coord;
+
+ if (agentTree_[node].maxCoord[0] - agentTree_[node].minCoord[0] > agentTree_[node].maxCoord[1] - agentTree_[node].minCoord[1] && agentTree_[node].maxCoord[0] - agentTree_[node].minCoord[0] > agentTree_[node].maxCoord[2] - agentTree_[node].minCoord[2]) {
+ coord = 0;
+ }
+ else if (agentTree_[node].maxCoord[1] - agentTree_[node].minCoord[1] > agentTree_[node].maxCoord[2] - agentTree_[node].minCoord[2]) {
+ coord = 1;
+ }
+ else {
+ coord = 2;
+ }
+
+ const float splitValue = 0.5f * (agentTree_[node].maxCoord[coord] + agentTree_[node].minCoord[coord]);
+
+ size_t left = begin;
+
+ size_t right = end;
+
+ while (left < right) {
+ while (left < right && agents_[left]->position_[coord] < splitValue) {
+ ++left;
+ }
+
+ while (right > left && agents_[right - 1]->position_[coord] >= splitValue) {
+ --right;
+ }
+
+ if (left < right) {
+ std::swap(agents_[left], agents_[right - 1]);
+ ++left;
+ --right;
+ }
+ }
+
+ size_t leftSize = left - begin;
+
+ if (leftSize == 0) {
+ ++leftSize;
+ ++left;
+ ++right;
+ }
+
+ agentTree_[node].left = node + 1;
+ agentTree_[node].right = node + 2 * leftSize;
+
+ buildAgentTreeRecursive(begin, left, agentTree_[node].left);
+ buildAgentTreeRecursive(left, end, agentTree_[node].right);
+ }
+ }
+
+ void KdTree3D::computeAgentNeighbors(Agent3D *agent, float rangeSq) const
+ {
+ queryAgentTreeRecursive(agent, rangeSq, 0);
+ }
+
+ void KdTree3D::queryAgentTreeRecursive(Agent3D *agent, float &rangeSq, size_t node) const
+ {
+ if (agentTree_[node].end - agentTree_[node].begin <= RVO3D_MAX_LEAF_SIZE) {
+ for (size_t i = agentTree_[node].begin; i < agentTree_[node].end; ++i) {
+ agent->insertAgentNeighbor(agents_[i], rangeSq);
+ }
+ }
+ else {
+ const float distSqLeft = sqr(std::max(0.0f, agentTree_[agentTree_[node].left].minCoord[0] - agent->position_.x())) + sqr(std::max(0.0f, agent->position_.x() - agentTree_[agentTree_[node].left].maxCoord[0])) + sqr(std::max(0.0f, agentTree_[agentTree_[node].left].minCoord[1] - agent->position_.y())) + sqr(std::max(0.0f, agent->position_.y() - agentTree_[agentTree_[node].left].maxCoord[1])) + sqr(std::max(0.0f, agentTree_[agentTree_[node].left].minCoord[2] - agent->position_.z())) + sqr(std::max(0.0f, agent->position_.z() - agentTree_[agentTree_[node].left].maxCoord[2]));
+
+ const float distSqRight = sqr(std::max(0.0f, agentTree_[agentTree_[node].right].minCoord[0] - agent->position_.x())) + sqr(std::max(0.0f, agent->position_.x() - agentTree_[agentTree_[node].right].maxCoord[0])) + sqr(std::max(0.0f, agentTree_[agentTree_[node].right].minCoord[1] - agent->position_.y())) + sqr(std::max(0.0f, agent->position_.y() - agentTree_[agentTree_[node].right].maxCoord[1])) + sqr(std::max(0.0f, agentTree_[agentTree_[node].right].minCoord[2] - agent->position_.z())) + sqr(std::max(0.0f, agent->position_.z() - agentTree_[agentTree_[node].right].maxCoord[2]));
+
+ if (distSqLeft < distSqRight) {
+ if (distSqLeft < rangeSq) {
+ queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);
+
+ if (distSqRight < rangeSq) {
+ queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);
+ }
+ }
+ }
+ else {
+ if (distSqRight < rangeSq) {
+ queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);
+
+ if (distSqLeft < rangeSq) {
+ queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/thirdparty/rvo2/rvo2_3d/KdTree3d.h b/thirdparty/rvo2/rvo2_3d/KdTree3d.h
index 900d9a2169..c018f98b23 100644
--- a/thirdparty/rvo2/rvo2_3d/KdTree3d.h
+++ b/thirdparty/rvo2/rvo2_3d/KdTree3d.h
@@ -1,9 +1,8 @@
/*
- * KdTree3d.h
+ * KdTree.h
* RVO2-3D Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,88 +29,92 @@
*
* <https://gamma.cs.unc.edu/RVO2/>
*/
-
-#ifndef RVO3D_KD_TREE_H_
-#define RVO3D_KD_TREE_H_
-
/**
- * @file KdTree3d.h
- * @brief Contains the KdTree3D class.
+ * \file KdTree.h
+ * \brief Contains the KdTree class.
*/
+#ifndef RVO3D_KD_TREE_H_
+#define RVO3D_KD_TREE_H_
#include <cstddef>
#include <vector>
-namespace RVO3D {
-class Agent3D;
-class RVOSimulator3D;
+#include "Vector3.h"
-/**
- * @brief Defines a k-D tree for agents in the simulation.
- */
-class KdTree3D {
- public:
- class AgentTreeNode;
-
- /**
- * @brief Constructs a k-D tree instance.
- * @param[in] sim The simulator instance.
- */
- explicit KdTree3D(RVOSimulator3D *sim);
-
- /**
- * @brief Destroys this k-D tree instance.
- */
- ~KdTree3D();
-
- /**
- * @brief Builds an agent k-D tree.
- */
- void buildAgentTree(std::vector<Agent3D *> agents);
-
- /**
- * @brief Recursive function to build a k-D tree.
- * @param[in] begin The beginning k-D tree node.
- * @param[in] end The ending k-D tree node.
- * @param[in] node The current k-D tree node.
- */
- void buildAgentTreeRecursive(std::size_t begin, std::size_t end,
- std::size_t node);
-
- /**
- * @brief Computes the agent neighbors of the specified agent.
- * @param[in] agent A pointer to the agent for which agent neighbors are to
- * be computed.
- * @param[in] rangeSq The squared range around the agent.
- */
- void computeAgentNeighbors(Agent3D *agent, float rangeSq) const;
-
- /**
- * @brief Recursive function to compute the neighbors of the specified
- * agent.
- * @param[in] agent A pointer to the agent for which neighbors are to be
- * computed.
- * @param[in,out] rangeSq The squared range around the agent.
- * @param[in] node The current k-D tree node.
- */
-
- void queryAgentTreeRecursive(Agent3D *agent,
- float &rangeSq, /* NOLINT(runtime/references) */
- std::size_t node) const;
-
- /* Not implemented. */
- KdTree3D(const KdTree3D &other);
-
- /* Not implemented. */
- KdTree3D &operator=(const KdTree3D &other);
-
- std::vector<Agent3D *> agents_;
- std::vector<AgentTreeNode> agentTree_;
- RVOSimulator3D *sim_;
-
- friend class Agent3D;
- friend class RVOSimulator3D;
-};
-} /* namespace RVO3D */
+namespace RVO3D {
+ class Agent3D;
+ class RVOSimulator3D;
+
+ /**
+ * \brief Defines <i>k</i>d-trees for agents in the simulation.
+ */
+ class KdTree3D {
+ public:
+ /**
+ * \brief Defines an agent <i>k</i>d-tree node.
+ */
+ class AgentTreeNode3D {
+ public:
+ /**
+ * \brief The beginning node number.
+ */
+ size_t begin;
+
+ /**
+ * \brief The ending node number.
+ */
+ size_t end;
+
+ /**
+ * \brief The left node number.
+ */
+ size_t left;
+
+ /**
+ * \brief The right node number.
+ */
+ size_t right;
+
+ /**
+ * \brief The maximum coordinates.
+ */
+ Vector3 maxCoord;
+
+ /**
+ * \brief The minimum coordinates.
+ */
+ Vector3 minCoord;
+ };
+
+ /**
+ * \brief Constructs a <i>k</i>d-tree instance.
+ * \param sim The simulator instance.
+ */
+ explicit KdTree3D(RVOSimulator3D *sim);
+
+ /**
+ * \brief Builds an agent <i>k</i>d-tree.
+ */
+ void buildAgentTree(std::vector<Agent3D *> agents);
+
+ void buildAgentTreeRecursive(size_t begin, size_t end, size_t node);
+
+ /**
+ * \brief Computes the agent neighbors of the specified agent.
+ * \param agent A pointer to the agent for which agent neighbors are to be computed.
+ * \param rangeSq The squared range around the agent.
+ */
+ void computeAgentNeighbors(Agent3D *agent, float rangeSq) const;
+
+ void queryAgentTreeRecursive(Agent3D *agent, float &rangeSq, size_t node) const;
+
+ std::vector<Agent3D *> agents_;
+ std::vector<AgentTreeNode3D> agentTree_;
+ RVOSimulator3D *sim_;
+
+ friend class Agent3D;
+ friend class RVOSimulator3D;
+ };
+}
#endif /* RVO3D_KD_TREE_H_ */
diff --git a/thirdparty/rvo2/rvo2_3d/Plane.h b/thirdparty/rvo2/rvo2_3d/Plane.h
deleted file mode 100644
index dbb1f63a80..0000000000
--- a/thirdparty/rvo2/rvo2_3d/Plane.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Plane.h
- * RVO2-3D Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-#ifndef RVO3D_PLANE_H_
-#define RVO3D_PLANE_H_
-
-/**
- * @file Plane.h
- * @brief Contains the Plane class.
- */
-
-#include "Vector3.h"
-
-namespace RVO3D {
-/**
- * @brief Defines a plane.
- */
-class Plane {
- public:
- /**
- * @brief Constructs a plane.
- */
- Plane();
-
- /**
- * @brief A point on the plane.
- */
- Vector3 point;
-
- /**
- * @brief The normal to the plane.
- */
- Vector3 normal;
-};
-} /* namespace RVO3D */
-
-#endif /* RVO3D_PLANE_H_ */
diff --git a/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.cc b/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.cc
deleted file mode 100644
index 346d604497..0000000000
--- a/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.cc
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * RVOSimulator3d.cc
- * RVO2-3D Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-#include "RVOSimulator3d.h"
-
-#include <utility>
-
-#ifdef _OPENMP
-#include <omp.h>
-#endif /* _OPENMP */
-
-#include "Agent3d.h"
-#include "KdTree3d.h"
-#include "Plane.h"
-
-namespace RVO3D {
-RVOSimulator3D::RVOSimulator3D()
- : defaultAgent_(NULL),
- kdTree_(new KdTree3D(this)),
- globalTime_(0.0F),
- timeStep_(0.0F) {}
-
-RVOSimulator3D::RVOSimulator3D(float timeStep, float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float radius, float maxSpeed,
- const Vector3 &velocity)
- : defaultAgent_(new Agent3D()),
- kdTree_(new KdTree3D(this)),
- globalTime_(0.0F),
- timeStep_(timeStep) {
- defaultAgent_->maxNeighbors_ = maxNeighbors;
- defaultAgent_->maxSpeed_ = maxSpeed;
- defaultAgent_->neighborDist_ = neighborDist;
- defaultAgent_->radius_ = radius;
- defaultAgent_->timeHorizon_ = timeHorizon;
- defaultAgent_->velocity_ = velocity;
-}
-
-RVOSimulator3D::~RVOSimulator3D() {
- delete defaultAgent_;
- delete kdTree_;
-
- for (std::size_t i = 0U; i < agents_.size(); ++i) {
- delete agents_[i];
- }
-}
-
-std::size_t RVOSimulator3D::getAgentNumAgentNeighbors(std::size_t agentNo) const {
- return agents_[agentNo]->agentNeighbors_.size();
-}
-
-std::size_t RVOSimulator3D::getAgentAgentNeighbor(std::size_t agentNo,
- std::size_t neighborNo) const {
- return agents_[agentNo]->agentNeighbors_[neighborNo].second->id_;
-}
-
-std::size_t RVOSimulator3D::getAgentNumORCAPlanes(std::size_t agentNo) const {
- return agents_[agentNo]->orcaPlanes_.size();
-}
-
-const Plane &RVOSimulator3D::getAgentORCAPlane(std::size_t agentNo,
- std::size_t planeNo) const {
- return agents_[agentNo]->orcaPlanes_[planeNo];
-}
-
-void RVOSimulator3D::removeAgent(std::size_t agentNo) {
- delete agents_[agentNo];
- agents_[agentNo] = agents_.back();
- agents_.pop_back();
-}
-
-std::size_t RVOSimulator3D::addAgent(const Vector3 &position) {
- if (defaultAgent_ == NULL) {
- return RVO3D_ERROR;
- }
-
- Agent3D *agent = new Agent3D();
-
- agent->position_ = position;
- agent->maxNeighbors_ = defaultAgent_->maxNeighbors_;
- agent->maxSpeed_ = defaultAgent_->maxSpeed_;
- agent->neighborDist_ = defaultAgent_->neighborDist_;
- agent->radius_ = defaultAgent_->radius_;
- agent->timeHorizon_ = defaultAgent_->timeHorizon_;
- agent->velocity_ = defaultAgent_->velocity_;
-
- agent->id_ = agents_.size();
-
- agents_.push_back(agent);
-
- return agents_.size() - 1U;
-}
-
-std::size_t RVOSimulator3D::addAgent(const Vector3 &position, float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float radius, float maxSpeed,
- const Vector3 &velocity) {
- Agent3D *agent = new Agent3D();
-
- agent->position_ = position;
- agent->maxNeighbors_ = maxNeighbors;
- agent->maxSpeed_ = maxSpeed;
- agent->neighborDist_ = neighborDist;
- agent->radius_ = radius;
- agent->timeHorizon_ = timeHorizon;
- agent->velocity_ = velocity;
-
- agent->id_ = agents_.size();
-
- agents_.push_back(agent);
-
- return agents_.size() - 1U;
-}
-
-void RVOSimulator3D::doStep() {
- kdTree_->buildAgentTree(agents_);
-
-#ifdef _OPENMP
-#pragma omp parallel for
-#endif /* _OPENMP */
- for (int i = 0; i < static_cast<int>(agents_.size()); ++i) {
- agents_[i]->computeNeighbors(this);
- agents_[i]->computeNewVelocity(this);
- }
-
-#ifdef _OPENMP
-#pragma omp parallel for
-#endif /* _OPENMP */
- for (int i = 0; i < static_cast<int>(agents_.size()); ++i) {
- agents_[i]->update(this);
- }
-
- globalTime_ += timeStep_;
-}
-
-std::size_t RVOSimulator3D::getAgentMaxNeighbors(std::size_t agentNo) const {
- return agents_[agentNo]->maxNeighbors_;
-}
-
-float RVOSimulator3D::getAgentMaxSpeed(std::size_t agentNo) const {
- return agents_[agentNo]->maxSpeed_;
-}
-
-float RVOSimulator3D::getAgentNeighborDist(std::size_t agentNo) const {
- return agents_[agentNo]->neighborDist_;
-}
-
-const Vector3 &RVOSimulator3D::getAgentPosition(std::size_t agentNo) const {
- return agents_[agentNo]->position_;
-}
-
-const Vector3 &RVOSimulator3D::getAgentPrefVelocity(std::size_t agentNo) const {
- return agents_[agentNo]->prefVelocity_;
-}
-
-float RVOSimulator3D::getAgentRadius(std::size_t agentNo) const {
- return agents_[agentNo]->radius_;
-}
-
-float RVOSimulator3D::getAgentTimeHorizon(std::size_t agentNo) const {
- return agents_[agentNo]->timeHorizon_;
-}
-
-const Vector3 &RVOSimulator3D::getAgentVelocity(std::size_t agentNo) const {
- return agents_[agentNo]->velocity_;
-}
-
-void RVOSimulator3D::setAgentDefaults(float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float radius, float maxSpeed,
- const Vector3 &velocity) {
- if (defaultAgent_ == NULL) {
- defaultAgent_ = new Agent3D();
- }
-
- defaultAgent_->maxNeighbors_ = maxNeighbors;
- defaultAgent_->maxSpeed_ = maxSpeed;
- defaultAgent_->neighborDist_ = neighborDist;
- defaultAgent_->radius_ = radius;
- defaultAgent_->timeHorizon_ = timeHorizon;
- defaultAgent_->velocity_ = velocity;
-}
-
-void RVOSimulator3D::setAgentMaxNeighbors(std::size_t agentNo,
- std::size_t maxNeighbors) {
- agents_[agentNo]->maxNeighbors_ = maxNeighbors;
-}
-
-void RVOSimulator3D::setAgentMaxSpeed(std::size_t agentNo, float maxSpeed) {
- agents_[agentNo]->maxSpeed_ = maxSpeed;
-}
-
-void RVOSimulator3D::setAgentNeighborDist(std::size_t agentNo,
- float neighborDist) {
- agents_[agentNo]->neighborDist_ = neighborDist;
-}
-
-void RVOSimulator3D::setAgentPosition(std::size_t agentNo,
- const Vector3 &position) {
- agents_[agentNo]->position_ = position;
-}
-
-void RVOSimulator3D::setAgentPrefVelocity(std::size_t agentNo,
- const Vector3 &prefVelocity) {
- agents_[agentNo]->prefVelocity_ = prefVelocity;
-}
-
-void RVOSimulator3D::setAgentRadius(std::size_t agentNo, float radius) {
- agents_[agentNo]->radius_ = radius;
-}
-
-void RVOSimulator3D::setAgentTimeHorizon(std::size_t agentNo, float timeHorizon) {
- agents_[agentNo]->timeHorizon_ = timeHorizon;
-}
-
-void RVOSimulator3D::setAgentVelocity(std::size_t agentNo,
- const Vector3 &velocity) {
- agents_[agentNo]->velocity_ = velocity;
-}
-} /* namespace RVO3D */
diff --git a/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.cpp b/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.cpp
new file mode 100644
index 0000000000..71e5aea9e2
--- /dev/null
+++ b/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.cpp
@@ -0,0 +1,274 @@
+/*
+ * RVOSimulator.cpp
+ * RVO2-3D Library
+ *
+ * Copyright 2008 University of North Carolina at Chapel Hill
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to <geom@cs.unc.edu>.
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ * <http://gamma.cs.unc.edu/RVO2/>
+ */
+
+#include "RVOSimulator3d.h"
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+#include "Agent3d.h"
+#include "KdTree3d.h"
+
+namespace RVO3D {
+ RVOSimulator3D::RVOSimulator3D() : defaultAgent_(NULL), kdTree_(NULL), globalTime_(0.0f), timeStep_(0.0f)
+ {
+ kdTree_ = new KdTree3D(this);
+ }
+
+ RVOSimulator3D::RVOSimulator3D(float timeStep, float neighborDist, size_t maxNeighbors, float timeHorizon, float radius, float maxSpeed, const Vector3 &velocity) : defaultAgent_(NULL), kdTree_(NULL), globalTime_(0.0f), timeStep_(timeStep)
+ {
+ kdTree_ = new KdTree3D(this);
+ defaultAgent_ = new Agent3D();
+
+ defaultAgent_->maxNeighbors_ = maxNeighbors;
+ defaultAgent_->maxSpeed_ = maxSpeed;
+ defaultAgent_->neighborDist_ = neighborDist;
+ defaultAgent_->radius_ = radius;
+ defaultAgent_->timeHorizon_ = timeHorizon;
+ defaultAgent_->velocity_ = velocity;
+ }
+
+ RVOSimulator3D::~RVOSimulator3D()
+ {
+ if (defaultAgent_ != NULL) {
+ delete defaultAgent_;
+ }
+
+ for (size_t i = 0; i < agents_.size(); ++i) {
+ delete agents_[i];
+ }
+
+ if (kdTree_ != NULL) {
+ delete kdTree_;
+ }
+ }
+
+ size_t RVOSimulator3D::getAgentNumAgentNeighbors(size_t agentNo) const
+ {
+ return agents_[agentNo]->agentNeighbors_.size();
+ }
+
+ size_t RVOSimulator3D::getAgentAgentNeighbor(size_t agentNo, size_t neighborNo) const
+ {
+ return agents_[agentNo]->agentNeighbors_[neighborNo].second->id_;
+ }
+
+ size_t RVOSimulator3D::getAgentNumORCAPlanes(size_t agentNo) const
+ {
+ return agents_[agentNo]->orcaPlanes_.size();
+ }
+
+ const Plane &RVOSimulator3D::getAgentORCAPlane(size_t agentNo, size_t planeNo) const
+ {
+ return agents_[agentNo]->orcaPlanes_[planeNo];
+ }
+
+ void RVOSimulator3D::removeAgent(size_t agentNo)
+ {
+ delete agents_[agentNo];
+ agents_[agentNo] = agents_.back();
+ agents_.pop_back();
+ }
+
+ size_t RVOSimulator3D::addAgent(const Vector3 &position)
+ {
+ if (defaultAgent_ == NULL) {
+ return RVO3D_ERROR;
+ }
+
+ Agent3D *agent = new Agent3D();
+
+ agent->position_ = position;
+ agent->maxNeighbors_ = defaultAgent_->maxNeighbors_;
+ agent->maxSpeed_ = defaultAgent_->maxSpeed_;
+ agent->neighborDist_ = defaultAgent_->neighborDist_;
+ agent->radius_ = defaultAgent_->radius_;
+ agent->timeHorizon_ = defaultAgent_->timeHorizon_;
+ agent->velocity_ = defaultAgent_->velocity_;
+
+ agent->id_ = agents_.size();
+
+ agents_.push_back(agent);
+
+ return agents_.size() - 1;
+ }
+
+ size_t RVOSimulator3D::addAgent(const Vector3 &position, float neighborDist, size_t maxNeighbors, float timeHorizon, float radius, float maxSpeed, const Vector3 &velocity)
+ {
+ Agent3D *agent = new Agent3D();
+
+ agent->position_ = position;
+ agent->maxNeighbors_ = maxNeighbors;
+ agent->maxSpeed_ = maxSpeed;
+ agent->neighborDist_ = neighborDist;
+ agent->radius_ = radius;
+ agent->timeHorizon_ = timeHorizon;
+ agent->velocity_ = velocity;
+
+ agent->id_ = agents_.size();
+
+ agents_.push_back(agent);
+
+ return agents_.size() - 1;
+ }
+
+ void RVOSimulator3D::doStep()
+ {
+ kdTree_->buildAgentTree(agents_);
+
+ for (int i = 0; i < static_cast<int>(agents_.size()); ++i) {
+ agents_[i]->computeNeighbors(this);
+ agents_[i]->computeNewVelocity(this);
+ }
+
+ for (int i = 0; i < static_cast<int>(agents_.size()); ++i) {
+ agents_[i]->update(this);
+ }
+
+ globalTime_ += timeStep_;
+ }
+
+ size_t RVOSimulator3D::getAgentMaxNeighbors(size_t agentNo) const
+ {
+ return agents_[agentNo]->maxNeighbors_;
+ }
+
+ float RVOSimulator3D::getAgentMaxSpeed(size_t agentNo) const
+ {
+ return agents_[agentNo]->maxSpeed_;
+ }
+
+ float RVOSimulator3D::getAgentNeighborDist(size_t agentNo) const
+ {
+ return agents_[agentNo]->neighborDist_;
+ }
+
+ const Vector3 &RVOSimulator3D::getAgentPosition(size_t agentNo) const
+ {
+ return agents_[agentNo]->position_;
+ }
+
+ const Vector3 &RVOSimulator3D::getAgentPrefVelocity(size_t agentNo) const
+ {
+ return agents_[agentNo]->prefVelocity_;
+ }
+
+ float RVOSimulator3D::getAgentRadius(size_t agentNo) const
+ {
+ return agents_[agentNo]->radius_;
+ }
+
+ float RVOSimulator3D::getAgentTimeHorizon(size_t agentNo) const
+ {
+ return agents_[agentNo]->timeHorizon_;
+ }
+
+ const Vector3 &RVOSimulator3D::getAgentVelocity(size_t agentNo) const
+ {
+ return agents_[agentNo]->velocity_;
+ }
+
+ float RVOSimulator3D::getGlobalTime() const
+ {
+ return globalTime_;
+ }
+
+ size_t RVOSimulator3D::getNumAgents() const
+ {
+ return agents_.size();
+ }
+
+ float RVOSimulator3D::getTimeStep() const
+ {
+ return timeStep_;
+ }
+
+ void RVOSimulator3D::setAgentDefaults(float neighborDist, size_t maxNeighbors, float timeHorizon, float radius, float maxSpeed, const Vector3 &velocity)
+ {
+ if (defaultAgent_ == NULL) {
+ defaultAgent_ = new Agent3D();
+ }
+
+ defaultAgent_->maxNeighbors_ = maxNeighbors;
+ defaultAgent_->maxSpeed_ = maxSpeed;
+ defaultAgent_->neighborDist_ = neighborDist;
+ defaultAgent_->radius_ = radius;
+ defaultAgent_->timeHorizon_ = timeHorizon;
+ defaultAgent_->velocity_ = velocity;
+ }
+
+ void RVOSimulator3D::setAgentMaxNeighbors(size_t agentNo, size_t maxNeighbors)
+ {
+ agents_[agentNo]->maxNeighbors_ = maxNeighbors;
+ }
+
+ void RVOSimulator3D::setAgentMaxSpeed(size_t agentNo, float maxSpeed)
+ {
+ agents_[agentNo]->maxSpeed_ = maxSpeed;
+ }
+
+ void RVOSimulator3D::setAgentNeighborDist(size_t agentNo, float neighborDist)
+ {
+ agents_[agentNo]->neighborDist_ = neighborDist;
+ }
+
+ void RVOSimulator3D::setAgentPosition(size_t agentNo, const Vector3 &position)
+ {
+ agents_[agentNo]->position_ = position;
+ }
+
+ void RVOSimulator3D::setAgentPrefVelocity(size_t agentNo, const Vector3 &prefVelocity)
+ {
+ agents_[agentNo]->prefVelocity_ = prefVelocity;
+ }
+
+ void RVOSimulator3D::setAgentRadius(size_t agentNo, float radius)
+ {
+ agents_[agentNo]->radius_ = radius;
+ }
+
+ void RVOSimulator3D::setAgentTimeHorizon(size_t agentNo, float timeHorizon)
+ {
+ agents_[agentNo]->timeHorizon_ = timeHorizon;
+ }
+
+ void RVOSimulator3D::setAgentVelocity(size_t agentNo, const Vector3 &velocity)
+ {
+ agents_[agentNo]->velocity_ = velocity;
+ }
+
+ void RVOSimulator3D::setTimeStep(float timeStep)
+ {
+ timeStep_ = timeStep;
+ }
+}
diff --git a/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.h b/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.h
index 73b734a4af..4ea093d74c 100644
--- a/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.h
+++ b/thirdparty/rvo2/rvo2_3d/RVOSimulator3d.h
@@ -1,15 +1,14 @@
/*
- * RVOSimulator3d.h
+ * RVOSimulator.h
* RVO2-3D Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,16 +27,15 @@
* Chapel Hill, N.C. 27599-3175
* United States of America
*
- * <https://gamma.cs.unc.edu/RVO2/>
+ * <http://gamma.cs.unc.edu/RVO2/>
*/
-#ifndef RVO3D_RVO_SIMULATOR_H_
-#define RVO3D_RVO_SIMULATOR_H_
-
/**
- * @file RVOSimulator3d.h
- * @brief Contains the RVOSimulator3D class.
+ * \file RVOSimulator.h
+ * \brief Contains the RVOSimulator class.
*/
+#ifndef RVO3D_RVO_SIMULATOR_H_
+#define RVO3D_RVO_SIMULATOR_H_
#include <cstddef>
#include <limits>
@@ -46,369 +44,281 @@
#include "Vector3.h"
namespace RVO3D {
-class Agent3D;
-class KdTree3D;
-class Plane;
-
-/**
- * @brief Error value. A value equal to the largest unsigned integer, which is
- * returned in case of an error by functions in RVO::RVOSimulator.
- */
-const std::size_t RVO3D_ERROR = std::numeric_limits<std::size_t>::max();
-
-/**
- * @brief Defines the simulation. The main class of the library that contains
- * all simulation functionality.
- */
-class RVOSimulator3D {
- public:
- /**
- * @brief Constructs a simulator instance.
- */
- RVOSimulator3D();
-
- /**
- * @brief Constructs a simulator instance and sets the default properties
- * for any new agent that is added.
- * @param[in] timeStep The time step of the simulation. Must be positive.
- * @param[in] neighborDist The default maximum distance (center point to
- * center point) to other agents a new agent takes
- * into account in the navigation. The larger this
- * number, the longer the running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe. Must be non-negative.
- * @param[in] maxNeighbors The default maximum number of other agents a new
- * agent takes into account in the navigation. The
- * larger this number, the longer the running time of
- * the simulation. If the number is too low, the
- * simulation will not be safe.
- * @param[in] timeHorizon The default minimum amount of time for which a new
- * agent's velocities that are computed by the
- * simulation are safe with respect to other agents.
- * The larger this number, the sooner an agent will
- * respond to the presence of other agents, but the
- * less freedom the agent has in choosing its
- * velocities. Must be positive.
- * @param[in] radius The default radius of a new agent. Must be
- * non-negative.
- * @param[in] maxSpeed The default maximum speed of a new agent. Must be
- * non-negative.
- * @param[in] velocity The default initial three-dimensional linear
- * velocity of a new agent (optional).
- */
- RVOSimulator3D(float timeStep, float neighborDist, std::size_t maxNeighbors,
- float timeHorizon, float radius, float maxSpeed,
- const Vector3 &velocity = Vector3());
-
- /**
- * @brief Destroys this simulator instance.
- */
- ~RVOSimulator3D();
-
- /**
- * @brief Adds a new agent with default properties to the simulation.
- * @param[in] position The three-dimensional starting position of this agent.
- * @return The number of the agent or RVO::RVO3D_ERROR when the agent
- * defaults have not been set.
- */
- std::size_t addAgent(const Vector3 &position);
-
- /**
- * @brief Adds a new agent to the simulation.
- * @param[in] position The three-dimensional starting position of this
- * agent.
- * @param[in] neighborDist The maximum distance (center point to center
- * point) to other agents this agent takes into
- * account in the navigation. The larger this number,
- * the longer the running time of the simulation. If
- * the number is too low, the simulation will not be
- * safe. Must be non-negative.
- * @param[in] maxNeighbors The maximum number of other agents this agent takes
- * into account in the navigation. The larger this
- * number, the longer the running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe.
- * @param[in] timeHorizon The minimum amount of time for which this agent's
- * velocities that are computed by the simulation are
- * safe with respect to other agents. The larger this
- * number, the sooner this agent will respond to the
- * presence of other agents, but the less freedom this
- * agent has in choosing its velocities. Must be
- * positive.
- * @param[in] radius The radius of this agent. Must be non-negative.
- * @param[in] maxSpeed The maximum speed of this agent. Must be
- * non-negative.
- * @param[in] velocity The initial three-dimensional linear velocity of
- * this agent (optional).
- * @return The number of the agent.
- */
- std::size_t addAgent(const Vector3 &position, float neighborDist,
- std::size_t maxNeighbors, float timeHorizon,
- float radius, float maxSpeed,
- const Vector3 &velocity = Vector3());
-
- /**
- * @brief Lets the simulator perform a simulation step and updates the
- * three-dimensional position and three-dimensional velocity of each
- * agent.
- */
- void doStep();
-
- /**
- * @brief Returns the specified agent neighbor of the specified agent.
- * @param[in] agentNo The number of the agent whose agent neighbor is to
- * be retrieved.
- * @param[in] neighborNo The number of the agent neighbor to be retrieved.
- * @return The number of the neighboring agent.
- */
- std::size_t getAgentAgentNeighbor(std::size_t agentNo,
- std::size_t neighborNo) const;
-
- /**
- * @brief Returns the maximum neighbor count of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum neighbor count is
- * to be retrieved.
- * @return The present maximum neighbor count of the agent.
- */
- std::size_t getAgentMaxNeighbors(std::size_t agentNo) const;
-
- /**
- * @brief Returns the maximum speed of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum speed is to be
- * retrieved.
- * @return The present maximum speed of the agent.
- */
- float getAgentMaxSpeed(std::size_t agentNo) const;
-
- /**
- * @brief Returns the maximum neighbor distance of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum neighbor distance
- * is to be retrieved.
- * @return The present maximum neighbor distance of the agent.
- */
- float getAgentNeighborDist(std::size_t agentNo) const;
-
- /**
- * @brief Returns the count of agent neighbors taken into account to
- * compute the current velocity for the specified agent.
- * @param[in] agentNo The number of the agent whose count of agent neighbors
- * is to be retrieved.
- * @return The count of agent neighbors taken into account to compute the
- * current velocity for the specified agent.
- */
- std::size_t getAgentNumAgentNeighbors(std::size_t agentNo) const;
-
- /**
- * @brief Returns the count of ORCA constraints used to compute the
- * current velocity for the specified agent.
- * @param[in] agentNo The number of the agent whose count of ORCA constraints
- * i to be retrieved.
- * @return The count of ORCA constraints used to compute the current
- * velocity for the specified agent.
- */
- std::size_t getAgentNumORCAPlanes(std::size_t agentNo) const;
-
- /**
- * @brief Returns the specified ORCA constraint of the specified agent.
- * @param[in] agentNo The number of the agent whose ORCA constraint is to be
- * retrieved.
- * @param[in] planeNo The number of the ORCA constraint to be retrieved.
- * @return A plane representing the specified ORCA constraint.
- * @note The halfspace to which the normal of the plane points is the
- * region of permissible velocities with respect to the specified
- * ORCA constraint.
- */
- const Plane &getAgentORCAPlane(std::size_t agentNo,
- std::size_t planeNo) const;
-
- /**
- * @brief Returns the three-dimensional position of a specified agent.
- * @param[in] agentNo The number of the agent whose three-dimensional position
- * is to be retrieved.
- * @return The present three-dimensional position of the (center of the)
- * agent.
- */
- const Vector3 &getAgentPosition(std::size_t agentNo) const;
-
- /**
- * @brief Returns the three-dimensional preferred velocity of a specified
- * agent.
- * @param[in] agentNo The number of the agent whose three-dimensional
- * preferred velocity is to be retrieved.
- * @return The present three-dimensional preferred velocity of the agent.
- */
- const Vector3 &getAgentPrefVelocity(std::size_t agentNo) const;
-
- /**
- * @brief Returns the radius of a specified agent.
- * @param[in] agentNo The number of the agent whose radius is to be retrieved.
- * @return The present radius of the agent.
- */
- float getAgentRadius(std::size_t agentNo) const;
-
- /**
- * @brief Returns the time horizon of a specified agent.
- * @param[in] agentNo The number of the agent whose time horizon is to be
- * retrieved.
- * @return The present time horizon of the agent.
- */
- float getAgentTimeHorizon(std::size_t agentNo) const;
-
- /**
- * @brief Returns the three-dimensional linear velocity of a specified
- * agent.
- * @param[in] agentNo The number of the agent whose three-dimensional linear
- * velocity is to be retrieved.
- * @return The present three-dimensional linear velocity of the agent.
- */
- const Vector3 &getAgentVelocity(std::size_t agentNo) const;
-
- /**
- * @brief Returns the global time of the simulation.
- * @return The present global time of the simulation (zero initially).
- */
- float getGlobalTime() const { return globalTime_; }
- /**
- * @brief Returns the count of agents in the simulation.
- * @return The count of agents in the simulation.
- */
- std::size_t getNumAgents() const { return agents_.size(); }
-
- /**
- * @brief Returns the time step of the simulation.
- * @return The present time step of the simulation.
- */
- float getTimeStep() const { return timeStep_; }
-
- /**
- * @brief Removes an agent from the simulation.
- * @param[in] agentNo The number of the agent that is to be removed.
- * @note After the removal of the agent, the agent that previously had
- * number getNumAgents() - 1 will now have number agentNo.
- */
- void removeAgent(std::size_t agentNo);
-
- /**
- * @brief Sets the default properties for any new agent that is added.
- * @param[in] neighborDist The default maximum distance (center point to
- * center point) to other agents a new agent takes
- * into account in the navigation. The larger this
- * number, the longer he running time of the
- * simulation. If the number is too low, the
- * simulation will not be safe. Must be non-negative.
- * @param[in] maxNeighbors The default maximum number of other agents a new
- * agent takes into account in the navigation. The
- * larger this number, the longer the running time of
- * the simulation. If the number is too low, the
- * simulation will not be safe.
- * @param[in] timeHorizon The default minimum amount of time for which a new
- * agent's velocities that are computed by the
- * simulation are safe with respect to other agents.
- * The larger this number, the sooner an agent will
- * respond to the presence of other agents, but the
- * less freedom the agent has in choosing its
- * velocities. Must be positive.
- * @param[in] radius The default radius of a new agent. Must be
- * non-negative.
- * @param[in] maxSpeed The default maximum speed of a new agent. Must be
- * non-negative.
- * @param[in] velocity The default initial three-dimensional linear
- * velocity of a new agent (optional).
- */
- void setAgentDefaults(float neighborDist, std::size_t maxNeighbors,
- float timeHorizon, float radius, float maxSpeed,
- const Vector3 &velocity = Vector3());
-
- /**
- * @brief Sets the maximum neighbor count of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum neighbor
- * count is to be modified.
- * @param[in] maxNeighbors The replacement maximum neighbor count.
- */
- void setAgentMaxNeighbors(std::size_t agentNo, std::size_t maxNeighbors);
-
- /**
- * @brief Sets the maximum speed of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum speed is to be
- * modified.
- * @param[in] maxSpeed The replacement maximum speed. Must be non-negative.
- */
- void setAgentMaxSpeed(std::size_t agentNo, float maxSpeed);
-
- /**
- * @brief Sets the maximum neighbor distance of a specified agent.
- * @param[in] agentNo The number of the agent whose maximum neighbor
- * distance is to be modified.
- * @param[in] neighborDist The replacement maximum neighbor distance. Must be
- * non-negative.
- */
- void setAgentNeighborDist(std::size_t agentNo, float neighborDist);
-
- /**
- * @brief Sets the three-dimensional position of a specified agent.
- * @param[in] agentNo The number of the agent whose three-dimensional
- * position is to be modified.
- * @param[in] position The replacement of the three-dimensional position.
- */
- void setAgentPosition(std::size_t agentNo, const Vector3 &position);
-
- /**
- * @brief Sets the three-dimensional preferred velocity of a specified
- * agent.
- * @param[in] agentNo The number of the agent whose three-dimensional
- * preferred velocity is to be modified.
- * @param[in] prefVelocity The replacement of the three-dimensional preferred
- * velocity.
- */
- void setAgentPrefVelocity(std::size_t agentNo, const Vector3 &prefVelocity);
-
- /**
- * @brief Sets the radius of a specified agent.
- * @param[in] agentNo The number of the agent whose radius is to be modified.
- * @param[in] radius The replacement radius. Must be non-negative.
- */
- void setAgentRadius(std::size_t agentNo, float radius);
-
- /**
- * @brief Sets the time horizon of a specified agent with respect to other
- * agents.
- * @param[in] agentNo The number of the agent whose time horizon is to be
- * modified.
- * @param[in] timeHorizon The replacement time horizon with respect to other
- * agents. Must be positive.
- */
- void setAgentTimeHorizon(std::size_t agentNo, float timeHorizon);
-
- /**
- * @brief Sets the three-dimensional linear velocity of a specified agent.
- * @param[in] agentNo The number of the agent whose three-dimensional linear
- * velocity is to be modified.
- * @param[in] velocity The replacement three-dimensional linear velocity.
- */
- void setAgentVelocity(std::size_t agentNo, const Vector3 &velocity);
-
- /**
- * @brief Sets the time step of the simulation.
- * @param[in] timeStep The time step of the simulation. Must be positive.
- */
- void setTimeStep(float timeStep) { timeStep_ = timeStep; }
-
- public:
- /* Not implemented. */
- RVOSimulator3D(const RVOSimulator3D &other);
-
- /* Not implemented. */
- RVOSimulator3D &operator=(const RVOSimulator3D &other);
-
- Agent3D *defaultAgent_;
- KdTree3D *kdTree_;
- float globalTime_;
- float timeStep_;
- std::vector<Agent3D *> agents_;
-
- friend class Agent3D;
- friend class KdTree3D;
-};
-} /* namespace RVO3D */
-
-#endif /* RVO3D_RVO_SIMULATOR_H_ */
+ class Agent3D;
+ class KdTree3D;
+
+ /**
+ * \brief Error value.
+ *
+ * A value equal to the largest unsigned integer, which is returned in case of an error by functions in RVO3D::RVOSimulator.
+ */
+ const size_t RVO3D_ERROR = std::numeric_limits<size_t>::max();
+
+ /**
+ * \brief Defines a plane.
+ */
+ class Plane {
+ public:
+ /**
+ * \brief A point on the plane.
+ */
+ Vector3 point;
+
+ /**
+ * \brief The normal to the plane.
+ */
+ Vector3 normal;
+ };
+
+ /**
+ * \brief Defines the simulation.
+ *
+ * The main class of the library that contains all simulation functionality.
+ */
+ class RVOSimulator3D {
+ public:
+ /**
+ * \brief Constructs a simulator instance.
+ */
+ RVOSimulator3D();
+
+ /**
+ * \brief Constructs a simulator instance and sets the default properties for any new agent that is added.
+ * \param timeStep The time step of the simulation. Must be positive.
+ * \param neighborDist The default maximum distance (center point to center point) to other agents a new agent takes into account in the navigation. The larger this number, the longer he running time of the simulation. If the number is too low, the simulation will not be safe. Must be non-negative.
+ * \param maxNeighbors The default maximum number of other agents a new agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
+ * \param timeHorizon The default minimum amount of time for which a new agent's velocities that are computed by the simulation are safe with respect to other agents. The larger this number, the sooner an agent will respond to the presence of other agents, but the less freedom the agent has in choosing its velocities. Must be positive.
+ * \param radius The default radius of a new agent. Must be non-negative.
+ * \param maxSpeed The default maximum speed of a new agent. Must be non-negative.
+ * \param velocity The default initial three-dimensional linear velocity of a new agent (optional).
+ */
+ RVOSimulator3D(float timeStep, float neighborDist, size_t maxNeighbors, float timeHorizon, float radius, float maxSpeed, const Vector3 &velocity = Vector3());
+
+ /**
+ * \brief Destroys this simulator instance.
+ */
+ ~RVOSimulator3D();
+
+ /**
+ * \brief Adds a new agent with default properties to the simulation.
+ * \param position The three-dimensional starting position of this agent.
+ * \return The number of the agent, or RVO3D::RVO3D_ERROR when the agent defaults have not been set.
+ */
+ size_t addAgent(const Vector3 &position);
+
+ /**
+ * \brief Adds a new agent to the simulation.
+ * \param position The three-dimensional starting position of this agent.
+ * \param neighborDist The maximum distance (center point to center point) to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe. Must be non-negative.
+ * \param maxNeighbors The maximum number of other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
+ * \param timeHorizon The minimum amount of time for which this agent's velocities that are computed by the simulation are safe with respect to other agents. The larger this number, the sooner this agent will respond to the presence of other agents, but the less freedom this agent has in choosing its velocities. Must be positive.
+ * \param radius The radius of this agent. Must be non-negative.
+ * \param maxSpeed The maximum speed of this agent. Must be non-negative.
+ * \param velocity The initial three-dimensional linear velocity of this agent (optional).
+ * \return The number of the agent.
+ */
+ size_t addAgent(const Vector3 &position, float neighborDist, size_t maxNeighbors, float timeHorizon, float radius, float maxSpeed, const Vector3 &velocity = Vector3());
+
+ /**
+ * \brief Lets the simulator perform a simulation step and updates the three-dimensional position and three-dimensional velocity of each agent.
+ */
+ void doStep();
+
+ /**
+ * \brief Returns the specified agent neighbor of the specified agent.
+ * \param agentNo The number of the agent whose agent neighbor is to be retrieved.
+ * \param neighborNo The number of the agent neighbor to be retrieved.
+ * \return The number of the neighboring agent.
+ */
+ size_t getAgentAgentNeighbor(size_t agentNo, size_t neighborNo) const;
+
+ /**
+ * \brief Returns the maximum neighbor count of a specified agent.
+ * \param agentNo The number of the agent whose maximum neighbor count is to be retrieved.
+ * \return The present maximum neighbor count of the agent.
+ */
+ size_t getAgentMaxNeighbors(size_t agentNo) const;
+
+ /**
+ * \brief Returns the maximum speed of a specified agent.
+ * \param agentNo The number of the agent whose maximum speed is to be retrieved.
+ * \return The present maximum speed of the agent.
+ */
+ float getAgentMaxSpeed(size_t agentNo) const;
+
+ /**
+ * \brief Returns the maximum neighbor distance of a specified agent.
+ * \param agentNo The number of the agent whose maximum neighbor distance is to be retrieved.
+ * \return The present maximum neighbor distance of the agent.
+ */
+ float getAgentNeighborDist(size_t agentNo) const;
+
+ /**
+ * \brief Returns the count of agent neighbors taken into account to compute the current velocity for the specified agent.
+ * \param agentNo The number of the agent whose count of agent neighbors is to be retrieved.
+ * \return The count of agent neighbors taken into account to compute the current velocity for the specified agent.
+ */
+ size_t getAgentNumAgentNeighbors(size_t agentNo) const;
+
+ /**
+ * \brief Returns the count of ORCA constraints used to compute the current velocity for the specified agent.
+ * \param agentNo The number of the agent whose count of ORCA constraints is to be retrieved.
+ * \return The count of ORCA constraints used to compute the current velocity for the specified agent.
+ */
+ size_t getAgentNumORCAPlanes(size_t agentNo) const;
+
+ /**
+ * \brief Returns the specified ORCA constraint of the specified agent.
+ * \param agentNo The number of the agent whose ORCA constraint is to be retrieved.
+ * \param planeNo The number of the ORCA constraint to be retrieved.
+ * \return A plane representing the specified ORCA constraint.
+ * \note The halfspace to which the normal of the plane points is the region of permissible velocities with respect to the specified ORCA constraint.
+ */
+ const Plane &getAgentORCAPlane(size_t agentNo, size_t planeNo) const;
+
+ /**
+ * \brief Returns the three-dimensional position of a specified agent.
+ * \param agentNo The number of the agent whose three-dimensional position is to be retrieved.
+ * \return The present three-dimensional position of the (center of the) agent.
+ */
+ const Vector3 &getAgentPosition(size_t agentNo) const;
+
+ /**
+ * \brief Returns the three-dimensional preferred velocity of a specified agent.
+ * \param agentNo The number of the agent whose three-dimensional preferred velocity is to be retrieved.
+ * \return The present three-dimensional preferred velocity of the agent.
+ */
+ const Vector3 &getAgentPrefVelocity(size_t agentNo) const;
+
+ /**
+ * \brief Returns the radius of a specified agent.
+ * \param agentNo The number of the agent whose radius is to be retrieved.
+ * \return The present radius of the agent.
+ */
+ float getAgentRadius(size_t agentNo) const;
+
+ /**
+ * \brief Returns the time horizon of a specified agent.
+ * \param agentNo The number of the agent whose time horizon is to be retrieved.
+ * \return The present time horizon of the agent.
+ */
+ float getAgentTimeHorizon(size_t agentNo) const;
+
+ /**
+ * \brief Returns the three-dimensional linear velocity of a specified agent.
+ * \param agentNo The number of the agent whose three-dimensional linear velocity is to be retrieved.
+ * \return The present three-dimensional linear velocity of the agent.
+ */
+ const Vector3 &getAgentVelocity(size_t agentNo) const;
+
+ /**
+ * \brief Returns the global time of the simulation.
+ * \return The present global time of the simulation (zero initially).
+ */
+ float getGlobalTime() const;
+
+ /**
+ * \brief Returns the count of agents in the simulation.
+ * \return The count of agents in the simulation.
+ */
+ size_t getNumAgents() const;
+
+ /**
+ * \brief Returns the time step of the simulation.
+ * \return The present time step of the simulation.
+ */
+ float getTimeStep() const;
+
+ /**
+ * \brief Removes an agent from the simulation.
+ * \param agentNo The number of the agent that is to be removed.
+ * \note After the removal of the agent, the agent that previously had number getNumAgents() - 1 will now have number agentNo.
+ */
+ void removeAgent(size_t agentNo);
+
+ /**
+ * \brief Sets the default properties for any new agent that is added.
+ * \param neighborDist The default maximum distance (center point to center point) to other agents a new agent takes into account in the navigation. The larger this number, the longer he running time of the simulation. If the number is too low, the simulation will not be safe. Must be non-negative.
+ * \param maxNeighbors The default maximum number of other agents a new agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
+ * \param timeHorizon The default minimum amount of time for which a new agent's velocities that are computed by the simulation are safe with respect to other agents. The larger this number, the sooner an agent will respond to the presence of other agents, but the less freedom the agent has in choosing its velocities. Must be positive.
+ * \param radius The default radius of a new agent. Must be non-negative.
+ * \param maxSpeed The default maximum speed of a new agent. Must be non-negative.
+ * \param velocity The default initial three-dimensional linear velocity of a new agent (optional).
+ */
+ void setAgentDefaults(float neighborDist, size_t maxNeighbors, float timeHorizon, float radius, float maxSpeed, const Vector3 &velocity = Vector3());
+
+ /**
+ * \brief Sets the maximum neighbor count of a specified agent.
+ * \param agentNo The number of the agent whose maximum neighbor count is to be modified.
+ * \param maxNeighbors The replacement maximum neighbor count.
+ */
+ void setAgentMaxNeighbors(size_t agentNo, size_t maxNeighbors);
+
+ /**
+ * \brief Sets the maximum speed of a specified agent.
+ * \param agentNo The number of the agent whose maximum speed is to be modified.
+ * \param maxSpeed The replacement maximum speed. Must be non-negative.
+ */
+ void setAgentMaxSpeed(size_t agentNo, float maxSpeed);
+
+ /**
+ * \brief Sets the maximum neighbor distance of a specified agent.
+ * \param agentNo The number of the agent whose maximum neighbor distance is to be modified.
+ * \param neighborDist The replacement maximum neighbor distance. Must be non-negative.
+ */
+ void setAgentNeighborDist(size_t agentNo, float neighborDist);
+
+ /**
+ * \brief Sets the three-dimensional position of a specified agent.
+ * \param agentNo The number of the agent whose three-dimensional position is to be modified.
+ * \param position The replacement of the three-dimensional position.
+ */
+ void setAgentPosition(size_t agentNo, const Vector3 &position);
+
+ /**
+ * \brief Sets the three-dimensional preferred velocity of a specified agent.
+ * \param agentNo The number of the agent whose three-dimensional preferred velocity is to be modified.
+ * \param prefVelocity The replacement of the three-dimensional preferred velocity.
+ */
+ void setAgentPrefVelocity(size_t agentNo, const Vector3 &prefVelocity);
+
+ /**
+ * \brief Sets the radius of a specified agent.
+ * \param agentNo The number of the agent whose radius is to be modified.
+ * \param radius The replacement radius. Must be non-negative.
+ */
+ void setAgentRadius(size_t agentNo, float radius);
+
+ /**
+ * \brief Sets the time horizon of a specified agent with respect to other agents.
+ * \param agentNo The number of the agent whose time horizon is to be modified.
+ * \param timeHorizon The replacement time horizon with respect to other agents. Must be positive.
+ */
+ void setAgentTimeHorizon(size_t agentNo, float timeHorizon);
+
+ /**
+ * \brief Sets the three-dimensional linear velocity of a specified agent.
+ * \param agentNo The number of the agent whose three-dimensional linear velocity is to be modified.
+ * \param velocity The replacement three-dimensional linear velocity.
+ */
+ void setAgentVelocity(size_t agentNo, const Vector3 &velocity);
+
+ /**
+ * \brief Sets the time step of the simulation.
+ * \param timeStep The time step of the simulation. Must be positive.
+ */
+ void setTimeStep(float timeStep);
+
+ public:
+ Agent3D *defaultAgent_;
+ KdTree3D *kdTree_;
+ float globalTime_;
+ float timeStep_;
+ std::vector<Agent3D *> agents_;
+
+ friend class Agent3D;
+ friend class KdTree3D;
+ };
+}
+
+#endif
diff --git a/thirdparty/rvo2/rvo2_3d/Vector3.cc b/thirdparty/rvo2/rvo2_3d/Vector3.cc
deleted file mode 100644
index 95831d3c90..0000000000
--- a/thirdparty/rvo2/rvo2_3d/Vector3.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Vector3.cc
- * RVO2-3D Library
- *
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Please send all bug reports to <geom@cs.unc.edu>.
- *
- * The authors may be contacted via:
- *
- * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
- * Dept. of Computer Science
- * 201 S. Columbia St.
- * Frederick P. Brooks, Jr. Computer Science Bldg.
- * Chapel Hill, N.C. 27599-3175
- * United States of America
- *
- * <https://gamma.cs.unc.edu/RVO2/>
- */
-
-#include "Vector3.h"
-
-#include <cmath>
-#include <ostream>
-
-namespace RVO3D {
-Vector3::Vector3() : val_() {
- val_[0] = 0.0F;
- val_[1] = 0.0F;
- val_[2] = 0.0F;
-}
-
-Vector3::Vector3(const Vector3 &vector) : val_() {
- val_[0] = vector[0];
- val_[1] = vector[1];
- val_[2] = vector[2];
-}
-
-Vector3::Vector3(const float val[3]) : val_() {
- val_[0] = val[0];
- val_[1] = val[1];
- val_[2] = val[2];
-}
-
-Vector3::Vector3(float x, float y, float z) : val_() {
- val_[0] = x;
- val_[1] = y;
- val_[2] = z;
-}
-
-Vector3::~Vector3() {}
-
-Vector3 &Vector3::operator=(const Vector3 &vector) {
- if (this != &vector) {
- val_[0] = vector[0];
- val_[1] = vector[1];
- val_[2] = vector[2];
- }
-
- return *this;
-}
-
-float Vector3::operator[](std::size_t i) const { return val_[i]; }
-
-float &Vector3::operator[](std::size_t i) { return val_[i]; }
-
-Vector3 Vector3::operator-() const {
- return Vector3(-val_[0], -val_[1], -val_[2]);
-}
-
-float Vector3::operator*(const Vector3 &vector) const {
- return val_[0] * vector[0] + val_[1] * vector[1] + val_[2] * vector[2];
-}
-
-Vector3 Vector3::operator*(float scalar) const {
- return Vector3(val_[0] * scalar, val_[1] * scalar, val_[2] * scalar);
-}
-
-Vector3 Vector3::operator/(float scalar) const {
- const float invScalar = 1.0F / scalar;
-
- return Vector3(val_[0] * invScalar, val_[1] * invScalar, val_[2] * invScalar);
-}
-
-Vector3 Vector3::operator+(const Vector3 &vector) const {
- return Vector3(val_[0] + vector[0], val_[1] + vector[1], val_[2] + vector[2]);
-}
-
-Vector3 Vector3::operator-(const Vector3 &vector) const {
- return Vector3(val_[0] - vector[0], val_[1] - vector[1], val_[2] - vector[2]);
-}
-
-bool Vector3::operator==(const Vector3 &vector) const {
- return val_[0] == vector[0] && val_[1] == vector[1] && val_[2] == vector[2];
-}
-
-bool Vector3::operator!=(const Vector3 &vector) const {
- return val_[0] != vector[0] || val_[1] != vector[1] || val_[2] != vector[2];
-}
-
-Vector3 &Vector3::operator*=(float scalar) {
- val_[0] *= scalar;
- val_[1] *= scalar;
- val_[2] *= scalar;
-
- return *this;
-}
-
-Vector3 &Vector3::operator/=(float scalar) {
- const float invScalar = 1.0F / scalar;
-
- val_[0] *= invScalar;
- val_[1] *= invScalar;
- val_[2] *= invScalar;
-
- return *this;
-}
-
-Vector3 &Vector3::operator+=(const Vector3 &vector) {
- val_[0] += vector[0];
- val_[1] += vector[1];
- val_[2] += vector[2];
-
- return *this;
-}
-
-Vector3 &Vector3::operator-=(const Vector3 &vector) {
- val_[0] -= vector[0];
- val_[1] -= vector[1];
- val_[2] -= vector[2];
-
- return *this;
-}
-
-Vector3 operator*(float scalar, const Vector3 &vector) {
- return Vector3(scalar * vector[0], scalar * vector[1], scalar * vector[2]);
-}
-
-std::ostream &operator<<(std::ostream &stream, const Vector3 &vector) {
- stream << "(" << vector[0] << "," << vector[1] << "," << vector[2] << ")";
-
- return stream;
-}
-
-float abs(const Vector3 &vector) { return std::sqrt(vector * vector); }
-
-float absSq(const Vector3 &vector) { return vector * vector; }
-
-Vector3 cross(const Vector3 &vector1, const Vector3 &vector2) {
- return Vector3(vector1[1] * vector2[2] - vector1[2] * vector2[1],
- vector1[2] * vector2[0] - vector1[0] * vector2[2],
- vector1[0] * vector2[1] - vector1[1] * vector2[0]);
-}
-
-Vector3 normalize(const Vector3 &vector) { return vector / abs(vector); }
-
-} /* namespace RVO3D */
diff --git a/thirdparty/rvo2/rvo2_3d/Vector3.h b/thirdparty/rvo2/rvo2_3d/Vector3.h
index 8f4708942f..6fa4bb074c 100644
--- a/thirdparty/rvo2/rvo2_3d/Vector3.h
+++ b/thirdparty/rvo2/rvo2_3d/Vector3.h
@@ -2,8 +2,7 @@
* Vector3.h
* RVO2-3D Library
*
- * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright 2008 University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,284 +30,324 @@
* <https://gamma.cs.unc.edu/RVO2/>
*/
-#ifndef RVO3D_VECTOR3_H_
-#define RVO3D_VECTOR3_H_
-
/**
- * @file Vector3.h
- * @brief Contains the Vector3 class.
+ * \file Vector3.h
+ * \brief Contains the Vector3 class.
*/
+#ifndef RVO3D_VECTOR3_H_
+#define RVO3D_VECTOR3_H_
+#include <cmath>
#include <cstddef>
-#include <iosfwd>
+#include <ostream>
namespace RVO3D {
-/**
- * @brief Defines a three-dimensional vector.
- */
-class Vector3 {
- public:
- /**
- * @brief Constructs and initializes a three-dimensional vector instance to
- * zero.
- */
- Vector3();
-
- /**
- * @brief Constructs and initializes a three-dimensional vector from the
- * specified three-dimensional vector.
- * @param[in] vector The three-dimensional vector containing the
- * xyz-coordinates.
- */
- Vector3(const Vector3 &vector);
-
- /**
- * @brief Constructs and initializes a three-dimensional vector from the
- * specified three-element array.
- * @param[in] val The three-element array containing the xyz-coordinates.
- */
- explicit Vector3(const float val[3]);
-
- /**
- * @brief Constructs and initializes a three-dimensional vector from the
- * specified xyz-coordinates.
- * @param[in] x The x-coordinate of the three-dimensional vector.
- * @param[in] y The y-coordinate of the three-dimensional vector.
- * @param[in] z The z-coordinate of the three-dimensional vector.
- */
- Vector3(float x, float y, float z);
-
- /**
- * @brief Destroys this three-dimensional vector instance.
- */
- ~Vector3();
-
- /**
- * @brief Returns the x-coordinate of this three-dimensional vector.
- * @return The x-coordinate of the three-dimensional vector.
- */
- float x() const { return val_[0]; }
-
- /**
- * @brief Returns the y-coordinate of this three-dimensional vector.
- * @return The y-coordinate of the three-dimensional vector.
- */
- float y() const { return val_[1]; }
-
- /**
- * @brief Returns the z-coordinate of this three-dimensional vector.
- * @return The z-coordinate of the three-dimensional vector.
- */
- float z() const { return val_[2]; }
-
- /**
- * @brief Assigns a copy of the specified three-dimensional vector to
- * this three-dimensional vector instance.
- * @param[in] vector The three-dimensional vector containing the
- * xyz-coordinates.
- * @return A reference to this three-dimensional vector instance.
- */
- Vector3 &operator=(const Vector3 &vector);
-
- /**
- * @brief Returns the specified coordinate of this three-dimensional
- * vector.
- * @param[in] i The coordinate that should be returned (0 <= i < 3).
- * @return The specified coordinate of the three-dimensional vector.
- */
- float operator[](std::size_t i) const;
-
- /**
- * @brief Returns a reference to the specified coordinate of this
- * three-dimensional vector.
- * @param[in] i The coordinate to which a reference should be returned
- * (0 <= i < 3).
- * @return A reference to the specified coordinate of the three-dimensional
- * vector.
- */
- float &operator[](std::size_t i);
-
- /**
- * @brief Computes the negation of this three-dimensional vector.
- * @return The negation of this three-dimensional vector.
- */
- Vector3 operator-() const;
-
- /**
- * @brief Computes the dot product of this three-dimensional vector with
- * the specified three-dimensional vector.
- * @param[in] vector The three-dimensional vector with which the dot product
- * should be computed.
- * @return The dot product of this three-dimensional vector with a
- * specified three-dimensional vector.
- */
- float operator*(const Vector3 &vector) const;
-
- /**
- * @brief Computes the scalar multiplication of this three-dimensional
- * vector with the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar multiplication
- * should be computed.
- * @return The scalar multiplication of this three-dimensional vector with
- * a specified scalar value.
- */
- Vector3 operator*(float scalar) const;
-
- /**
- * @brief Computes the scalar division of this three-dimensional vector
- * with the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar division should be
- * computed.
- * @return The scalar division of this three-dimensional vector with a
- * specified scalar value.
- */
- Vector3 operator/(float scalar) const;
-
- /**
- * @brief Computes the vector sum of this three-dimensional vector with
- * the specified three-dimensional vector.
- * @param[in] vector The three-dimensional vector with which the vector sum
- * should be computed.
- * @return The vector sum of this three-dimensional vector with a specified
- * three-dimensional vector.
- */
- Vector3 operator+(const Vector3 &vector) const;
-
- /**
- * @brief Computes the vector difference of this three-dimensional vector
- * with the specified three-dimensional vector.
- * @param[in] vector The three-dimensional vector with which the vector
- * difference should be computed.
- * @return The vector difference of this three-dimensional vector with a
- * specified three-dimensional vector.
- */
- Vector3 operator-(const Vector3 &vector) const;
-
- /**
- * @brief Tests this three-dimensional vector for equality with the
- * specified three-dimensional vector.
- * @param[in] vector The three-dimensional vector with which to test for
- * equality.
- * @return True if the three-dimensional vectors are equal.
- */
- bool operator==(const Vector3 &vector) const;
-
- /**
- * @brief Tests this three-dimensional vector for inequality with the
- * specified three-dimensional vector
- * @param[in] vector The three-dimensional vector with which to test for
- * inequality.
- * @return True if the three-dimensional vectors are not equal.
- */
- bool operator!=(const Vector3 &vector) const;
-
- /**
- * @brief Sets the value of this three-dimensional vector to the scalar
- * multiplication of itself with the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar multiplication
- * should be computed.
- * @return A reference to this three-dimensional vector.
- */
- Vector3 &operator*=(float scalar);
-
- /**
- * @brief Sets the value of this three-dimensional vector to the scalar
- * division of itself with the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar division should be
- * computed.
- * @return A reference to this three-dimensional vector.
- */
- Vector3 &operator/=(float scalar);
-
- /**
- * @brief Sets the value of this three-dimensional vector to the vector
- * sum of itself with the specified three-dimensional vector.
- * @param[in] vector The three-dimensional vector with which the vector sum
- * should be computed.
- * @return A reference to this three-dimensional vector.
- */
- Vector3 &operator+=(const Vector3 &vector);
-
- /**
- * @brief Sets the value of this three-dimensional vector to the vector
- * difference of itself with the specified three-dimensional
- * vector.
- * @param[in] vector The three-dimensional vector with which the vector
- * difference should be computed.
- * @return A reference to this three-dimensional vector.
- */
- Vector3 &operator-=(const Vector3 &vector);
-
- private:
- float val_[3];
-};
-
-/**
- * @relates Vector3
- * @brief Computes the scalar multiplication of the specified
- * three-dimensional vector with the specified scalar value.
- * @param[in] scalar The scalar value with which the scalar multiplication
- * should be computed.
- * @param[in] vector The three-dimensional vector with which the scalar
- * multiplication should be computed.
- * @return The scalar multiplication of the three-dimensional vector with the
- * scalar value.
- */
-Vector3 operator*(float scalar, const Vector3 &vector);
-
-/**
- * @relates Vector3
- * @brief Inserts the specified three-dimensional vector into the
- * specified output stream.
- * @param[in,out] os The output stream into which the three-dimensional
- * vector should be inserted.
- * @param[in] vector The three-dimensional vector which to insert into the
- * output stream.
- * @return A reference to the output stream.
- */
-std::ostream &operator<<(std::ostream &stream,
- const Vector3 &vector);
-
-/**
- * @relates Vector3
- * @brief Computes the length of a specified three-dimensional vector.
- * @param[in] vector The three-dimensional vector whose length is to be
- * computed.
- * @return The length of the three-dimensional vector.
- */
-float abs(const Vector3 &vector);
-
-/**
- * @relates Vector3
- * @brief Computes the squared length of a specified three-dimensional
- * vector.
- * @param[in] vector The three-dimensional vector whose squared length is to be
- * computed.
- * @return The squared length of the three-dimensional vector.
- */
-float absSq(const Vector3 &vector);
-
-/**
- * @relates Vector3
- * @brief Computes the cross product of the specified three-dimensional
- * vectors.
- * @param[in] vector1 The first vector with which the cross product should be
- * computed.
- * @param[in] vector2 The second vector with which the cross product should be
- * computed.
- * @return The cross product of the two specified vectors.
- */
-Vector3 cross(const Vector3 &vector1, const Vector3 &vector2);
-
-/**
- * @relates Vector3
- * @brief Computes the normalization of the specified three-dimensiona
- * vector.
- * @param[in] vector The three-dimensional vector whose normalization is to be
- * computed.
- * @return The normalization of the three-dimensional vector.
- */
-Vector3 normalize(const Vector3 &vector);
-} /* namespace RVO3D */
-
-#endif /* RVO3D_VECTOR3_H_ */
+ /**
+ * \brief Defines a three-dimensional vector.
+ */
+ class Vector3 {
+ public:
+ /**
+ * \brief Constructs and initializes a three-dimensional vector instance to zero.
+ */
+ inline Vector3()
+ {
+ val_[0] = 0.0f;
+ val_[1] = 0.0f;
+ val_[2] = 0.0f;
+ }
+
+ /**
+ * \brief Constructs and initializes a three-dimensional vector from the specified three-dimensional vector.
+ * \param vector The three-dimensional vector containing the xyz-coordinates.
+ */
+ inline Vector3(const Vector3 &vector)
+ {
+ val_[0] = vector[0];
+ val_[1] = vector[1];
+ val_[2] = vector[2];
+ }
+
+ /**
+ * \brief Constructs and initializes a three-dimensional vector from the specified three-element array.
+ * \param val The three-element array containing the xyz-coordinates.
+ */
+ inline explicit Vector3(const float val[3])
+ {
+ val_[0] = val[0];
+ val_[1] = val[1];
+ val_[2] = val[2];
+ }
+
+ /**
+ * \brief Constructs and initializes a three-dimensional vector from the specified xyz-coordinates.
+ * \param x The x-coordinate of the three-dimensional vector.
+ * \param y The y-coordinate of the three-dimensional vector.
+ * \param z The z-coordinate of the three-dimensional vector.
+ */
+ inline Vector3(float x, float y, float z)
+ {
+ val_[0] = x;
+ val_[1] = y;
+ val_[2] = z;
+ }
+
+ /**
+ * \brief Returns the x-coordinate of this three-dimensional vector.
+ * \return The x-coordinate of the three-dimensional vector.
+ */
+ inline float x() const { return val_[0]; }
+
+ /**
+ * \brief Returns the y-coordinate of this three-dimensional vector.
+ * \return The y-coordinate of the three-dimensional vector.
+ */
+ inline float y() const { return val_[1]; }
+
+ /**
+ * \brief Returns the z-coordinate of this three-dimensional vector.
+ * \return The z-coordinate of the three-dimensional vector.
+ */
+ inline float z() const { return val_[2]; }
+
+ /**
+ * \brief Returns the specified coordinate of this three-dimensional vector.
+ * \param i The coordinate that should be returned (0 <= i < 3).
+ * \return The specified coordinate of the three-dimensional vector.
+ */
+ inline float operator[](size_t i) const { return val_[i]; }
+
+ /**
+ * \brief Returns a reference to the specified coordinate of this three-dimensional vector.
+ * \param i The coordinate to which a reference should be returned (0 <= i < 3).
+ * \return A reference to the specified coordinate of the three-dimensional vector.
+ */
+ inline float &operator[](size_t i) { return val_[i]; }
+
+ /**
+ * \brief Computes the negation of this three-dimensional vector.
+ * \return The negation of this three-dimensional vector.
+ */
+ inline Vector3 operator-() const
+ {
+ return Vector3(-val_[0], -val_[1], -val_[2]);
+ }
+
+ /**
+ * \brief Computes the dot product of this three-dimensional vector with the specified three-dimensional vector.
+ * \param vector The three-dimensional vector with which the dot product should be computed.
+ * \return The dot product of this three-dimensional vector with a specified three-dimensional vector.
+ */
+ inline float operator*(const Vector3 &vector) const
+ {
+ return val_[0] * vector[0] + val_[1] * vector[1] + val_[2] * vector[2];
+ }
+
+ /**
+ * \brief Computes the scalar multiplication of this three-dimensional vector with the specified scalar value.
+ * \param scalar The scalar value with which the scalar multiplication should be computed.
+ * \return The scalar multiplication of this three-dimensional vector with a specified scalar value.
+ */
+ inline Vector3 operator*(float scalar) const
+ {
+ return Vector3(val_[0] * scalar, val_[1] * scalar, val_[2] * scalar);
+ }
+
+ /**
+ * \brief Computes the scalar division of this three-dimensional vector with the specified scalar value.
+ * \param scalar The scalar value with which the scalar division should be computed.
+ * \return The scalar division of this three-dimensional vector with a specified scalar value.
+ */
+ inline Vector3 operator/(float scalar) const
+ {
+ const float invScalar = 1.0f / scalar;
+
+ return Vector3(val_[0] * invScalar, val_[1] * invScalar, val_[2] * invScalar);
+ }
+
+ /**
+ * \brief Computes the vector sum of this three-dimensional vector with the specified three-dimensional vector.
+ * \param vector The three-dimensional vector with which the vector sum should be computed.
+ * \return The vector sum of this three-dimensional vector with a specified three-dimensional vector.
+ */
+ inline Vector3 operator+(const Vector3 &vector) const
+ {
+ return Vector3(val_[0] + vector[0], val_[1] + vector[1], val_[2] + vector[2]);
+ }
+
+ /**
+ * \brief Computes the vector difference of this three-dimensional vector with the specified three-dimensional vector.
+ * \param vector The three-dimensional vector with which the vector difference should be computed.
+ * \return The vector difference of this three-dimensional vector with a specified three-dimensional vector.
+ */
+ inline Vector3 operator-(const Vector3 &vector) const
+ {
+ return Vector3(val_[0] - vector[0], val_[1] - vector[1], val_[2] - vector[2]);
+ }
+
+ /**
+ * \brief Tests this three-dimensional vector for equality with the specified three-dimensional vector.
+ * \param vector The three-dimensional vector with which to test for equality.
+ * \return True if the three-dimensional vectors are equal.
+ */
+ inline bool operator==(const Vector3 &vector) const
+ {
+ return val_[0] == vector[0] && val_[1] == vector[1] && val_[2] == vector[2];
+ }
+
+ /**
+ * \brief Tests this three-dimensional vector for inequality with the specified three-dimensional vector.
+ * \param vector The three-dimensional vector with which to test for inequality.
+ * \return True if the three-dimensional vectors are not equal.
+ */
+ inline bool operator!=(const Vector3 &vector) const
+ {
+ return val_[0] != vector[0] || val_[1] != vector[1] || val_[2] != vector[2];
+ }
+
+ /**
+ * \brief Sets the value of this three-dimensional vector to the scalar multiplication of itself with the specified scalar value.
+ * \param scalar The scalar value with which the scalar multiplication should be computed.
+ * \return A reference to this three-dimensional vector.
+ */
+ inline Vector3 &operator*=(float scalar)
+ {
+ val_[0] *= scalar;
+ val_[1] *= scalar;
+ val_[2] *= scalar;
+
+ return *this;
+ }
+
+ /**
+ * \brief Sets the value of this three-dimensional vector to the scalar division of itself with the specified scalar value.
+ * \param scalar The scalar value with which the scalar division should be computed.
+ * \return A reference to this three-dimensional vector.
+ */
+ inline Vector3 &operator/=(float scalar)
+ {
+ const float invScalar = 1.0f / scalar;
+
+ val_[0] *= invScalar;
+ val_[1] *= invScalar;
+ val_[2] *= invScalar;
+
+ return *this;
+ }
+
+ /**
+ * \brief Sets the value of this three-dimensional vector to the vector
+ * sum of itself with the specified three-dimensional vector.
+ * \param vector The three-dimensional vector with which the vector sum should be computed.
+ * \return A reference to this three-dimensional vector.
+ */
+ inline Vector3 &operator+=(const Vector3 &vector)
+ {
+ val_[0] += vector[0];
+ val_[1] += vector[1];
+ val_[2] += vector[2];
+
+ return *this;
+ }
+
+ /**
+ * \brief Sets the value of this three-dimensional vector to the vector difference of itself with the specified three-dimensional vector.
+ * \param vector The three-dimensional vector with which the vector difference should be computed.
+ * \return A reference to this three-dimensional vector.
+ */
+ inline Vector3 &operator-=(const Vector3 &vector)
+ {
+ val_[0] -= vector[0];
+ val_[1] -= vector[1];
+ val_[2] -= vector[2];
+
+ return *this;
+ }
+
+ inline Vector3 &operator=(const Vector3 &vector)
+ {
+ val_[0] = vector[0];
+ val_[1] = vector[1];
+ val_[2] = vector[2];
+
+ return *this;
+ }
+
+ private:
+ float val_[3];
+ };
+
+
+ /**
+ * \relates Vector3
+ * \brief Computes the scalar multiplication of the specified three-dimensional vector with the specified scalar value.
+ * \param scalar The scalar value with which the scalar multiplication should be computed.
+ * \param vector The three-dimensional vector with which the scalar multiplication should be computed.
+ * \return The scalar multiplication of the three-dimensional vector with the scalar value.
+ */
+ inline Vector3 operator*(float scalar, const Vector3 &vector)
+ {
+ return Vector3(scalar * vector[0], scalar * vector[1], scalar * vector[2]);
+ }
+
+ /**
+ * \relates Vector3
+ * \brief Computes the cross product of the specified three-dimensional vectors.
+ * \param vector1 The first vector with which the cross product should be computed.
+ * \param vector2 The second vector with which the cross product should be computed.
+ * \return The cross product of the two specified vectors.
+ */
+ inline Vector3 cross(const Vector3 &vector1, const Vector3 &vector2)
+ {
+ return Vector3(vector1[1] * vector2[2] - vector1[2] * vector2[1], vector1[2] * vector2[0] - vector1[0] * vector2[2], vector1[0] * vector2[1] - vector1[1] * vector2[0]);
+ }
+
+ /**
+ * \relates Vector3
+ * \brief Inserts the specified three-dimensional vector into the specified output stream.
+ * \param os The output stream into which the three-dimensional vector should be inserted.
+ * \param vector The three-dimensional vector which to insert into the output stream.
+ * \return A reference to the output stream.
+ */
+ inline std::ostream &operator<<(std::ostream &os, const Vector3 &vector)
+ {
+ os << "(" << vector[0] << "," << vector[1] << "," << vector[2] << ")";
+
+ return os;
+ }
+
+ /**
+ * \relates Vector3
+ * \brief Computes the length of a specified three-dimensional vector.
+ * \param vector The three-dimensional vector whose length is to be computed.
+ * \return The length of the three-dimensional vector.
+ */
+ inline float abs(const Vector3 &vector)
+ {
+ return std::sqrt(vector * vector);
+ }
+
+ /**
+ * \relates Vector3
+ * \brief Computes the squared length of a specified three-dimensional vector.
+ * \param vector The three-dimensional vector whose squared length is to be computed.
+ * \return The squared length of the three-dimensional vector.
+ */
+ inline float absSq(const Vector3 &vector)
+ {
+ return vector * vector;
+ }
+
+ /**
+ * \relates Vector3
+ * \brief Computes the normalization of the specified three-dimensional vector.
+ * \param vector The three-dimensional vector whose normalization is to be computed.
+ * \return The normalization of the three-dimensional vector.
+ */
+ inline Vector3 normalize(const Vector3 &vector)
+ {
+ return vector / abs(vector);
+ }
+}
+
+#endif
diff --git a/version.py b/version.py
index 39ed2b76af..1ba2f6685f 100644
--- a/version.py
+++ b/version.py
@@ -1,9 +1,9 @@
short_name = "godot"
name = "Godot Engine"
major = 4
-minor = 1
+minor = 2
patch = 0
-status = "rc"
+status = "dev"
module_config = ""
year = 2023
website = "https://godotengine.org"